From 7db28aeb0a9bb61fe50aac52e6cc789e6a113063 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 15:11:30 +0000 Subject: [PATCH 01/28] Track the installed version of a game Add a free-text installed version on games (SQLite + Postgres), editable in the game details modal with suggestions taken from the game's download release names. A finished full-game or update download records the version found in its release name (v1.2.3, v123456, Build 12345, Update.1.05) when it is newer than the known one. Auto-search no longer flags or notifies update releases whose version is not newer than the installed one. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- .../installed-version/desktop-saved.png | Bin 0 -> 123990 bytes .../installed-version/mobile-saved.png | Bin 0 -> 129966 bytes .../__tests__/InstalledVersionField.test.tsx | 113 + client/src/components/GameDetailsModal.tsx | 14 + .../src/components/InstalledVersionField.tsx | 142 + docs/API.md | 1 + .../0008_cultured_stephen_strange.sql | 1 + migrations-pg/meta/0008_snapshot.json | 2307 ++++++++++++++++ migrations-pg/meta/_journal.json | 7 + migrations/0043_massive_dormammu.sql | 1 + migrations/meta/0043_snapshot.json | 2337 +++++++++++++++++ migrations/meta/_journal.json | 7 + server/__tests__/api_routes.test.ts | 55 + server/__tests__/cron_autosearch.test.ts | 98 +- .../database_storage_extended.test.ts | 4 + .../__tests__/fixtures/common-route-mocks.ts | 1 + .../__tests__/helpers/import-test-helpers.ts | 1 + server/cron.ts | 52 +- server/routes.ts | 30 + server/storage.ts | 32 + shared/__tests__/version-utils.test.ts | 82 + shared/schema.pg.ts | 1 + shared/schema.ts | 11 + shared/version-utils.ts | 99 + 24 files changed, 5394 insertions(+), 2 deletions(-) create mode 100644 .github/pr-assets/installed-version/desktop-saved.png create mode 100644 .github/pr-assets/installed-version/mobile-saved.png create mode 100644 client/__tests__/InstalledVersionField.test.tsx create mode 100644 client/src/components/InstalledVersionField.tsx create mode 100644 migrations-pg/0008_cultured_stephen_strange.sql create mode 100644 migrations-pg/meta/0008_snapshot.json create mode 100644 migrations/0043_massive_dormammu.sql create mode 100644 migrations/meta/0043_snapshot.json create mode 100644 shared/__tests__/version-utils.test.ts create mode 100644 shared/version-utils.ts diff --git a/.github/pr-assets/installed-version/desktop-saved.png b/.github/pr-assets/installed-version/desktop-saved.png new file mode 100644 index 0000000000000000000000000000000000000000..38c080a8d63bfea139069ac4937ccdd09109cb1b GIT binary patch literal 123990 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 LPNew#$1nc}it}wa literal 0 HcmV?d00001 diff --git a/.github/pr-assets/installed-version/mobile-saved.png b/.github/pr-assets/installed-version/mobile-saved.png new file mode 100644 index 0000000000000000000000000000000000000000..bb8468304d0e59faf436519d2c756ffff20937b0 GIT binary patch literal 129966 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 literal 0 HcmV?d00001 diff --git a/client/__tests__/InstalledVersionField.test.tsx b/client/__tests__/InstalledVersionField.test.tsx new file mode 100644 index 000000000..ff3a33583 --- /dev/null +++ b/client/__tests__/InstalledVersionField.test.tsx @@ -0,0 +1,113 @@ +/** @vitest-environment jsdom */ +import React from "react"; +import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react"; +import "@testing-library/jest-dom"; +import { QueryClientProvider } from "@tanstack/react-query"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +import { createTestQueryClient } from "./test-utils"; +import InstalledVersionField, { getVersionSuggestions } from "@/components/InstalledVersionField"; + +const mockToast = vi.fn(); +vi.mock("@/hooks/use-toast", () => ({ + useToast: () => ({ toast: mockToast }), +})); + +const apiRequest = vi.fn(); +vi.mock("@/lib/queryClient", () => ({ + apiRequest: (...args: unknown[]) => apiRequest(...args), +})); + +const gameId = "game-1"; + +function renderField(installedVersion: string | null, releaseNames: string[] = []) { + render( + + + + ); + return screen.getByLabelText("Installed version"); +} + +describe("getVersionSuggestions", () => { + it("lists distinct versions newest first, without the current one", () => { + expect( + getVersionSuggestions( + [ + "Game.v1.2-RUNE", + "Game.Update.v1.10-RUNE", + "Game.v1.2-GOG", + "Game.Update.v1.3-RUNE", + "Game-NoVersion", + ], + "v1.3" + ) + ).toEqual(["v1.10", "v1.2"]); + }); +}); + +describe("InstalledVersionField", () => { + beforeEach(() => { + vi.clearAllMocks(); + apiRequest.mockResolvedValue({ ok: true, json: async () => ({}) }); + }); + + afterEach(() => { + cleanup(); + }); + + it("shows the stored version", () => { + expect(renderField("v1.2.3")).toHaveValue("v1.2.3"); + }); + + it("saves the typed version on Enter", async () => { + const input = renderField(null); + fireEvent.change(input, { target: { value: " v2.0 " } }); + fireEvent.keyDown(input, { key: "Enter" }); + await waitFor(() => + expect(apiRequest).toHaveBeenCalledWith("PATCH", `/api/games/${gameId}/installed-version`, { + installedVersion: "v2.0", + }) + ); + }); + + it("clears the version when emptied and blurred", async () => { + const input = renderField("v1.0"); + fireEvent.change(input, { target: { value: "" } }); + fireEvent.blur(input); + await waitFor(() => + expect(apiRequest).toHaveBeenCalledWith("PATCH", `/api/games/${gameId}/installed-version`, { + installedVersion: null, + }) + ); + }); + + it("does not save when the value did not change", () => { + const input = renderField("v1.0"); + fireEvent.blur(input); + expect(apiRequest).not.toHaveBeenCalled(); + }); + + it("applies a suggestion from the game's downloads", async () => { + renderField(null, ["Game.Update.v1.4-RUNE"]); + fireEvent.click(screen.getByRole("button", { name: "Set installed version to v1.4" })); + await waitFor(() => + expect(apiRequest).toHaveBeenCalledWith("PATCH", `/api/games/${gameId}/installed-version`, { + installedVersion: "v1.4", + }) + ); + }); + + it("restores the stored value and warns when saving fails", async () => { + apiRequest.mockRejectedValue(new Error("boom")); + const input = renderField("v1.0"); + fireEvent.change(input, { target: { value: "v9" } }); + fireEvent.keyDown(input, { key: "Enter" }); + await waitFor(() => expect(mockToast).toHaveBeenCalled()); + expect(input).toHaveValue("v1.0"); + }); +}); diff --git a/client/src/components/GameDetailsModal.tsx b/client/src/components/GameDetailsModal.tsx index 9cdb1ea04..6e6152be4 100644 --- a/client/src/components/GameDetailsModal.tsx +++ b/client/src/components/GameDetailsModal.tsx @@ -87,6 +87,7 @@ import { import { NexusModsIcon } from "./NexusModsIcon"; import GameJournalTab from "./GameJournalTab"; import FileCategorySelect from "./FileCategorySelect"; +import InstalledVersionField from "./InstalledVersionField"; import { getSocket } from "@/lib/socket"; import { useToast } from "@/hooks/use-toast"; import { useHiddenMutation } from "@/hooks/use-hidden-mutation"; @@ -635,6 +636,11 @@ export default function GameDetailsModal({ game, open, onOpenChange }: GameDetai refetchInterval: 5000, }); + const downloadReleaseNames = useMemo( + () => gameDownloads.map((download) => download.downloadTitle), + [gameDownloads] + ); + const { data: xrelStatus, isLoading: xrelStatusLoading, @@ -1241,6 +1247,14 @@ export default function GameDetailsModal({ game, open, onOpenChange }: GameDetai

)} + {!isDiscoveryId(game.id) && ( + + )} diff --git a/client/src/components/InstalledVersionField.tsx b/client/src/components/InstalledVersionField.tsx new file mode 100644 index 000000000..e7967a105 --- /dev/null +++ b/client/src/components/InstalledVersionField.tsx @@ -0,0 +1,142 @@ +import { useEffect, useMemo, useState } from "react"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { Check, Loader2, Tag } from "lucide-react"; +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { useToast } from "@/hooks/use-toast"; +import { apiRequest } from "@/lib/queryClient"; +import { compareVersions, extractVersionFromReleaseName } from "@shared/version-utils"; + +interface InstalledVersionFieldProps { + gameId: string; + installedVersion: string | null; + /** Release names of the game's downloads, mined for version suggestions. */ + releaseNames: string[]; +} + +const MAX_SUGGESTIONS = 6; + +/** Distinct versions found in release names, newest first when they can be compared. */ +export function getVersionSuggestions(releaseNames: string[], current: string | null): string[] { + const seen = new Map(); + for (const name of releaseNames) { + const version = extractVersionFromReleaseName(name); + if (version && !seen.has(version.toLowerCase())) seen.set(version.toLowerCase(), version); + } + const currentKey = current?.trim().toLowerCase(); + return Array.from(seen.values()) + .filter((version) => version.toLowerCase() !== currentKey) + .sort((a, b) => compareVersions(b, a) ?? 0) + .slice(0, MAX_SUGGESTIONS); +} + +export default function InstalledVersionField({ + gameId, + installedVersion, + releaseNames, +}: InstalledVersionFieldProps) { + const { toast } = useToast(); + const queryClient = useQueryClient(); + const [draft, setDraft] = useState(installedVersion ?? ""); + + // Follow the server value (another tab, a finished download detecting a newer version). + useEffect(() => { + setDraft(installedVersion ?? ""); + }, [gameId, installedVersion]); + + const mutation = useMutation({ + mutationFn: async (value) => { + await apiRequest("PATCH", `/api/games/${gameId}/installed-version`, { + installedVersion: value, + }); + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["/api/games"] }); + }, + onError: () => { + setDraft(installedVersion ?? ""); + toast({ description: "Failed to save the installed version", variant: "destructive" }); + }, + }); + + const suggestions = useMemo( + () => getVersionSuggestions(releaseNames, draft), + [releaseNames, draft] + ); + + const save = (value: string) => { + const next = value.trim() || null; + if (next === (installedVersion ?? null)) return; + // Enter then blur would otherwise send the same value twice before the refetch lands. + if (mutation.isPending && mutation.variables === next) return; + mutation.mutate(next); + }; + + return ( +
+ +
+ setDraft(e.target.value)} + onBlur={() => save(draft)} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.preventDefault(); + save(draft); + } else if (e.key === "Escape" && draft !== (installedVersion ?? "")) { + e.stopPropagation(); + setDraft(installedVersion ?? ""); + } + }} + data-testid="input-installed-version" + /> + + {mutation.isPending ? ( + + ) : mutation.isSuccess && draft === (installedVersion ?? "") && draft ? ( + + ) : null} + +
+ {suggestions.length > 0 && ( +
+ From your downloads: + {suggestions.map((version) => ( + + ))} +
+ )} +

+ Detected from release names when a download finishes. Updates that are not newer than this + version are not notified. +

+
+ ); +} diff --git a/docs/API.md b/docs/API.md index a47bd71fb..934cdb252 100644 --- a/docs/API.md +++ b/docs/API.md @@ -69,6 +69,7 @@ JWT even where a table row doesn't repeat `authenticateToken`. | PATCH | `/api/games/:id/status` | JWT + `sensitiveEndpointLimiter`, `sanitizeGameId`, `sanitizeGameStatus`, `validateRequest` | `{ status: "wanted"\|"owned"\|"completed"\|"downloading" }` via `updateGameStatusSchema` | Updated `Game`; 404 if not found | | PATCH | `/api/games/:id/hidden` | JWT + `sensitiveEndpointLimiter`, `sanitizeGameId`, `validateRequest` | `{ hidden: boolean }` via `updateGameHiddenSchema` | Updated `Game`; 404 if not found | | PATCH | `/api/games/:id/user-rating` | JWT + `sensitiveEndpointLimiter`, `sanitizeGameId`, `validateRequest` | `{ userRating: number\|null }` (0.5–10, step 0.5) via `updateGameUserRatingSchema` | Updated `Game`; 404 if not found | +| PATCH | `/api/games/:id/installed-version` | JWT + `sensitiveEndpointLimiter`, `sanitizeGameId`, `validateRequest` | `{ installedVersion: string\|null }` (free text, trimmed, ≤64; blank clears) via `updateGameInstalledVersionSchema` | Updated `Game`; 404 if not found. Auto-search skips update releases whose version is not newer than this | | POST | `/api/games/refresh-metadata` | JWT + `igdbRateLimiter` | — | `{ success, message, updatedCount, errorCount }` | | DELETE | `/api/games/:id` | JWT + `sensitiveEndpointLimiter`, `sanitizeGameId`, `validateRequest` | Query: `deleteFiles?` ("true" to also remove the game's files on disk) | `{ success: true, fileDeletion }`; 404 if not found. `fileDeletion` is `null` when `deleteFiles` wasn't set, otherwise `{ deleted: true, path }` or `{ deleted: false, reason: "outside-library-root"\|"delete-failed", path }`. Files are only deleted when `libraryPath` resolves inside the configured library root **or** inside a root folder with `allowDelete: true` (see Root Folders below) | | GET | `/api/games/:id/downloads` | JWT + `sanitizeGameId`, `validateRequest` (verifies game ownership) | — | `GameDownload[]`; 404 game not found, 403 not owner | diff --git a/migrations-pg/0008_cultured_stephen_strange.sql b/migrations-pg/0008_cultured_stephen_strange.sql new file mode 100644 index 000000000..e06c8b4ff --- /dev/null +++ b/migrations-pg/0008_cultured_stephen_strange.sql @@ -0,0 +1 @@ +ALTER TABLE "games" ADD COLUMN "installed_version" text; \ No newline at end of file diff --git a/migrations-pg/meta/0008_snapshot.json b/migrations-pg/meta/0008_snapshot.json new file mode 100644 index 000000000..4f6ce1dbf --- /dev/null +++ b/migrations-pg/meta/0008_snapshot.json @@ -0,0 +1,2307 @@ +{ + "id": "ea184a7e-1f5f-46c6-b1f3-33072994a55b", + "prevId": "569ebd28-47ce-4be9-9daf-24d98a63ba0e", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.ai_auto_download_holds": { + "name": "ai_auto_download_holds", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "release_title": { + "name": "release_title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": { + "ai_auto_download_holds_game_title_idx": { + "name": "ai_auto_download_holds_game_title_idx", + "columns": [ + { + "expression": "game_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "release_title", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "ai_auto_download_holds_game_id_games_id_fk": { + "name": "ai_auto_download_holds_game_id_games_id_fk", + "tableFrom": "ai_auto_download_holds", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.api_keys": { + "name": "api_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key_hash": { + "name": "key_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + }, + "last_used_at": { + "name": "last_used_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "api_keys_key_hash_idx": { + "name": "api_keys_key_hash_idx", + "columns": [ + { + "expression": "key_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "api_keys_user_id_idx": { + "name": "api_keys_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.downloaders": { + "name": "downloaders", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "use_ssl": { + "name": "use_ssl", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "url_path": { + "name": "url_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "allow_self_signed_certificate": { + "name": "allow_self_signed_certificate", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "allow_insecure_lan": { + "name": "allow_insecure_lan", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "download_path": { + "name": "download_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'games'" + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'Questarr'" + }, + "add_stopped": { + "name": "add_stopped", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "remove_completed": { + "name": "remove_completed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "post_import_category": { + "name": "post_import_category", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "settings": { + "name": "settings", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + }, + "updated_at": { + "name": "updated_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.game_downloads": { + "name": "game_downloads", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "downloader_id": { + "name": "downloader_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "download_type": { + "name": "download_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'torrent'" + }, + "download_hash": { + "name": "download_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "download_title": { + "name": "download_title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'downloading'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "file_size": { + "name": "file_size", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "added_at": { + "name": "added_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + }, + "completed_at": { + "name": "completed_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "game_downloads_downloader_hash_idx": { + "name": "game_downloads_downloader_hash_idx", + "columns": [ + { + "expression": "downloader_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "download_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "game_downloads_game_id_games_id_fk": { + "name": "game_downloads_game_id_games_id_fk", + "tableFrom": "game_downloads", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_downloads_downloader_id_downloaders_id_fk": { + "name": "game_downloads_downloader_id_downloaders_id_fk", + "tableFrom": "game_downloads", + "tableTo": "downloaders", + "columnsFrom": ["downloader_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.game_files": { + "name": "game_files", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "download_id": { + "name": "download_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "original_name": { + "name": "original_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stored_name": { + "name": "stored_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category_overridden": { + "name": "category_overridden", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_size": { + "name": "file_size", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": { + "game_files_game_id_idx": { + "name": "game_files_game_id_idx", + "columns": [ + { + "expression": "game_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "game_files_download_id_idx": { + "name": "game_files_download_id_idx", + "columns": [ + { + "expression": "download_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "game_files_game_id_games_id_fk": { + "name": "game_files_game_id_games_id_fk", + "tableFrom": "game_files", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_files_download_id_game_downloads_id_fk": { + "name": "game_files_download_id_game_downloads_id_fk", + "tableFrom": "game_files", + "tableTo": "game_downloads", + "columnsFrom": ["download_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.game_journal_entries": { + "name": "game_journal_entries", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": { + "game_journal_entries_game_user_idx": { + "name": "game_journal_entries_game_user_idx", + "columns": [ + { + "expression": "game_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "game_journal_entries_game_id_games_id_fk": { + "name": "game_journal_entries_game_id_games_id_fk", + "tableFrom": "game_journal_entries", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_journal_entries_user_id_users_id_fk": { + "name": "game_journal_entries_user_id_users_id_fk", + "tableFrom": "game_journal_entries", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.game_milestones": { + "name": "game_milestones", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "completed_at": { + "name": "completed_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": { + "game_milestones_game_user_idx": { + "name": "game_milestones_game_user_idx", + "columns": [ + { + "expression": "game_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "game_milestones_game_id_games_id_fk": { + "name": "game_milestones_game_id_games_id_fk", + "tableFrom": "game_milestones", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_milestones_user_id_users_id_fk": { + "name": "game_milestones_user_id_users_id_fk", + "tableFrom": "game_milestones", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.game_screenshots": { + "name": "game_screenshots", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "caption": { + "name": "caption", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": { + "game_screenshots_game_user_idx": { + "name": "game_screenshots_game_user_idx", + "columns": [ + { + "expression": "game_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "game_screenshots_game_id_games_id_fk": { + "name": "game_screenshots_game_id_games_id_fk", + "tableFrom": "game_screenshots", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_screenshots_user_id_users_id_fk": { + "name": "game_screenshots_user_id_users_id_fk", + "tableFrom": "game_screenshots", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.games": { + "name": "games", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "igdb_id": { + "name": "igdb_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "steam_appid": { + "name": "steam_appid", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cover_url": { + "name": "cover_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "release_date": { + "name": "release_date", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "rating": { + "name": "rating", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "platforms": { + "name": "platforms", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "target_platform_id": { + "name": "target_platform_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_platform_name": { + "name": "target_platform_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "genres": { + "name": "genres", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "themes": { + "name": "themes", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "publishers": { + "name": "publishers", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "developers": { + "name": "developers", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "screenshots": { + "name": "screenshots", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'manual'" + }, + "igdb_websites": { + "name": "igdb_websites", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "expansions": { + "name": "expansions", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "aggregated_rating": { + "name": "aggregated_rating", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "time_to_beat_hastily": { + "name": "time_to_beat_hastily", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "time_to_beat_normally": { + "name": "time_to_beat_normally", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "time_to_beat_completely": { + "name": "time_to_beat_completely", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'wanted'" + }, + "original_release_date": { + "name": "original_release_date", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "release_status": { + "name": "release_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'upcoming'" + }, + "early_access": { + "name": "early_access", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "hidden": { + "name": "hidden", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_adult_content": { + "name": "is_adult_content", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_age_restricted": { + "name": "is_age_restricted", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "user_rating": { + "name": "user_rating", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "library_path": { + "name": "library_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "installed_version": { + "name": "installed_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "search_results_available": { + "name": "search_results_available", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "search_results_available_at": { + "name": "search_results_available_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "update_search_results_available": { + "name": "update_search_results_available", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "packs_search_results_available": { + "name": "packs_search_results_available", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "added_at": { + "name": "added_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + }, + "completed_at": { + "name": "completed_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "games_user_id_users_id_fk": { + "name": "games_user_id_users_id_fk", + "tableFrom": "games", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.import_task_items": { + "name": "import_task_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "item_name": { + "name": "item_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "result": { + "name": "result", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "game_title": { + "name": "game_title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": { + "import_task_items_task_id_idx": { + "name": "import_task_items_task_id_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "import_task_items_task_id_import_tasks_id_fk": { + "name": "import_task_items_task_id_import_tasks_id_fk", + "tableFrom": "import_task_items", + "tableTo": "import_tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.import_tasks": { + "name": "import_tasks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "task_type": { + "name": "task_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "triggered_by": { + "name": "triggered_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + }, + "started_at": { + "name": "started_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "total_items": { + "name": "total_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "added_items": { + "name": "added_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "skipped_items": { + "name": "skipped_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "failed_items": { + "name": "failed_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "import_tasks_user_id_users_id_fk": { + "name": "import_tasks_user_id_users_id_fk", + "tableFrom": "import_tasks", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.indexers": { + "name": "indexers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'torznab'" + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "categories": { + "name": "categories", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "rss_enabled": { + "name": "rss_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "auto_search_enabled": { + "name": "auto_search_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "allow_insecure_lan": { + "name": "allow_insecure_lan", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + }, + "updated_at": { + "name": "updated_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notifications": { + "name": "notifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "read": { + "name": "read", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": { + "notifications_user_id_users_id_fk": { + "name": "notifications_user_id_users_id_fk", + "tableFrom": "notifications", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.path_mappings": { + "name": "path_mappings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "remote_path": { + "name": "remote_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "local_path": { + "name": "local_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "remote_host": { + "name": "remote_host", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.platform_mappings": { + "name": "platform_mappings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "igdb_platform_id": { + "name": "igdb_platform_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "source_platform_name": { + "name": "source_platform_name", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.release_blacklist": { + "name": "release_blacklist", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "release_title": { + "name": "release_title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "indexer_name": { + "name": "indexer_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": { + "release_blacklist_game_title_idx": { + "name": "release_blacklist_game_title_idx", + "columns": [ + { + "expression": "game_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "release_title", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "release_blacklist_game_id_games_id_fk": { + "name": "release_blacklist_game_id_games_id_fk", + "tableFrom": "release_blacklist", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.root_folders": { + "name": "root_folders", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "allow_delete": { + "name": "allow_delete", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accessible": { + "name": "accessible", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "disk_free_bytes": { + "name": "disk_free_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "disk_total_bytes": { + "name": "disk_total_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "last_scanned_at": { + "name": "last_scanned_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "root_folders_path_unique": { + "name": "root_folders_path_unique", + "nullsNotDistinct": false, + "columns": ["path"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.rss_feed_items": { + "name": "rss_feed_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "feed_id": { + "name": "feed_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "guid": { + "name": "guid", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pub_date": { + "name": "pub_date", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "source_name": { + "name": "source_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "igdb_game_id": { + "name": "igdb_game_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "igdb_game_name": { + "name": "igdb_game_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cover_url": { + "name": "cover_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": { + "rss_feed_items_feed_id_rss_feeds_id_fk": { + "name": "rss_feed_items_feed_id_rss_feeds_id_fk", + "tableFrom": "rss_feed_items", + "tableTo": "rss_feeds", + "columnsFrom": ["feed_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.rss_feeds": { + "name": "rss_feeds", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'custom'" + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "mapping": { + "name": "mapping", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "last_check": { + "name": "last_check", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'ok'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + }, + "updated_at": { + "name": "updated_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.system_config": { + "name": "system_config", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_settings": { + "name": "user_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auto_search_enabled": { + "name": "auto_search_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "auto_download_enabled": { + "name": "auto_download_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "notification_preferences": { + "name": "notification_preferences", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "search_interval_hours": { + "name": "search_interval_hours", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 6 + }, + "igdb_rate_limit_per_second": { + "name": "igdb_rate_limit_per_second", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 3 + }, + "download_rules": { + "name": "download_rules", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_auto_search": { + "name": "last_auto_search", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "xrel_scene_releases": { + "name": "xrel_scene_releases", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "xrel_p2p_releases": { + "name": "xrel_p2p_releases", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auto_search_unreleased": { + "name": "auto_search_unreleased", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "steam_sync_failures": { + "name": "steam_sync_failures", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "steam_sync_enabled": { + "name": "steam_sync_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "steam_sync_interval_hours": { + "name": "steam_sync_interval_hours", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 24 + }, + "last_steam_sync": { + "name": "last_steam_sync", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "preferred_release_groups": { + "name": "preferred_release_groups", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "filter_by_preferred_groups": { + "name": "filter_by_preferred_groups", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "release_name_blacklist": { + "name": "release_name_blacklist", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "preferred_platform": { + "name": "preferred_platform", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hide_adult_content": { + "name": "hide_adult_content", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "hide_age_restricted_content": { + "name": "hide_age_restricted_content", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "hide_shelved_by_default": { + "name": "hide_shelved_by_default", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "hide_owned_in_has_results": { + "name": "hide_owned_in_has_results", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "enable_post_processing": { + "name": "enable_post_processing", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auto_unpack": { + "name": "auto_unpack", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "rename_pattern": { + "name": "rename_pattern", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'{Title} ({Region})'" + }, + "overwrite_existing": { + "name": "overwrite_existing", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "transfer_mode": { + "name": "transfer_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'hardlink'" + }, + "import_platform_ids": { + "name": "import_platform_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "ignored_extensions": { + "name": "ignored_extensions", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "min_file_size": { + "name": "min_file_size", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "library_root": { + "name": "library_root", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'/data'" + }, + "auto_delete_after_import": { + "name": "auto_delete_after_import", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "sort_extras": { + "name": "sort_extras", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "telemetry_enabled": { + "name": "telemetry_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": { + "user_settings_user_id_users_id_fk": { + "name": "user_settings_user_id_users_id_fk", + "tableFrom": "user_settings", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_settings_user_id_unique": { + "name": "user_settings_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "steam_id_64": { + "name": "steam_id_64", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_username_unique": { + "name": "users_username_unique", + "nullsNotDistinct": false, + "columns": ["username"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.xrel_notified_releases": { + "name": "xrel_notified_releases", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "xrel_release_id": { + "name": "xrel_release_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": { + "xrel_notified_releases_game_id_games_id_fk": { + "name": "xrel_notified_releases_game_id_games_id_fk", + "tableFrom": "xrel_notified_releases", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/migrations-pg/meta/_journal.json b/migrations-pg/meta/_journal.json index 73268fcd6..db773ba15 100644 --- a/migrations-pg/meta/_journal.json +++ b/migrations-pg/meta/_journal.json @@ -57,6 +57,13 @@ "when": 1791193363035, "tag": "0007_sticky_thor", "breakpoints": true + }, + { + "idx": 8, + "version": "7", + "when": 1791212677241, + "tag": "0008_cultured_stephen_strange", + "breakpoints": true } ] } diff --git a/migrations/0043_massive_dormammu.sql b/migrations/0043_massive_dormammu.sql new file mode 100644 index 000000000..b3df82a2e --- /dev/null +++ b/migrations/0043_massive_dormammu.sql @@ -0,0 +1 @@ +ALTER TABLE `games` ADD `installed_version` text; \ No newline at end of file diff --git a/migrations/meta/0043_snapshot.json b/migrations/meta/0043_snapshot.json new file mode 100644 index 000000000..e4a2c0b0c --- /dev/null +++ b/migrations/meta/0043_snapshot.json @@ -0,0 +1,2337 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "d6f633c9-9943-4e6d-b369-e5bfb84b2c60", + "prevId": "eb7a6251-80b1-4ba9-8d4c-12d0d198d3b6", + "tables": { + "ai_auto_download_holds": { + "name": "ai_auto_download_holds", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "release_title": { + "name": "release_title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "ai_auto_download_holds_game_title_idx": { + "name": "ai_auto_download_holds_game_title_idx", + "columns": ["game_id", "release_title"], + "isUnique": true + } + }, + "foreignKeys": { + "ai_auto_download_holds_game_id_games_id_fk": { + "name": "ai_auto_download_holds_game_id_games_id_fk", + "tableFrom": "ai_auto_download_holds", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "api_keys": { + "name": "api_keys", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "key_hash": { + "name": "key_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + }, + "last_used_at": { + "name": "last_used_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "api_keys_key_hash_idx": { + "name": "api_keys_key_hash_idx", + "columns": ["key_hash"], + "isUnique": true + }, + "api_keys_user_id_idx": { + "name": "api_keys_user_id_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "downloaders": { + "name": "downloaders", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "use_ssl": { + "name": "use_ssl", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "url_path": { + "name": "url_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "allow_self_signed_certificate": { + "name": "allow_self_signed_certificate", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "allow_insecure_lan": { + "name": "allow_insecure_lan", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "download_path": { + "name": "download_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'games'" + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'Questarr'" + }, + "add_stopped": { + "name": "add_stopped", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "remove_completed": { + "name": "remove_completed", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "post_import_category": { + "name": "post_import_category", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "settings": { + "name": "settings", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "game_downloads": { + "name": "game_downloads", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "downloader_id": { + "name": "downloader_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "download_type": { + "name": "download_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'torrent'" + }, + "download_hash": { + "name": "download_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "download_title": { + "name": "download_title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'downloading'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "file_size": { + "name": "file_size", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "added_at": { + "name": "added_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + }, + "completed_at": { + "name": "completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "game_downloads_downloader_hash_idx": { + "name": "game_downloads_downloader_hash_idx", + "columns": ["downloader_id", "download_hash"], + "isUnique": true + } + }, + "foreignKeys": { + "game_downloads_game_id_games_id_fk": { + "name": "game_downloads_game_id_games_id_fk", + "tableFrom": "game_downloads", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_downloads_downloader_id_downloaders_id_fk": { + "name": "game_downloads_downloader_id_downloaders_id_fk", + "tableFrom": "game_downloads", + "tableTo": "downloaders", + "columnsFrom": ["downloader_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "game_files": { + "name": "game_files", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "download_id": { + "name": "download_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "original_name": { + "name": "original_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "stored_name": { + "name": "stored_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category_overridden": { + "name": "category_overridden", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_size": { + "name": "file_size", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "game_files_game_id_idx": { + "name": "game_files_game_id_idx", + "columns": ["game_id"], + "isUnique": false + }, + "game_files_download_id_idx": { + "name": "game_files_download_id_idx", + "columns": ["download_id"], + "isUnique": false + } + }, + "foreignKeys": { + "game_files_game_id_games_id_fk": { + "name": "game_files_game_id_games_id_fk", + "tableFrom": "game_files", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_files_download_id_game_downloads_id_fk": { + "name": "game_files_download_id_game_downloads_id_fk", + "tableFrom": "game_files", + "tableTo": "game_downloads", + "columnsFrom": ["download_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "game_journal_entries": { + "name": "game_journal_entries", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "game_journal_entries_game_user_idx": { + "name": "game_journal_entries_game_user_idx", + "columns": ["game_id", "user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "game_journal_entries_game_id_games_id_fk": { + "name": "game_journal_entries_game_id_games_id_fk", + "tableFrom": "game_journal_entries", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_journal_entries_user_id_users_id_fk": { + "name": "game_journal_entries_user_id_users_id_fk", + "tableFrom": "game_journal_entries", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "game_milestones": { + "name": "game_milestones", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "completed_at": { + "name": "completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "game_milestones_game_user_idx": { + "name": "game_milestones_game_user_idx", + "columns": ["game_id", "user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "game_milestones_game_id_games_id_fk": { + "name": "game_milestones_game_id_games_id_fk", + "tableFrom": "game_milestones", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_milestones_user_id_users_id_fk": { + "name": "game_milestones_user_id_users_id_fk", + "tableFrom": "game_milestones", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "game_screenshots": { + "name": "game_screenshots", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "caption": { + "name": "caption", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "game_screenshots_game_user_idx": { + "name": "game_screenshots_game_user_idx", + "columns": ["game_id", "user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "game_screenshots_game_id_games_id_fk": { + "name": "game_screenshots_game_id_games_id_fk", + "tableFrom": "game_screenshots", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_screenshots_user_id_users_id_fk": { + "name": "game_screenshots_user_id_users_id_fk", + "tableFrom": "game_screenshots", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "games": { + "name": "games", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "igdb_id": { + "name": "igdb_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "steam_appid": { + "name": "steam_appid", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cover_url": { + "name": "cover_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "release_date": { + "name": "release_date", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rating": { + "name": "rating", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "platforms": { + "name": "platforms", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_platform_id": { + "name": "target_platform_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_platform_name": { + "name": "target_platform_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "genres": { + "name": "genres", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "themes": { + "name": "themes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "publishers": { + "name": "publishers", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "developers": { + "name": "developers", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "screenshots": { + "name": "screenshots", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'manual'" + }, + "igdb_websites": { + "name": "igdb_websites", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expansions": { + "name": "expansions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "aggregated_rating": { + "name": "aggregated_rating", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_to_beat_hastily": { + "name": "time_to_beat_hastily", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_to_beat_normally": { + "name": "time_to_beat_normally", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_to_beat_completely": { + "name": "time_to_beat_completely", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'wanted'" + }, + "original_release_date": { + "name": "original_release_date", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "release_status": { + "name": "release_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'upcoming'" + }, + "early_access": { + "name": "early_access", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "hidden": { + "name": "hidden", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "is_adult_content": { + "name": "is_adult_content", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "is_age_restricted": { + "name": "is_age_restricted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "user_rating": { + "name": "user_rating", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "library_path": { + "name": "library_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "installed_version": { + "name": "installed_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "search_results_available": { + "name": "search_results_available", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "search_results_available_at": { + "name": "search_results_available_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "update_search_results_available": { + "name": "update_search_results_available", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "packs_search_results_available": { + "name": "packs_search_results_available", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "added_at": { + "name": "added_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + }, + "completed_at": { + "name": "completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "games_user_id_users_id_fk": { + "name": "games_user_id_users_id_fk", + "tableFrom": "games", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "import_task_items": { + "name": "import_task_items", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "item_name": { + "name": "item_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "result": { + "name": "result", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "game_title": { + "name": "game_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "import_task_items_task_id_idx": { + "name": "import_task_items_task_id_idx", + "columns": ["task_id"], + "isUnique": false + } + }, + "foreignKeys": { + "import_task_items_task_id_import_tasks_id_fk": { + "name": "import_task_items_task_id_import_tasks_id_fk", + "tableFrom": "import_task_items", + "tableTo": "import_tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "import_tasks": { + "name": "import_tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "task_type": { + "name": "task_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "triggered_by": { + "name": "triggered_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + }, + "started_at": { + "name": "started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "completed_at": { + "name": "completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "total_items": { + "name": "total_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "added_items": { + "name": "added_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "skipped_items": { + "name": "skipped_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "failed_items": { + "name": "failed_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "import_tasks_user_id_users_id_fk": { + "name": "import_tasks_user_id_users_id_fk", + "tableFrom": "import_tasks", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "indexers": { + "name": "indexers", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "protocol": { + "name": "protocol", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'torznab'" + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "categories": { + "name": "categories", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'[]'" + }, + "rss_enabled": { + "name": "rss_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "auto_search_enabled": { + "name": "auto_search_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "allow_insecure_lan": { + "name": "allow_insecure_lan", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "notifications": { + "name": "notifications", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "read": { + "name": "read", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": {}, + "foreignKeys": { + "notifications_user_id_users_id_fk": { + "name": "notifications_user_id_users_id_fk", + "tableFrom": "notifications", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "path_mappings": { + "name": "path_mappings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "remote_path": { + "name": "remote_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "local_path": { + "name": "local_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "remote_host": { + "name": "remote_host", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "platform_mappings": { + "name": "platform_mappings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "igdb_platform_id": { + "name": "igdb_platform_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_platform_name": { + "name": "source_platform_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "release_blacklist": { + "name": "release_blacklist", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "release_title": { + "name": "release_title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "indexer_name": { + "name": "indexer_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "release_blacklist_game_title_idx": { + "name": "release_blacklist_game_title_idx", + "columns": ["game_id", "release_title"], + "isUnique": true + } + }, + "foreignKeys": { + "release_blacklist_game_id_games_id_fk": { + "name": "release_blacklist_game_id_games_id_fk", + "tableFrom": "release_blacklist", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "root_folders": { + "name": "root_folders", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "allow_delete": { + "name": "allow_delete", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "accessible": { + "name": "accessible", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "disk_free_bytes": { + "name": "disk_free_bytes", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "disk_total_bytes": { + "name": "disk_total_bytes", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_scanned_at": { + "name": "last_scanned_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "root_folders_path_unique": { + "name": "root_folders_path_unique", + "columns": ["path"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "rss_feed_items": { + "name": "rss_feed_items", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "feed_id": { + "name": "feed_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "guid": { + "name": "guid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "pub_date": { + "name": "pub_date", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source_name": { + "name": "source_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "igdb_game_id": { + "name": "igdb_game_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "igdb_game_name": { + "name": "igdb_game_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cover_url": { + "name": "cover_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": {}, + "foreignKeys": { + "rss_feed_items_feed_id_rss_feeds_id_fk": { + "name": "rss_feed_items_feed_id_rss_feeds_id_fk", + "tableFrom": "rss_feed_items", + "tableTo": "rss_feeds", + "columnsFrom": ["feed_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "rss_feeds": { + "name": "rss_feeds", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'custom'" + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "mapping": { + "name": "mapping", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_check": { + "name": "last_check", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'ok'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "system_config": { + "name": "system_config", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_settings": { + "name": "user_settings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "auto_search_enabled": { + "name": "auto_search_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "auto_download_enabled": { + "name": "auto_download_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "notification_preferences": { + "name": "notification_preferences", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "search_interval_hours": { + "name": "search_interval_hours", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 6 + }, + "igdb_rate_limit_per_second": { + "name": "igdb_rate_limit_per_second", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 3 + }, + "download_rules": { + "name": "download_rules", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_auto_search": { + "name": "last_auto_search", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "xrel_scene_releases": { + "name": "xrel_scene_releases", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "xrel_p2p_releases": { + "name": "xrel_p2p_releases", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "auto_search_unreleased": { + "name": "auto_search_unreleased", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "steam_sync_failures": { + "name": "steam_sync_failures", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "steam_sync_enabled": { + "name": "steam_sync_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "steam_sync_interval_hours": { + "name": "steam_sync_interval_hours", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 24 + }, + "last_steam_sync": { + "name": "last_steam_sync", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "preferred_release_groups": { + "name": "preferred_release_groups", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "filter_by_preferred_groups": { + "name": "filter_by_preferred_groups", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "release_name_blacklist": { + "name": "release_name_blacklist", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "preferred_platform": { + "name": "preferred_platform", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hide_adult_content": { + "name": "hide_adult_content", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "hide_age_restricted_content": { + "name": "hide_age_restricted_content", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "hide_shelved_by_default": { + "name": "hide_shelved_by_default", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "hide_owned_in_has_results": { + "name": "hide_owned_in_has_results", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "enable_post_processing": { + "name": "enable_post_processing", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "auto_unpack": { + "name": "auto_unpack", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "rename_pattern": { + "name": "rename_pattern", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{Title} ({Region})'" + }, + "overwrite_existing": { + "name": "overwrite_existing", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "transfer_mode": { + "name": "transfer_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'hardlink'" + }, + "import_platform_ids": { + "name": "import_platform_ids", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'[]'" + }, + "ignored_extensions": { + "name": "ignored_extensions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'[]'" + }, + "min_file_size": { + "name": "min_file_size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "library_root": { + "name": "library_root", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'/data'" + }, + "auto_delete_after_import": { + "name": "auto_delete_after_import", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "sort_extras": { + "name": "sort_extras", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "telemetry_enabled": { + "name": "telemetry_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "user_settings_user_id_unique": { + "name": "user_settings_user_id_unique", + "columns": ["user_id"], + "isUnique": true + } + }, + "foreignKeys": { + "user_settings_user_id_users_id_fk": { + "name": "user_settings_user_id_users_id_fk", + "tableFrom": "user_settings", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "steam_id_64": { + "name": "steam_id_64", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "users_username_unique": { + "name": "users_username_unique", + "columns": ["username"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "xrel_notified_releases": { + "name": "xrel_notified_releases", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "xrel_release_id": { + "name": "xrel_release_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": {}, + "foreignKeys": { + "xrel_notified_releases_game_id_games_id_fk": { + "name": "xrel_notified_releases_game_id_games_id_fk", + "tableFrom": "xrel_notified_releases", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/migrations/meta/_journal.json b/migrations/meta/_journal.json index d8a1bcfd8..6a0ba9d8e 100644 --- a/migrations/meta/_journal.json +++ b/migrations/meta/_journal.json @@ -309,6 +309,13 @@ "when": 1791193362024, "tag": "0042_outstanding_arclight", "breakpoints": true + }, + { + "idx": 43, + "version": "6", + "when": 1791212676341, + "tag": "0043_massive_dormammu", + "breakpoints": true } ] } diff --git a/server/__tests__/api_routes.test.ts b/server/__tests__/api_routes.test.ts index 8a0a0b8ee..ba7434899 100644 --- a/server/__tests__/api_routes.test.ts +++ b/server/__tests__/api_routes.test.ts @@ -972,6 +972,61 @@ describe("API Routes - Extended Coverage", () => { }); }); + describe("PATCH /api/games/:id/installed-version", () => { + const gameId = "123e4567-e89b-12d3-a456-426614174000"; + + it("should set a trimmed version scoped to the authenticated user", async () => { + vi.mocked(storage.updateGameInstalledVersion).mockResolvedValue({ + id: gameId, + installedVersion: "v1.2.3", + } as unknown as Game); + + const response = await request(app) + .patch(`/api/games/${gameId}/installed-version`) + .send({ installedVersion: " v1.2.3 " }); + expect(response.status).toBe(200); + expect(vi.mocked(storage.updateGameInstalledVersion)).toHaveBeenCalledWith( + gameId, + "user-1", + "v1.2.3" + ); + }); + + it("should clear the version with a blank value", async () => { + vi.mocked(storage.updateGameInstalledVersion).mockResolvedValue({ + id: gameId, + installedVersion: null, + } as unknown as Game); + + const response = await request(app) + .patch(`/api/games/${gameId}/installed-version`) + .send({ installedVersion: " " }); + expect(response.status).toBe(200); + expect(vi.mocked(storage.updateGameInstalledVersion)).toHaveBeenCalledWith( + gameId, + "user-1", + null + ); + }); + + it("should reject a version longer than 64 characters", async () => { + const response = await request(app) + .patch(`/api/games/${gameId}/installed-version`) + .send({ installedVersion: "v".repeat(65) }); + expect(response.status).toBe(400); + expect(response.body.error).toBe("Invalid installed version data"); + }); + + it("should return 404 when the game is not the user's", async () => { + vi.mocked(storage.updateGameInstalledVersion).mockResolvedValue(undefined); + + const response = await request(app) + .patch(`/api/games/${gameId}/installed-version`) + .send({ installedVersion: "v1" }); + expect(response.status).toBe(404); + }); + }); + describe("PATCH /api/games/:id/user-rating", () => { const gameId = "123e4567-e89b-12d3-a456-426614174000"; diff --git a/server/__tests__/cron_autosearch.test.ts b/server/__tests__/cron_autosearch.test.ts index 2b901dd63..1e00cfc18 100644 --- a/server/__tests__/cron_autosearch.test.ts +++ b/server/__tests__/cron_autosearch.test.ts @@ -30,6 +30,7 @@ const mockAddNotification = vi.fn(); const mockUpdateGameSearchResultsAvailable = vi.fn(); const mockUpdateGameSearchResultsByCategory = vi.fn(); const mockUpdateGameStatus = vi.fn(); +const mockUpdateGame = vi.fn(); const mockAddGameDownload = vi.fn(); const mockGetEnabledDownloaders = vi.fn().mockResolvedValue([]); const mockGetReleaseBlacklistSet = vi.fn(); @@ -48,6 +49,7 @@ vi.mock("../storage.js", () => ({ updateGameSearchResultsAvailable: mockUpdateGameSearchResultsAvailable, updateGameSearchResultsByCategory: mockUpdateGameSearchResultsByCategory, updateGameStatus: mockUpdateGameStatus, + updateGame: mockUpdateGame, addGameDownload: mockAddGameDownload, getEnabledDownloaders: mockGetEnabledDownloaders, getReleaseBlacklistSet: mockGetReleaseBlacklistSet, @@ -122,7 +124,8 @@ vi.mock("../xrel.js", () => ({ // Import the function under test // We need to use dynamic import or require because of the hoisting of vi.mock -const { checkAutoSearch, categorizeSearchItems } = await import("../cron.js"); +const { checkAutoSearch, categorizeSearchItems, recordVersionFromCompletedDownload } = + await import("../cron.js"); const { igdbLogger } = await import("../logger.js"); describe("Cron - checkAutoSearch", () => { @@ -366,6 +369,52 @@ describe("Cron - checkAutoSearch", () => { ); }); + it("should not notify updates that are not newer than the installed version", async () => { + const game = { + ...baseGame, + status: "owned" as const, + releaseStatus: "released" as const, + installedVersion: "v1.2", + }; + const settings = { ...baseSettings, notifyUpdates: true }; + + mockGetWantedGamesGroupedByUser.mockResolvedValue(new Map([[userId, []]])); + mockGetUserGames.mockResolvedValue([game]); + mockGetUserSettings.mockResolvedValue(settings); + mockSearchAllIndexers.mockResolvedValue({ items: [UPDATE_ITEM], errors: [], total: 1 }); + + await checkAutoSearch(); + + expect(mockAddNotification).not.toHaveBeenCalledWith( + expect.objectContaining({ title: "Game Updates Available" }) + ); + expect(mockUpdateGameSearchResultsByCategory).toHaveBeenCalledWith( + game.id, + expect.objectContaining({ updates: false }) + ); + }); + + it("should notify updates newer than the installed version", async () => { + const game = { + ...baseGame, + status: "owned" as const, + releaseStatus: "released" as const, + installedVersion: "1.0", + }; + const settings = { ...baseSettings, notifyUpdates: true }; + + mockGetWantedGamesGroupedByUser.mockResolvedValue(new Map([[userId, []]])); + mockGetUserGames.mockResolvedValue([game]); + mockGetUserSettings.mockResolvedValue(settings); + mockSearchAllIndexers.mockResolvedValue({ items: [UPDATE_ITEM], errors: [], total: 1 }); + + await checkAutoSearch(); + + expect(mockAddNotification).toHaveBeenCalledWith( + expect.objectContaining({ title: "Game Updates Available" }) + ); + }); + it("should still notify game availability for wanted games when main results exist", async () => { const game = { ...baseGame, status: "wanted" as const, releaseStatus: "released" as const }; const settings = { ...baseSettings, notifyUpdates: true, autoDownloadEnabled: false }; @@ -2326,3 +2375,50 @@ describe("Cron - checkAutoSearch", () => { }); }); }); + +describe("Cron - recordVersionFromCompletedDownload", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("records the version of a finished full-game download when none is known", async () => { + const recorded = await recordVersionFromCompletedDownload( + { id: "g1", installedVersion: null }, + "Test.Game.v1.2.3-RUNE" + ); + expect(recorded).toBe("v1.2.3"); + expect(mockUpdateGame).toHaveBeenCalledWith("g1", { installedVersion: "v1.2.3" }); + }); + + it("moves the version forward on a newer update", async () => { + await recordVersionFromCompletedDownload( + { id: "g1", installedVersion: "v1.2" }, + "Test.Game.Update.v1.3-RUNE" + ); + expect(mockUpdateGame).toHaveBeenCalledWith("g1", { installedVersion: "v1.3" }); + }); + + it("never moves the version backwards or across numbering schemes", async () => { + await recordVersionFromCompletedDownload( + { id: "g1", installedVersion: "v1.5" }, + "Test.Game.Update.v1.3-RUNE" + ); + await recordVersionFromCompletedDownload( + { id: "g1", installedVersion: "Build 1234" }, + "Test.Game.v1.3-RUNE" + ); + expect(mockUpdateGame).not.toHaveBeenCalled(); + }); + + it("ignores DLC releases and releases without a version", async () => { + await recordVersionFromCompletedDownload( + { id: "g1", installedVersion: null }, + "Test.Game.Season.Pass.DLC.v2.0-RUNE" + ); + await recordVersionFromCompletedDownload( + { id: "g1", installedVersion: null }, + "Test.Game-RUNE" + ); + expect(mockUpdateGame).not.toHaveBeenCalled(); + }); +}); diff --git a/server/__tests__/database_storage_extended.test.ts b/server/__tests__/database_storage_extended.test.ts index 3ee0136af..75744b7f5 100644 --- a/server/__tests__/database_storage_extended.test.ts +++ b/server/__tests__/database_storage_extended.test.ts @@ -184,6 +184,10 @@ describe("DatabaseStorage Extended Coverage", () => { const ratingUpdated = await storage.updateGameUserRating(game.id, userId, 8.5); expect(ratingUpdated?.userRating).toBe(8.5); + const versionUpdated = await storage.updateGameInstalledVersion(game.id, userId, "v1.2.3"); + expect(versionUpdated?.installedVersion).toBe("v1.2.3"); + expect(await storage.updateGameInstalledVersion(game.id, "other-user", "v9")).toBeUndefined(); + await storage.updateGameSearchResultsAvailable(game.id, true); const refetched = await storage.getGame(game.id); expect(refetched?.searchResultsAvailable).toBe(true); diff --git a/server/__tests__/fixtures/common-route-mocks.ts b/server/__tests__/fixtures/common-route-mocks.ts index 5b7c5aec1..bc67d755e 100644 --- a/server/__tests__/fixtures/common-route-mocks.ts +++ b/server/__tests__/fixtures/common-route-mocks.ts @@ -68,6 +68,7 @@ export function createStorageMock() { updateGameStatus: vi.fn(), updateGameHidden: vi.fn(), updateGameUserRating: vi.fn(), + updateGameInstalledVersion: vi.fn(), updateGame: vi.fn(), getGameJournalEntries: vi.fn().mockResolvedValue([]), addGameJournalEntry: vi.fn(), diff --git a/server/__tests__/helpers/import-test-helpers.ts b/server/__tests__/helpers/import-test-helpers.ts index d5f1184b2..1ae26c900 100644 --- a/server/__tests__/helpers/import-test-helpers.ts +++ b/server/__tests__/helpers/import-test-helpers.ts @@ -26,6 +26,7 @@ export function makeGame(overrides: Partial = {}): Game { isAdultContent: false, isAgeRestricted: false, libraryPath: null, + installedVersion: null, originalReleaseDate: null, releaseStatus: null, addedAt: null, diff --git a/server/cron.ts b/server/cron.ts index 00600deec..6d9017fee 100644 --- a/server/cron.ts +++ b/server/cron.ts @@ -30,6 +30,11 @@ import { type NotificationPreferences, } from "../shared/schema.js"; import { categorizeDownload } from "../shared/download-categorizer.js"; +import { + compareVersions, + extractVersionFromReleaseName, + isReleasePossiblyNewer, +} from "../shared/version-utils.js"; import { releaseMatchesGame, normalizeTitle, @@ -145,6 +150,35 @@ export async function getAiAutoDownloadHoldReason( return null; } +/** + * Records the version carried by a finished download's release name (e.g. "v1.2.3") as the + * game's installed version. Only the full game or an update counts (a DLC's version says nothing + * about the base game), and a known version is only ever moved forward: an older or + * incomparable release never overwrites what the user has. Returns the version recorded, if any. + */ +export async function recordVersionFromCompletedDownload( + game: Pick, + downloadTitle: string +): Promise { + const { category } = categorizeDownload(downloadTitle); + if (category !== "main" && category !== "update") return null; + + const detected = extractVersionFromReleaseName(downloadTitle); + if (!detected) return null; + + if (game.installedVersion?.trim()) { + const cmp = compareVersions(detected, game.installedVersion); + if (cmp === null || cmp <= 0) return null; + } + + await storage.updateGame(game.id, { installedVersion: detected }); + igdbLogger.info( + { gameId: game.id, previous: game.installedVersion, installedVersion: detected }, + "Recorded game version from completed download" + ); + return detected; +} + function getAutoSearchRules(downloadRules: string | null): AutoSearchRules { let minSeeders = 0; let sortBy: DownloadSortBy = "seeders"; @@ -911,6 +945,17 @@ export async function checkDownloadStatus() { const gameTitle = game ? game.title : download.downloadTitle; const importConfig = await storage.getImportConfig(game?.userId ?? undefined); + if (game) { + try { + await recordVersionFromCompletedDownload(game, download.downloadTitle); + } catch (error) { + igdbLogger.warn( + { error, gameId: game.id, item: download.downloadTitle }, + "Failed to record game version from completed download" + ); + } + } + let shouldSendCompletionNotification = true; if (importConfig.enablePostProcessing) { @@ -1544,7 +1589,12 @@ export async function checkAutoSearch() { preferredGroups, settings.filterByPreferredGroups ?? false ); - const updateItems = deduplicateByTitle(groupFilteredUpdate, indexerPriorityMap); + // Drop update releases whose version is provably not newer than the one the user + // has installed, so a game already on v1.5 isn't flagged for a v1.4 patch. + const versionFilteredUpdate = groupFilteredUpdate.filter((item) => + isReleasePossiblyNewer(item.title, game.installedVersion) + ); + const updateItems = deduplicateByTitle(versionFilteredUpdate, indexerPriorityMap); // Packs/add-ons are content for owned games, surfaced like updates. const platformFilteredPacks = applyPreferredPlatformFilter( diff --git a/server/routes.ts b/server/routes.ts index eeacb8c38..73dae6408 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -13,6 +13,7 @@ import { updateGameStatusSchema, updateGameHiddenSchema, updateGameUserRatingSchema, + updateGameInstalledVersionSchema, updateGameTargetPlatformSchema, insertIndexerSchema, insertDownloaderSchema, @@ -1862,6 +1863,35 @@ export async function registerRoutes(app: Express): Promise { } ); + // Set the version of the game the user has installed (free text), or null to clear it. + // Used to skip "update available" notifications for releases that aren't newer. + app.patch( + "/api/games/:id/installed-version", + sensitiveEndpointLimiter, + sanitizeGameId, + validateRequest, + async (req: Request, res: Response) => { + try { + const { id } = req.params as { id: string }; + const userId = req.user!.id; + const { installedVersion } = updateGameInstalledVersionSchema.parse(req.body); + + const updatedGame = await storage.updateGameInstalledVersion(id, userId, installedVersion); + if (!updatedGame) { + return res.status(404).json({ error: "Game not found" }); + } + + return res.json(updatedGame); + } catch (error) { + if (error instanceof z.ZodError) { + return respondWithZodError(res, error, "Invalid installed version data"); + } + routesLogger.error({ error }, "error updating game installed version"); + return res.status(500).json({ error: "Failed to update installed version" }); + } + } + ); + // Update the per-game download target, or clear it to use the account default. app.patch( "/api/games/:id/target-platform", diff --git a/server/storage.ts b/server/storage.ts index 3f544ddad..0dead2bf3 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -243,6 +243,11 @@ export interface IStorage { userId: string, userRating: number | null ): Promise; + updateGameInstalledVersion( + id: string, + userId: string, + installedVersion: string | null + ): Promise; updateGameSearchResultsAvailable(gameId: string, available: boolean): Promise; updateGameSearchResultsByCategory( gameId: string, @@ -675,6 +680,7 @@ export class MemStorage implements IStorage { packsSearchResultsAvailable: false, userRating: null, libraryPath: null, + installedVersion: null, addedAt: new Date(), completedAt: null, }; @@ -736,6 +742,19 @@ export class MemStorage implements IStorage { return updatedGame; } + async updateGameInstalledVersion( + id: string, + userId: string, + installedVersion: string | null + ): Promise { + const game = this.games.get(id); + if (!game || game.userId !== userId) return undefined; + + const updatedGame: Game = { ...game, installedVersion }; + this.games.set(id, updatedGame); + return updatedGame; + } + async getGameJournalEntries(gameId: string, userId: string): Promise { return Array.from(this.gameJournalEntries.values()) .filter((entry) => entry.gameId === gameId && entry.userId === userId) @@ -2322,6 +2341,19 @@ export class DatabaseStorage implements IStorage { return updatedGame || undefined; } + async updateGameInstalledVersion( + id: string, + userId: string, + installedVersion: string | null + ): Promise { + const [updatedGame] = await db + .update(games) + .set({ installedVersion }) + .where(and(eq(games.id, id), eq(games.userId, userId))) + .returning(); + return updatedGame || undefined; + } + async getGameJournalEntries(gameId: string, userId: string): Promise { return db .select() diff --git a/shared/__tests__/version-utils.test.ts b/shared/__tests__/version-utils.test.ts new file mode 100644 index 000000000..acb1ff0f8 --- /dev/null +++ b/shared/__tests__/version-utils.test.ts @@ -0,0 +1,82 @@ +import { describe, it, expect } from "vitest"; +import { + compareVersions, + extractVersionFromReleaseName, + isReleasePossiblyNewer, + parseVersion, +} from "../version-utils"; + +describe("extractVersionFromReleaseName", () => { + it.each([ + ["Cyberpunk.2077.v2.12-GOG", "v2.12"], + ["Hades.II.v123456-RUNE", "v123456"], + ["setup_baldurs_gate_3_v4.1.1.6072089_(64bit)_(74309).exe", "v4.1.1.6072089"], + ["Elden Ring [v 1.10] [FitGirl Repack]", "v1.10"], + ["Starfield.Update.1.7.23-RUNE", "v1.7.23"], + ["Starfield.Update.v1.7.29-RUNE", "v1.7.29"], + ["Valheim.Build.12345678-P2P", "Build 12345678"], + ["Game build_998 Linux", "Build 998"], + ])("finds the version in %s", (name, expected) => { + expect(extractVersionFromReleaseName(name)).toBe(expected); + }); + + it.each([ + "Test.Game-RUNE", + "Some.Game.Update.2-CODEX", // second update pack, not a version + "Game.x64v2.Edition", // "v2" glued to a word + "Game.dev1.2.Repack", + ])("finds nothing in %s", (name) => { + expect(extractVersionFromReleaseName(name)).toBeNull(); + }); +}); + +describe("parseVersion", () => { + it("accepts user-typed forms", () => { + expect(parseVersion("1.2.3")).toEqual({ kind: "version", parts: [1, 2, 3] }); + expect(parseVersion(" V1.05 ")).toEqual({ kind: "version", parts: [1, 5] }); + expect(parseVersion("Build 42")).toEqual({ kind: "build", parts: [42] }); + }); + + it("rejects free text", () => { + expect(parseVersion("latest")).toBeNull(); + expect(parseVersion("1.2 hotfix")).toBeNull(); + expect(parseVersion("")).toBeNull(); + expect(parseVersion(null)).toBeNull(); + }); +}); + +describe("compareVersions", () => { + it("compares dotted versions segment by segment", () => { + expect(compareVersions("v1.10", "v1.9")).toBe(1); + expect(compareVersions("1.2", "v1.2.0")).toBe(0); + expect(compareVersions("v1.2", "1.2.1")).toBe(-1); + }); + + it("compares build numbers and bare numbers", () => { + expect(compareVersions("Build 200", "build 100")).toBe(1); + expect(compareVersions("v123457", "v123456")).toBe(1); + }); + + it("returns null across numbering schemes", () => { + expect(compareVersions("Build 200", "v1.2")).toBeNull(); + expect(compareVersions("v20231005", "v1.2")).toBeNull(); + expect(compareVersions("latest", "v1.2")).toBeNull(); + }); +}); + +describe("isReleasePossiblyNewer", () => { + it("is true when nothing is known", () => { + expect(isReleasePossiblyNewer("Game.Update.v1.1-RUNE", null)).toBe(true); + expect(isReleasePossiblyNewer("Game.Update-RUNE", "v1.2")).toBe(true); + expect(isReleasePossiblyNewer("Game.Update.v1.1-RUNE", "latest")).toBe(true); + }); + + it("is false for an equal or older release", () => { + expect(isReleasePossiblyNewer("Game.Update.v1.1-RUNE", "v1.1")).toBe(false); + expect(isReleasePossiblyNewer("Game.Update.v1.1-RUNE", "1.2")).toBe(false); + }); + + it("is true for a newer release", () => { + expect(isReleasePossiblyNewer("Game.Update.v1.3-RUNE", "1.2")).toBe(true); + }); +}); diff --git a/shared/schema.pg.ts b/shared/schema.pg.ts index c3b2a8df1..96f3b3e98 100644 --- a/shared/schema.pg.ts +++ b/shared/schema.pg.ts @@ -171,6 +171,7 @@ export const games = pgTable("games", { isAgeRestricted: boolean("is_age_restricted").notNull().default(false), userRating: doublePrecision("user_rating"), libraryPath: text("library_path"), + installedVersion: text("installed_version"), searchResultsAvailable: boolean("search_results_available").default(false).notNull(), searchResultsAvailableAt: timestampMs("search_results_available_at"), updateSearchResultsAvailable: boolean("update_search_results_available").default(false).notNull(), diff --git a/shared/schema.ts b/shared/schema.ts index c6f68456f..969b6d202 100644 --- a/shared/schema.ts +++ b/shared/schema.ts @@ -224,6 +224,7 @@ export const games = sqliteTable("games", { isAgeRestricted: integer("is_age_restricted", { mode: "boolean" }).notNull().default(false), userRating: real("user_rating"), libraryPath: text("library_path"), + installedVersion: text("installed_version"), searchResultsAvailable: integer("search_results_available", { mode: "boolean" }) .default(false) .notNull(), @@ -583,6 +584,16 @@ export const updateGameUserRatingSchema = z.object({ .nullable(), }); +export const updateGameInstalledVersionSchema = z.object({ + // Free text ("v1.2.3", "Build 12345", "1.05 hotfix"...); blank clears it. + installedVersion: z + .string() + .trim() + .max(64, "installedVersion must be at most 64 characters") + .nullable() + .transform((v) => (v ? v : null)), +}); + export const insertGameJournalEntrySchema = createInsertSchema(gameJournalEntries, { note: (schema) => schema.trim().min(1, "Note cannot be empty").max(10000), }).omit({ diff --git a/shared/version-utils.ts b/shared/version-utils.ts new file mode 100644 index 000000000..47deff821 --- /dev/null +++ b/shared/version-utils.ts @@ -0,0 +1,99 @@ +/** + * Game version helpers: detect a version in a release name, and compare two versions. + * + * Versions are free text on the game (users can type anything), so every function here is + * conservative: when two versions can't be meaningfully compared, the answer is "unknown" + * (null) rather than a guess, and callers treat unknown as "might be newer". + */ + +export type ParsedVersionKind = "version" | "build"; + +export interface ParsedVersion { + kind: ParsedVersionKind; + parts: number[]; +} + +// A version token must not be glued to a preceding letter/digit ("dev1.2", "x64v2"), but `_`, +// `.`, `-`, `(`, `[` and spaces are all used as separators in release names. +const NOT_PRECEDED_BY_ALNUM = "(? 0 ? 1 : -1; + } + return 0; +} + +/** + * Whether a release may hold something newer than the version the user has installed. True + * unless the release name carries a version that is provably equal to or older than it. + */ +export function isReleasePossiblyNewer( + releaseName: string, + installedVersion: string | null | undefined +): boolean { + if (!parseVersion(installedVersion)) return true; + const releaseVersion = extractVersionFromReleaseName(releaseName); + if (!releaseVersion) return true; + const cmp = compareVersions(releaseVersion, installedVersion); + return cmp === null || cmp > 0; +} From 3450885d0fb906b03ba4243e698bd50bbf5277be Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 15:11:42 +0000 Subject: [PATCH 02/28] Remove PR screenshots from the tree Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- .../installed-version/desktop-saved.png | Bin 123990 -> 0 bytes .../installed-version/mobile-saved.png | Bin 129966 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .github/pr-assets/installed-version/desktop-saved.png delete mode 100644 .github/pr-assets/installed-version/mobile-saved.png diff --git a/.github/pr-assets/installed-version/desktop-saved.png b/.github/pr-assets/installed-version/desktop-saved.png deleted file mode 100644 index 38c080a8d63bfea139069ac4937ccdd09109cb1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 123990 zcmd3O^pIVKuEpqRsSx4Q;bUN65P?;d^e`}R-eX{3?c!nHeN#$1 zR)m4^5Cg0vZ}1}faOM6h_C0x~A49Db8=IL484<)eUb43A?D?-A$}=m$T&J+Ip4}gZdZ}9Pkn(VT{Nh-nzqB_Hbjw zC2il>y@16+M6U zpLpH(-aDpK5#iTh@l&Aw{6O4Ak{JJ*)7Y8S)?gKzxp14;CXceU4znfMdy{bKy~X=h;dR<1YtHyQk=h5J;Gs&cuW zz%HVD62cH@R66UhcyEdOuhP5A5#r;!I7BKd@(e3TJDi$lQI?=ueRnL@wT04%Jt&ZE z5|>RU00ggQRgtcpleZhrB0rKycpv%Y`=U2i+XzzQm-J@gj_oWreXxT}Pd-t3FA9s= zT}IS2U19n(x#-i=2{iW~_8F+*R$4Qy+>pG3T8XDxb+iu{Jgfxe*!wb-CjS z1Ae)1bwBy59}F(D4^v9%xmC`k(3k1Pgdk_h#u|xrRaz@e?PA)TexD}uv~bc*Kq8X8 z=!c=~>BAy9t`uR}M!PW!t0DzmmN>j6?-T;9Y;Am*uALXXJ6!nTMnHDtv3DABM}=Yt zlAZ0c<$0gqSRj`^NzeXr$c1Z!>#M0_o#}+Fu>0pP?RL(N_0#U_3f^jt(3YYYS@k&p zzC~rL337L;uiuK}cL8$gdv){M1p@6+A2u~^LPBB+ie&p;cCVbVDZOFN;nK)eeCV9s zXvVN@f?Y z38Rc84j(%6Q2>q66hVB!R41npR5~TfhpM`Pvp^I+T=v)}Uy%U83%kZbZuA>-*(Xmo zs=ii;gO41wNGg|WX%MDUBp1RY^QFN2Zxi3{c8XEp+mJ`##Ha@kHgvory*NdgfC|1$ z#QktoqEZQC;)ISSB!7#k;QR)8zO40;cc8l!$p*5zxS(}?4t+|Ecr%hKz(oK0Bg#Y9 z>Pxp=#{dw+I4u@rsQcF)B(1c(f?qjo;3|IMEsuUOmv2uSWt&*!oqjvNj&g=pHE8S^ ze%c)*2C}Icw6u=vz6IMAYY-1fx@W_KSs;;Yq@A7$imVP3`TF zt>?p%)NT*V2a;c0saYs0IU>hC74M;=GW6o5gD=e?0HceN6*YGLS|&0-yAr2OVJ#k# zG#nTRd+rM~)m-vfGMT-nR}FcxNtC*I<>;wZP`TA0ZDD-2jDB)M_(%VCzFNu#uF{Od z)e0}uP(3Gpjq!%b_-))iA&p{lJ;O8xprrV3t$wsvJL`3(2Se$iQ|WyJQcoXfi#ach z{;ga9Pi#SgC?T-{nyJ;()@jMp{M5GN#V>}|b`vuvpxNJK$`IYLmOwryVq4hJH!$HC z8$P_JOqS3S7UtCWNzgNe65EiDT2YopEl9n>^&uXJ0FN8yg}>ho~y+R9Lmh5XfS1 zEa9U&FJ6C*$_hDTU13Ik>!@?HrifGtu*|qzs$lq*$v*8&@A2gqNh`g%}!YOz*EHY`i!^2}R{EH)WOFUu&}ZASPKud_PM#pqD(B z)E1$B8mmk>R8+)dYLRT?Apa(PA1DYzu^l&=jPA~EprYfCcGze~r`ic55x^mJ7eX#C zAf>JIyb{GbSzo*j#;#D{@HS(v8XL766GSG5g+8x{ar7GGSLCD`nEaC{!LHt3Kww5X zD?UphZeabZj_!^zvhD(wur>@()IC!!=0!L{rbWFsFZ*8PYL1PJRcGyt^t~(KR-y7} zFg@zHHXyczgVCK;&yTaVQWy&1jN)mgf-L4Sch?~8|UZEc2=Jn5y zE|xTLHeO%}yr29TX}UAX5)L$c+k#TlOWOH+8jG)bnRIyPkB!FSANz`FY5`D(uS1&+8*MZ4%kD&pX|VA>7tZ=V2~ zk{}x#-RHDXq2z!Xc2(V3(y?5c@UpsPamGpoA&X**+%Y1W`W?53OkI23P0; z(up)-1U9{4a0fB_q;aBhf}&jN44j>pEjBZp~lT9lr5&KB;b{DA@*DYz7_=G9&T1v?@c*+G)tYw z1Oc#UpeAFL5so~wuoVqx^WDO+`C}2wm#yl?sC(-34U#c}7P%c8mu6_I?z5L(LB2RB zzm~I0Guo(nMt`sU3Fq=ZTWmIKo9@@gZ~Mp(O6Vh51InhI+%A+N%>|4Nml0FIS=AX` zZa>D(xALg%=-uC9nmwB|4I(ILJJ7<|AzOzL9|h7W^N3 zO~OT>vFvQq{L*iX0)OIe=4%Rba!z&o&yFW_`JP^ZgTP2a)70a~fnV@#Q z=v9>{yTxIEeDFn|<^-qI$HEslYpGEZ?4JB&vT6mX^KEZ}K4WMiW78$6_$nROr#s&5 zFhZ72K1M(}+Uc}7F4|p7WeZ}9KTkfl>axhIjHAX?C+{4hsb3L3tDu5>8Ww_DB%9`D zc&ddRZt^+P-Dtg|72(2n&>d)RW(?*qvfZY?J3Y`Pq;2wF>TQFKTr3J*uY6F zR^UA{EQJWnt7FFbYMaA!Lbu4q~4%O z!`p)V6%gF}-v6@{xWX{gwpB8*?8xZahp<#3HrPr7^2BhmjN^wB&dt4?xvh@TxYq4> zL#k7JI@Y}L54w<1J~s`C@{qGviRuYdj)q0y+~ZGhebh*UzD29^XI>Lh<2oWdK+JFT zi1di<$_n6urM4+M+oGznnsaJYWkP7KrC+43+F;m6kCZwtJWMcIIh%Y<5$uC?y^x4( z-{siv6d;GOw&1hO0^-pSOk$XERWM+0h{G`|ZF8Y9pi>n=h#-%o^|cKQ!;jdX(6Moh zDWbn^RsGe2qI)2@+mWXB0lRT{cqwxYVyZJZNVH1x#D=gofca2hrmeG0wcb6TzQ*&k zJJKwcwEwj8@U=zexQi*)MwCHri^bK^E3z%w3cS&P;Y-*%GDFbRSQ%(OK?;OcjPGu` zeb+}XpQJ-pnwTT^OeDk3ESD)mX^ci@kn%P)h4LGBTLg|I2K&mc&!{r8zh0wQZ&J)q z7fR+`RV_Mj7W^=3)JW!Qgix$1jc#=++K23F&dGQF%*TSB@e!vK>S?32*kh#M^`=B7 z;1k=kWJ^Kz9IXs&hE3&sow9lQ+W=Ll`j%X!W3%($VnyP9;B@-Y{FG0Q5=EAux;7^) z8bx?C%IlfL9&RHgV?OpI+!CF>aqThvjo#7J@a#v^wb2Fqxy#4ke=;j&rHhTjy(v^Vo3`nJ$0Q?fik`^Gb@)8x^{4EL172>bFy zDiD5bF9`8)X}|L!Sc0lOpho!l=7kE15GuwS_$V=n8`_|B%_25EVo$@PXT0x|%>Wu; ziBXvL6xZUqr_yR(kciKt7Eeq9X+j!|$I(Y%VQmVu;sw6wS^VYXQMJ0i0&N8djzEEf zDT0qi<0wXzsyX0R>a+I}H&DiJ_)^g;slkynep^9^ws#hxu88-dLH!bHXQNE&Q;0E+<(nMSQQauqi?kh;?JsGW4ll~82=tyvx{yg9Z7Yn9 z@G-O|pv!%H8m#fuYDd*K8xGFY{knPw-8$Wd+2Gv|VgU$GZ>x0sfr_^GG{I0YXZ0`Z zZ$d1vjxiaC#;@#mwr`pl=i6_a%p}wKsqme#h^+(d#PMn@8D9L1DOJ*C2Z#PPPU@rD z0$zWbZ!1CQYeRK-G$v=DFIR5=$b5(a8gEb4HC~ zgL?}2G7f_HC3|a1GY@Dp{-}oBf)=f%@gP}pcO`7{13!bf+`ADQXquO0l(XPZLIy3S zbQFQM(=l7}a;MZazU2<3l211slMDB$K;c+&1->zeAVX0f;o6o-#Eo_-c=zd6j_0PB zBb77+uGY zSgaBkkXH_W7b?A4=<;hivtUvXJ^>PQ1BV;K&p3NGGEGRxM&Y>OS9$VH#Pr<1)wP&NYc19 z?!@)^OX?;=GhJGWm&mx#F&UxpvH`V`WY=X9)12ocG0+{Q_@2JvLjAfz`}fu*N-QCa?t1kVCHgc8(*K zRX^+2DUcq1=G(T?6SnWfM|tXXYv1^`;)CIxIbZ3A?L-2>O+0=u1*y!iktX5w-8@va zQOj<|u+dqf;q4R2GE3uQgHa#n4S$$G#yg(PHCAfm_6t+A zJ`7#{I_qusOLhO3G4Ga8toYI9N6$~(v3y&4g^LBmllzI;AFg~2!;G9|8I%XSa_-$v zYcrx!iD%YL9(<#xJRP$G)h(k`hx($^R)P35hSc%+t;qwrhc|@dgDaM6EgBy};|~JO z>Kngr7QP|D@Uyj$Q>?V9N@8mDxY%*+O&*xI_*PFE)oQBA^P6;~YUs;=pm%%9eTEq| zKFY%RCz0%fxgUIMSN`l_67Lz+9z)xnkda_=+Q-~VF$OH*n|s%N;orar#?Uz z#rH^Q@(002bnZ1EkNL*;WR0Xe9Cl?&H;~C>>yz!j`S~2PIA6i?y1;5{ zTvo2GGVa_{P$QtiuV^;?hVf{0Y}6gjloZogTwFg%I@}~-IV1aUvtWC3#!K`PIBHz5 z#+sY@2t|az>|#o?M(xYqcMiQbIF!y>Z(?cBT69{gL*+*YjhJK@_rwff>e@+Gim+?# zYy6^>f{q4Qi>_%RLu%w}pV473AQ~;A^*TS7-$;o6`c*vz^tHB*KNfR$Y?fgsY;xTh z`EDXtu|Ntz97)0}_Th6*jfNcV_ZH<(=Xg^_xp-(qvO zSG}>iff$yepG}YX@SGI-bSVZz%kH`qnW zY`5AL!O6lt&Sj~5^}+FcUn}et*7}>>wx))uMJ~l@(^^tav|DpIlX7DG?LdYxXQ{Cu zn@6YojDPvGFq#03FaXfpUWPd2{Q(~(ayn-F{47k1_;LbaJ`q3LJ&Q~#sHKa{vYRd{ zLWKIQR}I+kBHZj#aPeU5DRNG&<%q4IW39^IDRrl|R0%21IYLeAn}GXy0L5gDFqcU+ z_n+PAiWfJw@i3Qq#jBeeU=RyRS~q*N>6E>oYFnL?cF;wJNg=Y#j3Uzw)e)TPiL ztw?*9;!nh<9GW0ev@~TN zoq<8y@I)zbwZL1zWM>6KiDNy$tU8qvQs7tZ48NYx0q9p7l&uP1>FAr?Y4p`J_t(cO zcje4LQzjRfTx5Cstt~BDNjw4c1D?RKABBY4sn5?5x=BHX7dI!zhLncKt6a0xZgjA`QA}JjKfB1s_;;BLULlFrxWrMH(o$s80pauPO@(nQnUHewO`31|(`fHhvn6Tf$xQXFiX zn*9!mrRdN=MXF?z*9Gq?<1i&h8RqF9(e0KNS=Y|34fLh56T~%2`%b8u*1M@8XID!Q zkah_-=XxEJoG*bPp%W$5K5Z*%#eLqNGQSDKa=*%sPc-b@Y%=P$D}MBzMxYK(gF_~E zeI}m#sf?dL_8Ky%Mo3@SnK|(aG(5K5?%@f;1ip-8k`6AmaD>Eq|TPTlzW%+ zY}cplw%vYw6TOm#c06@QE~=%>tofc*K3=r%mbV8hU*!!$f$GPciT%9NVCgAtYg@5| zLO@K!8?<5q_t?~HI}NRUEd41Ts3JLYqUvY{co1ok4OTVS{>un=rl zn3#1CXhmbhYnx~r!F&kkgw!ALF%5XiN{Kxd7FSM;DPT@w(=D9TqX@XVcYl^1l8((_ zP>W`IAoBrUSJl-fh_yv0xHQ3S?bs5=G0WZ~Y2uoOEIQR!@1y#JbX+KUg{E`8+ae6FZA< zRjubDMn?P5b1Be6?9(te(TZ-;hp#(g6=@#*kUk83XCfUJbnCFG3sOG2R_%qV(Im;i zJnJg7x@beP5vIaKw|%Bs4tmNa)nAoFNQ>w(B*Y=^e#JH*kPde!bpL&~aT*W2LCkiCZ|lKX^iKs;H@IWY?!{W4{!X*>5P=`fem8L( z15G8k_~(q*1jt+RIK;AlbxD66=DgSxD#`d_BKwKX?81BG%q6U{){W4}V8DG|`j=zJ z;W&P*5{}!Oif10L$28*4KAn0-7148j{`#kp;t`Lq{C&5}Zt7yjQkXgf zvh`yFO9=JY6D- zFJ-6$KWVovJmn-J#T4vQhP7k(aT`mFsECxUZLstk-bcFh}oolacPEofNbboX(?(ffJGgWCNl&NB_NmM8oVtSW6) zva0mlGhJvVU?cWnHqtSvf^kJETFtii*-Z=3LGxmu&0Th%sv1i6&CU#UwJ-hI8myVX zksZQog+|^Kn4PVG*S;^g@#JT2Z27NW3*YMB=?J4v9=>fTRb%8Kmk15B^q!RhHQXy@ z8upU)U2)*$2zy$qHz3XeRknWs1_t)1)NbRALT`7Dw>hv4$@K=kYQ^hR3%jq*+5wK5GCjp*(MYa~CWvB~J)M#@MRT)uF1&dMmAD~-stHKyjA6-{UKi!OQ`7y8%fy-6n>yeHb`WsNOt3V()FlD(_BdRIK>h*zypmPPNm1SuQ@T0>g8#%VYD! zOv~VjIK&pSl(r=XtnUu%#|OKlLT_q#-vQLlu%Q9iRJ_Xpbqj#E0;-Y|&KqRD^aK{M z$#ImAnI1=PZz(`BQ2snINHNVt#B5~EGf6NmjTSFqB9&1|(LKdEI}7}zC@odWQ!1AD z5sofO`_myz6J3c|I&Di4P3|ZyqpR*T8?tM6!A&ddYJ-W_!OZKa9iIUt>R_QPoM9`X zG*0lz)23_QV&{z3Z!d)iht+3Ue0|jzp53e>Wo5s7z5Npw7_WNMi@|h0G>`5L{@R+A znCc`Ryf;iNxxUaDjGf-Gli0DV={6zbJCNKjuR+f`j@{$sOQM_2avI1&8VTrkC`NaHW94wC6|5&)**D|3$T5 zWkJ&WEx(9CS`~U$IV{-{9^+pgEYPV;8Vo>5Q=+cd+}h|gUyk1$92Rvr61T96O?cHH zyPKmzffr1tMXxE(JQe(OEm-1S3Vxx`96J!NE6`=+9m*=fgzR2tLd#q>qn#`K&-Yc% zvuZpM`I}b#=?9(WDG?pb2yhqVIe>IB{&8EHqJmeg+rfY@7MxD09=7VEC^+8k>$!8^M26@`%@*?dD zQ>gF*LBeG~V$62Os{zt{+2LfhEvtmotCw*Ptwsjv`Yye%i7i^@UyZ+PR>Igb607caOA|vF+Nrk=fKYsCeh)hob zvAb~O+w^9v>B@2ZKP*7RpY3E=gd;#FDtyT|ALqeQVInnOMy1|_lT7;~VQON$-lPb; zMCN~VAb}ab=FQ+B&u{D#Q|M@VyR&H8&4P*hfHmSvc!@a%YGe)4dM_1**&MOiD5LK@)aA!rZ5Lw`%`;jV8J_>ZoJ`u1(=pznGHde3mPz>& z;QM4>e!>Kv71L2_A4PnW=$H7?Dn3|`wv(Ds%Qz2jVSSc}2r~t5C+lz;|8~@mF(x)<= zx$DU%jJho+N;+XJNn-s%euj$KUZP>Y<*gVWzy~CP!Rx;LFM8V@wuN}i#ujxcf_~TM4ux0 z8>S`c;=;*m9*(QLr{0K<16oK&Tpkb(t%P||vk5V!YujZkZ@pFXB$^L4!NNgU7V8jY zuo}xzmn}4;Fs#dNu}Qa)ekO3WBQHbr$e$!bBT329w2cQqcEBKfi~njK6YyW%93mG2m33*+9C%e4i=>H)nv z*QZlOYeCTT?ca;;?*I70-Laa^d|ar$+&;6$U?MW)Hx;m!k|6k#sd)oi?0iM9vbz^m ztECbdapsrSg{#v`j!I7~Fbj7gTe4CvILRe^#ZD>JVinOi;(P|R|j;47;5w)le;jnN=l{021;t=J}rp3$cav1n|NnUCiMWAoVpAHPm zXoRgYrQ4ouK^@a|GD?9$mD_CFOMZqE5zSOdGwt%ouQWEx~iJp_LbJh!i60^v6 zNF8!1+%~s(+TKGEXIfscZ8IotW+B%(Hi5gY+|RR>{5iI#v<8y*3>XprPdKz#O@tTe zaAC0-EAwhRF;`Q%$8ayoY6{DFst*-mFKE;+rVl$l+^lL9m>JG`o{+~RSd~E4dzm&Y zX8)THaamkAcb*mygtVOu_Wb#&W$f}9LQ1N2{hQ*>IEiZKgOIZ+=!)V6*IxxnHYPSV zVT~RbdVwJuv{A;fILR>)%q19ZcvVI^Ef=@TQ`zPQwas5S5pcEviC_*lH?q)cSgCV;sTBFx|qB&w|nKZVW zpEA`xAmdTlx#mJw`qMF!%42za7nUO4)B>Zxd4IoN)&8&^Sjmtqd323)Bi-onP=)uv z_v(#X-?yfs$PyD;fKzOD-`vk)OBFU?Z7MIwA{`1|ci@dHWInGlLb?f%xF`|yds9cx zuD($Zv9X&ozR!mnz%MRB?dsU#Q+C4mkEp?SzC>)Aj_bxupqJ~Rsx0qvbGs_zC@;1d z(w@}kjj3fa-Q&LR%m2Xuou@c--uBVAy%Hxtc}mRj+Rwp%rI-7&Xt3kYV2BymToO@1 zX=qs7x(M&=ddAQtBx0p{xc?Ha&&Ng{G4I2#;N7A0i=yy3zt*_#Pvc>HEc1x;yoW{6q!~~5q?8__K$V>Qbk}6ch%0pnjF2m1;P@B3WGMkPjs3UPcr zd|aOH^^0`q@;6i|*ST4i3d^l|1SV)ZOeVdQc#oYsdKg(AsU^7lzWB5i8PO@xi)!oh z?e$$$a^N53Z_3%CqxJEr`p-%jf2<@=2Y1s+4ooA#z6%Gg&tkrDX-Kql2KogO9K1F)@i>_1+bB%YreT zAspDC?Mx-3bb2Rf*aq$*r%i)h^0Y5`@9wOP4lokgMp{i_wB*3(|3x_BP|F$6)9u*0ZdUbp5g>>jsM3BN{?8ThfH}%Z#0qp8iG(Qo|E>1ghz{klJ^o@oi+ zM0y#`#TB7e+j9a+8hy>;7R0KPOhaIt_^__KBC=|Xg_uPF`ALiicNDMk3JF|1_LXvd z@nuAdj9>m(s^;pSnNW$S9A^(9LiJxN)0=NgFtj?VBm`98MVr58 zJclrs8^}TSXUfz#jZB;+e)Gge`^qk?7czD_<=gzC*q~_<+tvi-U54X_tQ}Qv;y3uY z1btR3?5>jmiCyMH_U8`laQ*$<=bm2eQsA!ui_INiQtyZ`$z6-QjMb#Pa+H!;A7yzUd5q zZ!lo2IFI%&4)FD8DFC>)jvx=8ABdIA1D}Iyo4oS_`gH=F-X`vK{yi>t6Ir#>F)*kU z5H(nZO~)Q~LYWc^A2+2+J`MQzxv#DMhgh7&^kR86h|0vGwqUcc;q;3alInx=kry6m zSMYYz>40sUy0)foQz&Pp!PqA~G%VF_KKOvGa&e``e;g1KE?L-OXeda%SP&by3h zXbLWPHf@MjFQuU)OZI*YpK*50W@no&U6*I^AJP0T<2lIdiNAbBt#sagPvR9|xIk#( zoaJs)Jy)6|ex904V9$H|gxlJCdr0AGn^tMlF688|fjtjok z<(lY8*Hkq{h=n;yK1 z23epJLtxj=yA`APPN@o^PybtZAU!7@zd-5eI~4wi@sR;#K$lS|j}z3P+q3h!zZkF# zLIxPoK4O|FoSO-6^-IMzol%Ka@0fpAd1LPDqww|s*(g4s`|98!?yr(*Z8xsMzfxn= zsod1|^mu++Krs&^^pR)sNhGgnl_$TWzGi+)ZjCIKTs`TZXMfNuL0GB#j6?mSKt_ZB%J^|Msn+WT|)~#W|-?how|uIawBN?y_66 zrkq9YAQIDZ_Ipuhoeqg)r#ZkGftq4x^K7dwPN%nxmlcxE=O{@*!h;#wn@ zN^Yr>VvuKXP+Yz5MKw(P6ofpUGW;^ulrLYj6nGCusGe4Q#98StPNx-7vwdE~JRN4} z-Z1(`H!iKBO@xVUU(Zg0UY&8gaV1GsoATYS0!mPk%^-e~Teb(GCW+DTmY&s-l2?WX zlm`CK3Gh|cYKYTaKBKSpsb`6?E;eU3o-em-m~`>|$y^&i3KAYh%-mC5*`5ksB`M!x z@7(|`>PVK(+d}v6iVx9UTXG+yxUHVZh^+bvevq+{y;FVOlFfXzpKdh>3hk>q7bXO!k|R zQiGxM^jndlF#GGsiULYe76KWn(**s<*K`oU8YllGw}06)9AxmA2sfo&H~#Tm<7K6D zH3@^Nr7)0p@g6^Y+f%N@y@AC>i$Xg`vf@9#%NF>qWM; zd~N!$Jk2)pTYz(N2v?!AdtCU0L!P>GM%YZ!~$7Z z!zLW()6=WI7P(af2baLsf%KOTq)f6WUd9`$8L}M-_}-H1GsUJ1V__L8lDWk(@ z5C8UZ$SI4XWBX+57~}PBSE;O^M}X!mAhtkqXe=ZqRnO9LE$PMwh2G=Z+U9ReC#w#N?3#&q>-QW9?7|e14 zWm4jbKZ~-;Nf}-d-=t`h=^Ynur09(m(%N}AKr4^SJ__ynErGp8m!=e~evZ7!Z9NK< zNRB^U{|*W9^XiEy&tlY^F81OWMnz}46M~Hpz@rAUtg#>$mDU3vRub5qfr5O!aTqY7 zBdDN;@$E=tqO`bak()r9RRjE@u`^SMP#=(HHahSFLR)Sw)>kGfg>*=%U>Zu&01(~xeLTmdCX%_}C^kQyPJwQTnMy`KqrshBwxieP-4jx z3fXpKxhB-P-*y?jt4rRQG3Q{6uuqI1)SD z+o$VqE*6>>dghMDc`_gAMVFg1dN3|~uQ+o}Lr2xpoPu5^4h+FZY`Z!?q4lVw)APz= zIXzcAMz5aR8b6>hOgr=M?C76+xk>Mjd_8@C$ZN*2Awz|h%dD|L->#GKE1#> zh^fSPe0iGOba1o21b!AKOD z_A0|Q-C{a5XO_mZRrAirMu{u0k|~qHSo1(dQa9a8KTItMjVhfqSU|n z-QBNtafz>1qw9&tV(m>(*WT-@u7e0@C{sEpcl7Er23PD|;y}1Srmt0FBQc_n9WJ3> zzo=ckeG^F&^mOf5=Up=W`naXhj{-^Ryz*V%luuXi^NSt6o+pt05ZtDUEYJu#vO{j^ zdnKppIW}9=HfFy|BQo3_?W^oB=;112PR?k5QEfgG`7=gs^-`vR?m~H*BZUArR76W2 zl1PyX-mNo@kz>o^&!Vg2 zpa__ham~k(FdkevEq2@CGsGxw^N`F{m9NkUCxqEeIDD4)hK7H?81bMpz8KR9VB4h}tT(uh7BuXy2*6|?bOGG4VUzarrNq;ct) z`NO2QK*+LqMKdD}B4ukd#3(Qvg^E%~w{I;F5!k;lq!v9rVzWKa5K`mFY2VI5?71oT zKUuWJhU|W@hf_jx@iXE|ob%cjIXQw%>dQQ1oMC-zMNmy^lB4#$fB^PBuPpNc6xY;D z+sGTvHEo!Q(q|_ox;xy9wl`+pjWU+PodBO+DyKMbINqf3x$5w8c!whkL6zJ5rM{Lh z%KRFtEHV_Oq{6q)hfgerT9)+93?;6O(s$yWrzh>JH8+8$w_ui4v4f zIqs`EQ13?aX+<}2=+3)(@`B?Iwc2fdP+TW)pNsd*?&Sz9swhPS&o9hIWN|~a+E?oo zjQEKtQfD0J>0G&3f)F2T0VX?6O?46^a41HyE_Kg6S0E=(m*V+7GVl!&i>v z5zQe`CeClhT_n>8wM#4LUCQ(bcY#DiWJ|)Hx#6#;F2A@q-AyLf3L{2cXb1{QzmWfE zpw=1A3L4{dzL!%R5W{-;Nr!*i7*x2*n-b?$qwS`g$fydM^X_@%*iIWaY;WE-()FP%rz&DFWl6zW`Q&4Bb-@F zf98lD48QQC8EE5%S=)@L1@8y(2qq~gWM*x5=$_H%0XNx6CH_fft&oFl3%e4b{ENdNj30#Uc8g?=X( zO_u4!o@8gTOrW5HG8n00%!8`!(iqep z-F#ZTPeX{xycbK$8@mbDxH8PIc<2#+bkLHI!D^?vC7{_gZsR)S&G!8#4?@M) zDjnOJw`z_%pnTgGA#>Ev98VK8gH%f6W7~-GicjgxeV&9K`j~e90ZZkv_7H` zPlrBhwi^@lkyy8xrsB+fFn!6Mfby?qkL%cg8AL!;Tr@7%$xk11WYw(c$1ulQB}vFn z`9!#Il+L$BABG|dk_n$5eew5A-GG9Mg2_lPr91G#xzk&MBWrTB{KTYxFL_$JXP{3z zhq&@$?WJH)oy}&J-!UzL?}zgg6JOaa@6R@}wo9n{ImgJp)FfAsr{sAXTpx7dhDtBt zyG;lkwQTGkAWSsds(6c~T(xvL9 zW}+R6MKJUzZI&fV5dFgGiWqtj87BB<>Je7r#SIPQO0u}ML#K0N06Kr{a-EyL#nLk; zV`5ny&RUyRbv(W){rm39Ga?i9C8gtO$5{vAa8f+XocH8JoG*=dH)Oo3XcH}R0E+|c zy;Q8xvJKQ86@PSJ_4;wFF<+n(I|ZyomZ8HBM|^P<)*WY{`I%PkIXlmI%txY_UZbp3 zaN%qVe_Stj@)e@@(02L=GAGwG;cS^;@yuwPBkYK;U(J`93C#Z0V(r;WMdLM5w6ciw zcrdC4UEg6sYmp`27w{4;Mr)w@WdXtN#<#d8 z)7@XCH5i$6=zO6GC0#5(-TN7}$F4i#eX<(Ty1kxW`f_pTEoS58Q|jn%L%-fBvD-{b zB5<9TFksxTH-;34;IrTtr@GZEG0jWgeMYwVjphz}dmdd`-N6TnO%_~*o0#{J5XHb( z`YZ=&r)4SeR1In%Th_HJb3H;^L&Y`yqIVo!jx|Tm**^Tz{P8Y`R zQS^{}xif$^Uq}a5K5-?>#a`^(`2Nt<5CQa%o~KaPM?8;d6S$AOz?7RHh;&xhxtSLH zcGx1^Tz^eGpf?{$aS&k!Ld%L(9@^Jk4~fBPeOoehy>@NoSsj8SJIq z&{#stxbZd~M`M~D*+Ix!>TA?7v+6|hqH@;X1it+=U1Amo#kkZ;hRiu97n}u<&d-}C=G?xD)t*qbE*f+(3O!&TFvc#Y_^_0nh6~V|&C+M? zZygTuat3m3rJO~m5t@h#&2)*C@3aDe_b|G_%`5Jdt#0I(708lnP(vn_+RbWvazyT-inhV!R&XI!E%#G z%F9@;HF%@?vYmuFreF~^BpoVFx{fK@N`QYkO_kJZ(~y#lnv|oGT?O+GVf@YI>D!G4dSGo|`;#<~#35O|z9c z5g9x=dB?R8q}KHos=asenq9{%%Z)o0zAY#It<4{iRcPJ?;YR$fc9BE~qD00g=u6H5 zw7VvALl{n1oUZLwr-{+#b8g40^{gk;f!9Gf#*t{}9P{@0YVltKFW)ivmXRY#?x2A~ zyLSsK2B-Ekb}K^o7}jCvcJa$&7#g%NK})f zni!4at&{zNz0f*(L}>)4ZFJeX{NR`rlE#m3u0>M5CwV{8`^ZfZD_;4 zRawu#@cka+z|M%X_cUOz-X)to-#L2Ax?FXumue!sq*B3UZrN@3I;M(>z|qnpD2Grlpy7smzi2@ZW3CHtNnx!&268TZXx8vClvyV zc$@lsh84uEUl=TJlfYpq8tkB2A~T-2L%V6iC|qT(?}=GF{V=6~(Wq9>_=Wh?u~Y@& zMhiqgg`$;+%-T58l2!3^qcne{>(go z!IK}D$z|r=oPEyT=bpXSUdyLIo8Gb!7r;eF(wew57E)I!juwW5qoKmjc=%%I42h2p z>b+#m9kGROuCksk{5jrC43C$n_-l$x%b=4`fmI@xKoy{8=%qpASO|GVR`yi8-C*LX zo4Czu%I9OYQdzY@iEk6z+opjcKS$;u6sPuDEF=Z-rfp6lSMhNkmRYZr8Zv^+6h(^d z#zdA6jBm_9i7yZk=h1NlqlSLfA5J}cB~U|r`fGh-@VC;7B0YmRN#u9@e7Vz=cv+Cx`d~4|@@SaCR_Z?J! zL0ik-TM9odLXGou@?(v_V5~;j#C-Co(nzT10Cve>h*%Y2A{68+Wzmo(26b2Jw8AU1 zF+{J;3;>rT^l-UmR-0jB78|y$px?WLnd4L?3`sBOY^OKTxT3j`>AwZfjT_2=^XY->0W*p{%LuE|`72OkD!=e^&UbC__$C^$PA zTxi`h8#n+mr|ravTe=I75SQbjqNeh(r&thVD7WX<218)AFY`acVAf_$ySlb6xmeTH zU=9rP{Ld~?KV?bWuWWEy^=)fwiIr7?>V@p+?T5NM5$Rc?CR0_+Hq zX<_EdpjD#`^^cNIpx>36hU?oFUia_A4r|cx;9*WC%2maR^6m$~vbM*YoM7b)pBe>e zh9@Fpe;<~@I_<@@xLR9Ocz%B)b^3mQUx4`kQh}!T&4?6|(tfdx<0RL> zDPh9P#<*+2Pj!Ho3Tiyj)cex=SHWuXNzXSu1PXJU^2%++@!hC01Dru?#K9dF2*kvGS7O-VUpM0x<4a+S zxLE*6zY3QMB?!v@$WAi&JE~aJ=e1kvBtI+Se~4jVZPMFlurn(>JACU-^6wJTLPx$; zULdQKF?lukzboBGSai)%o*ar&2I{{`s( z{R9~BF+4+U(H9jEDrP+MsZeHJj={t_5fbfcPK244f0ky=A>zLIDa^TgsdXD|mNfk5 z=NDGiMpJXMa>XWsow2A*m+3$ob@^6CXT{|2ogiRCCF_4R1%!PXaX+{+4LDi$%SfuE zre`(T57d%5OW;Ux#0k|O^s(nLI$6h`hEpBx`F>Ef-W_#R$qNML>+n7(&W1>%C{Xn` z{13p#M;6_M$%g(Mjl(KDJKNw@V6|x6G6fN8S}H1eV0GEc4}r9GarR4SRVDXFtAx~h zK~f*~XA3P3E-UANvqd|^?zGAB95IFz|3-}XT|uV6JgQgse{O#4z%d%U(hX+-fauM= zmf)#%F^=AgLmxtEFkATBcS#DQ;7coCZOs?73kJBj(w{XxoZDzt3wYzVRy1<_d_}q` ziAHVHCoiY*GPw|^3S8Qd$qsAsd27Iw$faRs0cGM?#Hj%)y7pfd4+>xmMD$F zJ?=0uI;zap5^4DUa|)CDBy$zIim8)vB`#WUPuQ~$c5{W>8Q3)MB1&Z~^7wtf{4AaH zYid}i_K|*1TDtpO$;r8(G@?c=BPYlDHd6Ebq>9dq|BU$MDY^v(wYOS@^x8ooPn&^& zi1szD?0=;!il%&e3mx~Oms>D3lL@SNW;A_K4Rt9i&$g0YF;3SEfj`#ZY)YX;$^T9IehN6QhmIa$=Est6ts|nf&xQ(>=CTA z8fUQ$yBzafu4?9y2#zZL0~bZo+~@x@TX$#HPh%4-32Gu4!mY(;EylaLqH7CLhIfgx zbnxdb2``d!u$gKnuRP)$%>c_^WY;FU28Me#C8Yh!%#3aQYQ*q+1OiCSUsI&w&EPs*f3X-*S%pvbc58mecV+9=*;Gx1~TOD3Hh}m1G_!!!07)2 z7b7h+;o><~V;u&<5K$gxunJ~aAB>OvMfFl= zqk?_3n9GWVWf8NFu}_RefkU1hWuR1bzqNAj28|^}p0U9e0F~`U^p4PK9asWXQY}gh zjGC8|xD43#f+-Dni6dMfZ+fTy=YEG1Xy|-bF>kqoBOpKsW^&LAX=ZgyjWNBF!wV?$ z*>bgZX(FEg5Lz7Cm~&VB41uK1U`p)l*$s>$I%vN^oa@*3 zyD2PNKCtWthi5hr5a^}x2&tMu##ILkAeKCBw z9kDe&{jLr_4t5>U$?mdK5Op^LBRh7$fg zUm7D`+<-U4n1^hq;nSOfiua887d9=V-#xi8zU>TkJt#|qR`6fuPT9D%;=klgV_$Hy zPxD>$>-uNnX5&nf+Al3E2Vvh;6tnwX^hNe% zs|x$ioHc>Ch4vmw-e7rBM^pLuQ~^csannD$@rDHAq|{SaaE#aKBu}AV;F*)By>}GY(Cn zg(1$ESQ|qT?w=$qNqO(TIaP&bz9Q9kAxyyrk+zBtwh+7-U5fDizxiRg4R{k ziGIh>A0i`mzW|c={1H@7wAO*9k8V^Xv3Am4<_SP_y}R!VW1%k{*R;0@J8uTg^1PiB zNC`ds7x;&Y&EW$3Xd^jt z0UMDwqeHVy7b#Hv*oEQ)sFhBF(7mU@mda|~-)3+F4!*NZDbbS;qidjH>!ufE7^3&i zi+pRmt;QyaZsKM4Y4&!;eNWgVdPoXF;a><^e@mv3z?X;Q9_mxJvFkYSiT~@3@Uv#+ z8ytuad*Yn&Lg^-_9SnDO!K^9wFevUH}d9HXx8Qu1*$i@P@bXvkbLO333g_< z(MsB@{mmYf4zX`{bH2)^n|Q=zuFv$zeZr8CqEY^Px?`Q-w6V9cLEHc8&q#dllzW>0 zAR!Tb`Hq0<{g(^)FNlK?G<=SvR=PMehHtc!qw?uTUn20*b`gcv5+FRObdyh%dIPYt8lNx_2bXU z??1Ox;51`h)BrZ zeiez#<5M2qnqK=jSAPf(?&A}&H&DxAY^_Z2f9tqx_to@1*(u7PGXU|llqG-!mp@p*{|YmVlhr6qH;VH% zZXnpjGN;|uvn_g+$P>Cu1j%U=a=6YJqL(0;AbvbdBC@TLdYjG`4dG~2-5;5rJYXGX zNt<#b^Etar`<&G>!V(VRNuf&_Hw% z(q<{8^GgEMHC}mK%WTKSQ_fewuQG?eRpZ2yWe6uGEA;DpGb+s8wF;BRXr=w-G+fg9 zo1cej(m+8q{RNTfR<-|i4S$;A-l~Y2K_yTKgtKw+CN#2Goe{cP;AIg1>)dhz$Su&P z+9CE>+)MC6EW1o*>f&&jr!FgvFoKHpRWDXdEC6>X^3aq`{frfLloSU1Ugf7)xIr@7f5ia5?``myzS+;e` zx@lgSuE(-Yr3xE+uhlpW0$~nQW1`855*~2o&{T(tYpi9A0UbG$juYD5KBfPh#^}b1 z$rO)@ii&kL^|Ek>xehq78D+O$&PVi01YtyQ?+?bR8bu}ES{ZUP_D%0rACI}e-gZs2 zNE9!L|DFYmrK+Zx9_2-J9u#=0a7V6(IRPyiw^v9DG<0V%qaqLmj8ED+oP+%0gbfe_ zbNtBSV!L>w)xt`J^xJIn?WsfvtaYd*Ok8E-Q0)!DBp~)JPTSTG^FBVZGEA*Ft9<|7 z>xWQs-$((VQ@o<`CnG-pXvuw-bBv5}iTA1+muE>sfW>>k^uDXtk z_~mjeI$}&oX8lK*;QJ@S zO>!Cay1?2dtt9WLJMHzX#>9TbINk*lu z(11a9&hpJ0{^RnwWa*I5D-y@aOjTkcMk0<+mc~tu?4Yy3IU5A?;ICglnBRF>nAS)a zR`@C>7v_SQF4L4HbFx00$HDrc!{Et}a!EJL)dFs+^shN|xlm+6(HSRV>lT3(jaDJz zmv&F`WO9;xzR=&rvsr1naE-MHTuT|ekUVK%mqtzt$MFaGJSBW zWVK|B)%_vS)0+Lc$8BJf~MmHsH zXJuAw>?8~hI1&VCT9WJl8*`6I;#Hl05#Jg6x^tDKN7=#bSUcL(WWc?bFW;mMeBv3s z4@2^Nr);1m86A!cYAg>J?M`rx6OWrz`iVTUi5aEO%=%i+ur1kP3ptJk8ayap!}V?l z+{K~&K|RgVq_#KV)6XuC={&>t<@nrTMJB6_OHtCGk-Ffqot^si^Za;-LMPE>8wi1O}zE&Ql|rfz3EJ8ZML zvHnrf&&u(qHoc;@R{)Y4{OEtfJodo36Q0A|lr-TBC?n0lsS_#8#2EU5&LMX}Pc!)@>uP_3ih8iMQWkJL zxH0L%JQFdUvy=_tzkmL|@!-Dr7~$ z&c`G2Cq9=3o_2_SkXxHQr|7vZuO8EMsqT_}g+9IMFXw_mfw2&8;^%GwBr(i#P(0C< zjoQ@BX4e&$y5<}cq#{hrq+i9t4Qtf}Q>Wi3L0LAON$c@=(4FYS4?_A3*2!HuBzWm> z%{3Ahgv@jQOb=RVoFs1-QP*$?v2&0rDd~y36%Tqwq|gd?O5&@lFBjNXQOjhd$z2_` zeEa2Y-AGciv~XJliary#s32hDN=Lk|)(I4-Gix$!(Xkm6UVYn+V&ot6R#0=v{+vZf zMC#g+2DHG$B(CRnX(2*SI?Z*Say~%3Vmrr&FBrGTqF=$ZNizvKxxapJ@w+NK-;A%NmZ74{@sY$EVPb6H@V8R1I>J7qgtb+ za^fPk;yy5D8J_e-waIWMh7Jr2mm~545@Jj#vg<+j$|v4msoU^E{mM&P)A_~lq~!2r z9#n;^2rxfTX(@=G)#)?h?P0@-#;#?em6yiSQ;c3?bDq_ibAwTrj8XWHf7StxzXzx= znvqPpTUt~8l&sJvO8c@g62VHNMJGK{uTbcXmamB#GEhvP(>Zq!7nd?{!QUye$>iV@ z;^H{GQ>$nxs{F2%QOsVuV)SkHU`eHif-*790Yg`vi{TtU6KhpjchZgWRM!wn2h^X( zvTjL2U;HXzDIGa_#N3E1J*_~KlU73WKoCl{& z!&b`7Kz=Ul!~U=<=UU`cm@zkxUc}fB4RkY*S>1!1xlG4aRL{2Z0aY$@T$bHk&D_ipZ9 zSzZcSg?kvL9C97DK>3ZXFiPPgR;6_HZ$8}p(_dppiC7|BdJPoDH2K8@7tM>J=5&?>CKm2XPU(_(Wr^V^ z1a0o1@F6M2iqCm7twa|Vn|-q`io9FqN>dSDl4pV3RhcggWAV+x+z#)vCZF>+DEh?b zv75w|t4 zWJSpl0x*vZ2!**ud?Ue@)u!Fst&l_nXa%e%7mtbNYKDq9A4j9LSdb3ry+_MiDbPta zEwMkt3c(NG^uPlt%b#iUx#L&r=bcIXC{Ex2P|FJ`&~UY+52Fc9G)L`?kT5~wFm@#n z9H_cFioTU(C&6zSxOWILe&Lx9WIDTlPT;2_cMdRr@$EY6_5#;);`U;^?2la}Yangfn1S znhJMg8z1;CYg#o^D{Dp0oi$xd?=mXC_~H0a+`PS@Pj_UZ82C}nQ!nziyu<1G3!%oA znys-@-2L}y<=-QwCL$w-D}$_3hGp5sQWXfi$!s^T(hM4IxR&e?0(+O5XevH{`74h( z)$>=52XZS|MBplN8){NOWqI^`F`1PA<(JH*S-Y-IVSY9~?{RiK)?eWQdsPkd`>90d0u3qP{TsCK zkm5b@?S!0bW+g>BR;!n3brpP7acZ;L{%%;X01@xPlx+4ql{a-qzn6WEM~e?=mKS>r zQ_v6{mvf`(IXb%rQG4kkZhn!Y%X`BwlbmhOG2kK+ova_cozx4j`p$i8k>mJ+mX9n+ zA6$FgGxMv~jkryeI=wzb?{H*~HJ$WPipnR)pg_^Vx!AeWY@8mgwEXu`(UEo<+=X-d zq)s~n(5*kM>;fE$CiXM+gNcF0v26`rrUTr$!P9U=5(RARy@3zJ_qekAB#)NCUN=IqGyalAH+Ecp18AYK^5cXfkQe zVAoWojf;8BjNNxY$7JO2XG&@)3#-1anHaB?QXl;5P#0BCqVLy{gde&hoR) z5QW?uSd8x(oqM}3hO;#8tYy|-`YH{)f02(7pY(=l%QpEa{r?;nLj%} zumSE%95>S+&wLiGFn;?&%FGl*mm8S(BXQL}twXog@3^IQ)DvvwPM*rlAmCpLv{xzP$ zPE3(u-F#gCF!jzb{99E6d(#&~Z}$D`p19$pp68a_vc)}6d#kToqbvnwOf1zZ`G&lG zxx;^2&~;*GQgcd2gw>aJno^|}O2iZVk?d(*bFFkMO1w*UG)Blh%Sjp+* zG&8Z3)OH`u)hydQ8oDQ6nwCAbQ94A>I#?Vezqht>dyo(QPMzErk4Np4zETJeN%dr5 zdulc7G^cxMkis_-Z7sdA_s7UU!kL@?$7Ore+uofWE_;7C$$VREBEFXbqF?w&m|j#E zx9z7ZY*q(qvkG-*8cP;n>>=mcPfh12zy7H%vFWIWcLG3@MNRv-y-lmUc6Eo?kH#iG zheJhYt#-JZ`7q_C&WKKB&{dCECE8Kq>$tVRt;8O^BU1ge_#6G><}}(7)PTcSY(ej8 z>pnSWF)h3oXP=YF*4gHX=~&lxLqFNPCer09dGEGAG|jZhvfHQgCVTp29^rTdkRy{c8A&5<(K zZlVS2nSnFaXJ4qk!rDlT9-7EXbr^`eZ$yLAv4qD1*eX?nUIv+NRvz@Bb6erj)AD4I zF|8F?<0a&vW*3yu8|4j7p$!cuDY?hAJBs-+pJ&rgM~*wNd;3zi{gH#7eO!YMc_(`` zuFKNInPzc~q|Wh_VrEngOE9Uape#a=&xj2yt5{dFIQ1H1WDl2VSxC;zkEe9HVwqIgAm$oPt0 zRot5ebf2!zCG4(&Jy|Z!q(|+P7vScg7XZ>Itd`_-f`!N_o!N0PK z5s*R5KSf6;mrvdM$)K~gl39zM@K?2Pn^e=4p#1s4fG4t0{O!KEgb5LwLxHHXdukK@ zc8V-fzAASrGq`;hM-Ucmi(#PR1lvo zjW2+I$x->ezhy&tej~22ReafS70*RZqM+r=6faFXFZ@7{E!mo_wP=LJmb~vKHmD$I z%cfG9VVP2E*c9oBZp3^bG-Lam9y^nWtv_ndbH*v}7r>rSFl5_Y>eKgot#W+^1t;%* zv>CoVzI91sGkP0=64i405>5r@i^xO9w}Qn(hA!Xkr}^LV=G7Vx99`blKa>W$gDRsD zQWX|tF`6S%B1g<{$^!cZ;lYWZP1>#L$w>-Rl)w)^YdpzG52GE-$QRm+6f12P4JFY^ zD{D(|i*z<_t>v`7PhxW#PD#ZF#o>(Ia(bQJ0xEM$4$5b01j54;5HnR{Q*WTUEbr?~ z^o?342*Ttwm08ZHj%S%jKx?k@mZ*r}Pu%B`N$W0C2Y%7EnFCG|=OAY1w#V+Dz(hWg z#sd5!Y9MF-$=APU3 z_~(u*q#AM>-4$xL%>7q*ih*} z41-cZ5aF;H=?P`}tNmBd`p@N#_r)%EC^j-oUxzqwFWJbghImvdNz(m8rLz)cpSSqFM2+$X<}px@kCL1RG^ zf?ekzP@kr_Yzy|ERCRVet>4cBJUicRm!(wU6rc-jUfRk|3bkb2dU|^$-vijo=)Pd~ z>VMkrK@&Q-7+4)Y$c=^4Eq={rMpHE7U2;EuaLjBq;MR7=Hi!p=WhMj{`9PlskaS;+ zE-!N8HW{{8e=hUPCLgGwc=b|(yjb%*^!hF$Q=o!I?L8U4%iWjVX5)|O)1I=+HVf3f zmO!Fih&3}8ga!MV&KI7n>F2pS?+4_Msn)(#DNJ(-$; zzBO{;A!7OSNdpSK`K6E#6+Z!nZGQ%V4TtN)yM(;{<~1v4^TJsI*mW-Fvu@PK+ zAu>P)z&8m$&FOnmE-b;QXdxlj12Sr8G`M7Lz5&I=s)Wm@5cG!zBkNYN0=Ts`v0#{< zHWE^rbZR0JKK$D*e^t+Imrsm#suMTXIdBIhZ8*-=iXbKJTvxDebnUaJRe9=5prvuH z#Q+21q%xSn%{&GwwrN4Y!QhbSch0Jh&tNCgSCsCp_N||pH4^V1=;BNpz3mgJBJ@}0 zqk3{z=ou{rmVO1wOR`!F-gZ~d8rYD_VvNk%a+UwqHlM7v5Qv+zBA8Gg7+46|GcVU9 zqIW#X;{`PkD_xJSEm-Luqd*T^IJCcv>C8Acru!c#B{tDgS+cjknL2IAA%`oczvotG z{w!D2SR*3BQtEk^7@X{RiR-A^z?ZvKp-$RlO1HUnI^|kIGF7WGC)+=b!S}q5BrzmJ zCS)->!BMvb@Il?7*BpAV%o_bV2J76u*2u}LLDy`wWJqe@NMJ55H;%H^dZ1jld{A(k zyUi(b3Wc<7_IS4K%+cH|F{`D%nyZeTU0vAaj$Q#lR9E7G-PL%Q{r>mgl$_idyv~w0 zyG^h%<5$T6ytPneVEx5Q(qE}s3@P|F3a$?2S<-dy2HHw)5?{E-?$uIFDj$dD=wH7% zM~-B6ajh~S9YYJ34OYrYto2!)XulD_zR)3!kJyr{-_56UQUVs!R>)e6nmI@zP{WemA_g zO%^xl=}_)$(=Zfd>!60@NI1>a!NIS=7|&FL3?+U$SBAaTdQ`xafS`_xiHiMEKev*H zqrcCh@8@Gr7BgER4BtJgu7w0MK`t*vH^zUPS)R*N>ddD3+BMwWGxJ!o3Ag(U*pGiQ z1S4A>Hf-nEj8*A-=<@7mvjHfR=u@`F0_74N5>}1a06;Ijk+W2-nnoawk1DrU^W>^N#wOI?1iQ&um%*^dptgN zj+>8+EA2OYsB;PTBa2|!-f8sXF0;p%L1kM}wNaYTzv~+}iFY*9rQ{ilqF&<&EW}9c za#fljHM4Zei=VeGFqtbPn9go<}wNPkJvg;OmiB>=1&mJs>_6cRjGixojxZFH0apLl#L&=-xrHajJ?Nv4o;ZdYm(}Zj?JT7@VkZ?`OO;6K+FBEBEP} z$)Uc~s9p4V*8TK&Ln6nXU@d3Gd*wR4azb5(E+8H%Wy=rf#Q>L5FK~o8F-rWgHV*(OqCZ`c(3eZam>ookpQiw1g|KUZ^x`vYQ>`~#V79+UMX zFp2&H##rHy`e4LP76pQ~ZtulN2X!1Wh0!DiO_s_^k|%ziRhG6Sy?uEG*8hDaaI5V?!rg|1 zt3<-=PQ9azIT9I-X|A($v_^O96{qO+)oSg&g%dm~Ax{?3U~s{MUZi6-F4D*& zB^R^}#bq)tVQxH7`vhD@J=@dDUhui?hnsqz4$)PP*YS`=lrL=!Xob69CCPx)4{28~ zxDw`U6lv@oI?`u9f!FFh^CT&j{u>L#r@^ER;J z*)G2_LXRF&jL8D(SLpZGj0D%rg^5X$3{$$(RtpHYy$MNB)5BlUe>-^ff4P9Xn}v{4 zrTD}bN8?Ve>`w7gDqP&0f?S`;h~86?SQ^(zlcDOy;_bJ_sYUr-IQ-!lU05h)RuD?r zVMZ{6jjDLb%Kd?w3@#LdDnEiV6~ z>A(z*jqb&|0;|Wfa;1t!u2YV`ymMOU94%&MWU@U}xn-Gnoh?4AumS;PH*_a<*}u!$J7zv~!mb^p!VW*0-Kcm_ru? zFN_hp^jUVE4K&mnL4*&;*ForxOat@X_Q7r^(gjqZ6*Nqec22w4Ckii$UJkwV(9&?x zVoY*Q2fX4dX5l$JYT|)Al_x5cmIB@85`EN$(roMIMA|!99Nweeu`CqK__Ui#N~vJX zQ3@NRXY*G|>(MRpkRRE+CI&~~w61Jzy29_O!sWU+r&@%siGlsSN?Xu zr=StiMqmGDZc5bV8mb{!y}MyWtSUvrJjb`%(XyzI(*rs|5(qvH5HmQ!qL(Lm&ZfW?ViQpiN1>tPDC>nB9|d38Wul%t5J8ThR`pJeHg_<8c>4kU$rS)h*_& zQN%9ftysm2qOX0=^|ZJ0nf)2$UNJA->csbzhlIspI^46Hf~H}U;WqnYvc2djltwDK zcXz=iu3IyjbInmd<=zKdovF||4oqT65f_?!&{`P3*a&l?L(6O@!A{Gk7JIw*b4x~S zzo?bUsX`l|me<%-iA8qoZ91#FOk2Nn;;Sfd6hQJd6ID9p72SVqG7nlicHsS9
;4%FzQYmg1IK0+*DnWwT(_+R$C3${wVd2U?*S( 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 LPNew#$1nc}it}wa diff --git a/.github/pr-assets/installed-version/mobile-saved.png b/.github/pr-assets/installed-version/mobile-saved.png deleted file mode 100644 index bb8468304d0e59faf436519d2c756ffff20937b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 129966 zcmdqJRa9JEuq{kN5-dP)hu{vu9fG^N2X}XABv^2FcNz^2jRg3;iFyd6ttm~IQY&u`+N}oX#_~*WKI`}E7*D|{KcJJtIP$Q-{u^Q8rT-25UlRTe zo?j{6L5IulQvWR242=5#9saXxrvL6{K{l_8M1Q%~ z_xn@Ig&3JGwZ|vuRmU?gA8)}out{&>r-g-uQVUakr^hQ3iFJ>Kvxet%7o2h%>&4rU zeNO0iTNFOv=>FcH$QBp!xZqnH?n#Pk>9@yJ`?s!}yuixJ0(=!MOL+O235{cE5Q5d* z@-2?>_M%(Ze`~yeT3kTCPtg%P>)m~{Ec|cz15V0svrH)v!b$)6ge1KPP~xyfXxN3R!4N3 zE{rve&NfDReZr2%e8K5B%@?b^P@nTErt&ZjwQJ8@bef=rQ1n*Ne47fPg4`jr9aOK> zxj3i3y)NX^FZ{M28=KpkFzmd!wyc%a78UIsnz67VBWrIq5FtxqEBh@*N%;?ozM$_? zh)8F*%aId!^AtMUdq-EtkrU(T952aSLce6CHucTB+qK`l`gyZ8Uo87TPQB)_($dpk z!Dppa6ci=ZSd_!2&KZs_E_?caIzk?yGyaJZqEJqHd~9QG5m9afBOtw)EgjrAbcHn^ zj0HQHNW|inb0wyn(ve!-fipcLtwH04w(e2U(Fgi@2Mw}NfVu`KldMTF$_N2&wBgXv z!!(|^Dq`(yE47>1eD>MbAJuqe6yzD1Xp4__N+%rIT&}O*3_27XhHf*PN{UKYpe9%b zDr+XZ-p`s4pKH!h>|Pu^_4T5*U!8|l5}?6RwxI`hp+V>&B!NeNN z;p|^qV`OIb?@c)qVto6Dr|%KEu?*|HVY ztT-Jf%n!>=#O)i!Me1bWx6@HLsE9Wni$7iUX_TFTJiera>Yq!q2R-SfQSRJB+3tzB zXCXTN&-LC=jC!-3oy~G_*j@Kc2>MneyBPwu@IaRSc2>S37(mzQhg!6)j-Vh|{cIvT zJG)8-#*txq#K;IFq{upFXD-|Isp(1BESy}x_V@}m6p;J<3($)L>}zu*K8Ne?ULYV4 zcX~#~bXLEI(B<`wV#pn${T^orzd*t`$xOCrapT-chNR0vTLcD=t*^WtqYa+G%o3YD zKJL;)@7mhhSpU#eZ8->3)WA+p&&9;zG|?$~6)s(=y0pAFn#m@>O4c(mII=QWQBc6j z)wQ_`WIN%sm+wF`sd^9dUD3RVG~75$YxHK(+WJ_>&}kv(rR()Ec6~H7RAL^lEZF5j zzj>|c65E1WvZKNhMIT}bQQhd+oo72>dTz8n8(>^fr^B*|rNtQRy5E<@-rqkBy>|4_ z_a3xUrB^-tgA3LF?l(D%gJH)iwX}9cc;29 zzl(+MI=R#Jf3@o`H3SSo-BFE0jx0UL!Qq-;R>UR5(6Hd2+0@W^-bMl#uYO18?0erI z1`D~j8|jIEAv<&)SxrY3yt6%-!`Ckil>~stD?qecp}4q9_Z5ok2UWXA=r0ajgu_!f60jv-IRYVVe2=qD6Ywn93dHVtV?}d=7J82pD9iH2@XRrEY zL9jbDD;L+(N$SONT3kcu=cwnc6Gh~Mo0L?`ebrb2$6k!-o=l6kyIw9$IVl}*fRN`? zGM~NfAKr*_n||gEeJ5MFYp@Aw3@h$?OlbJQXIYO+N*G|9%}-B1s@d>=xpq-}gm~7U z942~fz<&l?oJp#uQ$`*%n+;8F=B<;Gwre&vk5%_d#1g*l)4vtgA={K%5c{|EZrwKG zT28^Mdocjyc`eXQd1xLEi3%2gB4 zDC}*X($qG+s7&tLe%qCXO3YKe!pF_VmYMkrpZ&-4qH-wLB1Iw*k2|X%DJ_QpIR(vc z2eFndFVi6?A|Ou@>L8c0{9(shpL0-jV?c^wm)FWw;uyK*%A(d-dcM%MySn=AGIDC8 z7iDS5@4LK#u?0ill>73Yg6)=vzV@GFnihj`2Hm0Lz8O-*7hR9T@-EnoToYqyyk5ga zSB(0)x|*qpnUbiZbN%V)=wny6SH}P2mC&Mp*n6DlYG!P2E&f<`70INglNX1HK>!UI zqv5I+#@jmll?+Uz@l2}?xizsyQp;^`U)Kt^B5oXV%(!oST~FT(0Q4M;K~HW$`v;Xr zTu`Xkc+093;SzH^T-IV#+R4a_xL@$arKRa<>th^V99*10&3PMf@VCPG1%F|On?P4l zUR}pFzk|AFk>*EJ(hk{&%WOKElov{*iUPcir7|)yxTb>dZ#vAzN7Zc>>hD_okIvd} z>RoOG-;ST6b(>wfRDef7NfPMYzK4>&7K12A14XXi<66rUd9`PqH^jPhWH)>#ZJ*z4 z#pCqRW$&0XC3V?&WxV6@F=Rc5n3&l9ouA+AuBM)f_gkT2YO>}bW2@iHJTP$}mPkOv z!Oyho7iVaZq2Jp{eNC5x?P*r;)pAUPdgx9jJ!S+PF<}1z$mV_Hak{Llu6=ugYUnga zRK6{68|g4lg~*AhXpTlBQw1{tE=BgoywBTa1&Nn z^|T0V7u(NX6gy41-V2yhOTu-e+sr$#%1LFJP%Ant)!IOkq(N-3urD1Q0`+yyS}St7 ztnnVNd?bF=nQ;y4-fxLUqMtrKJh4JKhRuX0pS=q!TRqO2mymcE2n1=W5hva6Y)h?t zv}sK&BtNkQzhuWHtxh+hpxlMBRWUiFZ;Q_r#tOcLu6>;;xoj}4TA5t7MDn>O;mqQ( zKKwFoZj|5g*5z1!z7Dds+@bd>0GoPRw=akQ}<;)7GsCBr} z#bmP+ud2yR^L5i-QK0E^f2mSbAxltlOz!m4(VDDK&0o{&8Hd{{*H^#Fv8-&O z&lbdj(>iUt>#$)-GL-)ya2Ew?mDjY=e%z>7m3?Fve|!@%Cz2u^GTfkfH2cUpF@|IiIlD5qPwh zB|P;KnSNYs(a^}(7zcw#0|MN|ppiZx=7^P4dSU;J???n=HiOfA_cFfsQ!GA9R2|Yq z&%4)7kM*X>OFc@WZ&p2v{Wk~VcPB24p}w}(3H1bGU%xDB>DG?_urZk#pgd9_dd#4r z*Eu{bR#!0~{_~FxZ)Tj}kJ&NOGSO;x*uR)ebh0}QFzUsJYldb1X(*EcZ}HXmy$tz? zhJ9||3NrTKg@Pbns*g9Qs>+QZ)z#g3w`1lwgFdUj7*w7CWfOWn`g{~t$~xX>XQ=xd zooamO2~7S%8eu5eD^Sce`D@FRV0^LV_&eZh!e|I=`S3_W7vm>jR9P zWt^>byu8d@^?dd8deW48|Hb|JVs=hW4Rv*0!}V@Q84=qZBb60wiaM%yn!hohHI)*It^wgA;W4}eY9PU$_E^n`L z*o`W;p0nDYq4dS>78I=}V61Pb?bT{v5HC}F0eJ4`5U|tp5-&EALPSQfHG_w-z6amm z8vQ#EbK*Ih_x2A6#tFYHm5@@7F?uQlEK?-bqO@8~bN8l8#$;y+Ud;QyzD#^04e!gI zX+7X&BP3A$`bF$6^2Y)?lm@5o3`X0UC1+B_T=)T?RO=5no{iM-9uM&EG#|F1mB73Z zS=K!}RXaKN$qwH|WmsG0*64+w-ukqoya6$BB@!_m!C{%UBfoQ9$FUAcT)!Gh=b?(sMUX{h|03~CCcXm%Nr49yuuRyQ*61a!v zr{B+ZeC}7{{##3f9sFK((D3N9jA~~GO%^+Ft)w6}bIaF=Iakj1y5Ah2SpjtvK^51= zz<~GF&(^o+SAdq~uPvSMAzJOF)NCaNKI#d_TIn4L0?xgpYvdI+%kM%12TOw_ce@q* zcwG(PC>I=Ku=(=JQd?-6{QuSh{GJ}4?5p{yb6nh=eRqlvtOB8lQ_3puTL+inI_Ugj zCd{Mpg~4a{Fnp%{fYjaD_2D+G##|w@AX_y3Xa;q?-R)HmN< z2)jplxvNJlFE5{A%ZwBi$^WgWWl7J~_oQLJuO65C!hN|2@h2<*;o{hF5RSNjM0{SbUi|W{!8um1J(fPVR zGGVc|3q1qcK-@?V_@dBFRZX;mEG_ibWW4>r!iZ&FSycs1tW4~_q{g+l_nLR41Fi7d zkyK9-ngW3ixsHg^PpHH`*YR**Y&I?~pMzT*62N5+(p2qSV5?S&1q@6KP-kD zzC90qOHX9yK@VJ>wWgQ1rfE~)!q5LoS~Z4HRUAiWycCuw1AqSoBKNf zp4$~U2jffkU~b3uq7-9(n%jL)tSZOfOFBAF{;N~jD(c?`8F6CJm{nhX%qbB1v!}pA z5R&DljTo|h4wu92w(sksxe5Z@uaNlm@KOk}9MxJFR@&w>w=)eJL6_*iEgn+a{3Tm} zMBskDt?6vBN{w!%QzKEX$$Jgb8hJiCI%;o)hp2dyx>|2D@tT4S-|kuNMMot7nZ0Q@ zlGW639|y$p>uYF?gIHx!n%CXlxHjHY3^yiI_Gm5ruJ@W_h3-{WDuhGbF9g0hT&+E! z5ZYV4g9N=^j$G7qyuAC5oq+yWNz)wi-<`?=o`U5wS)H_I|7`yGqk$b0t;p>Q?gK^Z z>KwZj(bLl(hf3GlD#6A=*()6+rIA&i8CiR`XfVh?cNku=-EhReY= z4_k@1kJs@U${fhgu-1BMqKku*Q%6VZclAZ218w57+f5c8TZsbV#n=pO4%t*l+Tz+1 zYW2gx2Il~99!S1lsHobz2k>A-xV&#{Y^<$oDEg3+nCbDniw6lZH#Pqk$Y9!oFl@XH~M78b>Qitv7o3 zhpl{w&h5yybNm6*af(TnETgXNJCo6V(5g zOLPCf^5e2tu?mX`*@pnJxWo~cBYl+fememrF$fz9;7OT*yJ0pjdeSpc9|K}+@mg3|FCtsx*B?l@r zmO@HZsaVsDQ)x5}E|viM;7Cc8a51uET+wgV2p_4mFPN-=ZWyKk@_Z#rbMxVT@>Y?2HM&`$BpGwU!>uXv2*1hs2&)1W008#> z^7q{PfQrGHRSCXm%(xHlNrQ3%I~Byq#P#L1+^h*5x!`fQJ$93P_9634~j9nrbne_oi^QbOP%*Rv(1E_=%%l>3;Y|kbC zm3_N}sl}SE7{r~&ghsRL8ZT1>K3kk!H0A#Y+mgdXMS+$YXIi&!&Hyd-q+3fJn+t~r z6T1h=h`TZGQoyvxq>7*em}QDpGV=C0fWVKG6rTiwzGsIVp;n)x)WnSt5FFD`WoBe> za&ppQ($L^T?l2`8)55$co6oHsR9;uCE+;2X4nYPZ zeRg+sW@TZisAORNI}$DE!^=mX-AIB%dx-pXiXv)YKw|zQ2Rmm*dd9S>rL78yU4#S| z%;C2{52>Q?aD>K2gbyOBNc6Vy0iuSC$c^e?w%?i;(lh2WS#{If$ZxNzDtdpT!lfuO zcu!K|ehY?bD#t9aRik-^QWQSC5i`%z3p4SYmD-s@X4|yYak1H?IJC zY1~8XZ-kdlGNZKzd3jH{`YE`p7~A@Sz2=t=%`g!{^ib_X$=6`=3dNcf&Sxh}&VT-} zCl!OUYx%W~E)uUrnwXq|eIIkE=zz}Vg7lVWz%pfl4lY)?l=$B44^EA4Dm6Si+PoSfZT z_vYIyJwojHS(x_0wY}*_K=4Ngn~Sd;Ecv|J3L56>W+CTvNpU6P8PxMhzO2&;6S;y| zE?aVvUbP)J~Vm) zU1|$W>(%^=Q*aW6IUxj0!fo0D`r!iJ%yFaFr0C00RFsd26qMvB3fMGAI;NpFH80YD z2HMlRuoyxDLVN`bf`wNX%L|2JQA+WUSyPEKZQ=ZmvC+{rfer-{z5+FUM2sY5^R@Og z1JHCr!G_;+M&~Q=eQIW+*Xt+(7b>$ZpAU{^^XaH-M<1KXxrnu~jkWdjSy+w9crGm+ z1I^zN>8Qw(IiIlmWT_%fclX+Z3F}mxaLQ(e&P1Ig8vN>)gZo0b`zd|LSVm4rmZ1`} ziwlzV1)s~cLMdsPqFpgc zb{rfo@5M?Cgb%Bmn{|il&h8d6_vW~9WdwlK#~>nK$O_%edF|D`Y9S-LwKdtA9`hR= zlMoj8%uOoqh#R{(+{@c&a&WR+9;iy2^e+3CO^eQu56DgG_fHQmuPo$Jjpy=cYb#g# zsQcO90e2)VdsYTF#7Zg0*VYor@Z||t>l4XR&*>UD<_1wtjgG0P*+@2E=KWSDzO>dBPOlq~QJc(l1CKGvb1KmjX~5 zwP{S{1ZF8z&o&yzW>!+Icv(l7N$>-(kuC_NaR_vMtSf2hMkhwbIvw{hv6R8~mnG>p zmMl5}GF0w&F+l~PZQh>T+}x_-!5Tb%p8ifo?`#OH&kA@y0Emc}n@28}6SjYL`MoI9 zCC}P8OT#Ih)JInl$(t6H;2LBm#}D7amu$zKKj#_bgAQ85Mnx^fH%sR^Vb!Hkof+LCT&)?cB?P#WG&m@~e!w`aB*91g5a z3JVhLJv^utefnHeK=K)lxBeTYQFI;ERb)w{WOU{}^rvGuG{v+n7DXUz`U1-iwa zNUW(y(pU=@#))CfUSg8?1ZHaMsZGjk$4kk#ApHB+$|@kRO4^9g(a}~xzgS{sWW8Vg z<&K7yiM74FvNFjE<&!B4j6_Lm0L7PW3W`5LCnFm&{wVQUb%*0VXGF7b{(Gio6x4m{ z8XBIS-eI?Aid$BPe_3V`-Nj}gg(E#Z){s?Q)4CGTCyx>;O7>YU&qv5-V&3Jo8JlhS z`eW;pW!BYz#CoJQTn3u#C_=uWsiFR!;kqVJ2JujQkPkikMkkR3M|o5OcF?b8Ll;>M zBZHW6QEP>WN1o?GSWK+lnXzfX@Swy$0sSDw=(MJS!(Lw0WP~2?SPyT4a2^ov*ixQK#uJN=E<6DNdbD_Kq01X!+^e$#1+1 z8dS`wt_pP)2gd#W74+nu!|xoY51T|JX$`?r*HGI%iW(4Wjmz9*O#dc-Sx_p6IWi2rZc|C3qoy<7yqzKL`U1>9lS~2u>=4r<@ zHtJYw40OrrxQmU(Xe%;I4>@gmngXZrK6!oL4C&Zl85y`c+fvgnE?ZF|)z$M+ctVuc zeYoz(QMi2F!ZY!Qhxr|#rI1L$3>00)Px$9r9&9)CVHDmmGv;dyXtFdq%0`vRl%=C- zfRXLC0r?DULVO7XT3XV(*xXJVGx*^XW=Iy~to!NU7d}sl)jH~Dm_L8NQV3_R-v4Do zi-&bPP+}Qk{+f28=6XKs)T=HN8HrZh+V{V;07RtO?9|pzpjR9U@kr%czMs3f|ZV$LPafu%Wh9<^Pj^|d!*8>|BO5sMr$-~BTcuRcD zl!aeo#!k#PoC&Z@paJr?$DsMV^q~)6yCI!jS=pdTTEP9z%rxWXhhwR*Edma`nIUKDIZkwCYtGd?JpZZ5|zvn73&X@H%`)xPs~ zTw|VtV@8Pd2YuMyf|{m{Ln{_$SBsyrbGqEjesQb}j@od61Pk-n?~mC(?d{fot^i*m zht(=xpF;|Ax(ii=m`OXx$dqM8Z>1=X@wG$&`t%-{`0F0C4?}Voc*uoXvUDROhY6S@ ziJ8e>GnJW)Rh1GknNn^X<{u6};z7AWMO!H^uKv8Z?&k41$5-oztr1Dkdzf#Z;H4+2 zy51hn+QntdZcE<+x~XFcZ8iOIfMQ*BWcFTqOy{%ZmB>5fTpS!K74lYA@$DhypE>T7 zD{Ft(8E1D747hjOc_@oV*G(N`bsa}T{#vyxF0GEQ$KO+UBw;ad#FpmorAgVTs9KB_ z7OAVKwLoeN`Mxn3kA~F8i-v+)y!C45t|7lY95XolYYPi81WpnMQLy$8uy=u|Z7yye zrHky}ti@(8r)FK-oW_Lq%YzBimU%bLCu` z;O6M6L5HQwRV}@T#064G*gh)t|M88IxT8XDbQA(s7dmOrI@JkM!E2mcb6(L0>nLx9 ziNHFztW$~vwv~E(S7I(dzB0HV!5p1E_+1fi2n>7R5Jz?XvuT9v=B7JeV-FazBbcA` zvHCIV=%GmR3FZgkmxMg|o~OImUuyo{s(cD&;y1wVvV6w;KJe z=yRMTw>H)LZA!}#t*rELU$Y^jiyNtO($lXDG#}Ts^elV(>vY^b=!Rp1qi(^jz~M~ut&8y#$caw{rGZ1k^LYBlV<^<0wm;kfje8-N)E?t6Nc#MD`ZDT z6mmL$L%PN&&Gstkb#G6abIz-MPzb#q&tlW37Q4KX#mHW5ZXq@P&(Ut>;ap>w@F8HV zPM;^LwMRI2hx=R9qMBXh9jX;RUdq0KvLwWCF??L~WxjT1z`@+C8i`PW{|CPQyz+=^ zFX(-*Q3`Oh)^@J<4sum03So?Ki?%h}vGY4dEzC#T;H*2vYEk64-H=&N=Ih#6+ZI7& zYSy>(42xlX+-K+YtQ(H`eq2(>doI_Sy*$on@{4Bum}iV^2fU<1l4^@NIhzUxuGl}# z&CTcV`e{Acn0YO|uB||$rG#5$F{+@~-E8f4fryWfBwfN1PuUxCmx!_5dbHj16Ujnx%1%W@2eOGlD~&KaEg7wSZm=%+ zDjbuMk5^{kcDgADCG18)BKb;Qwfc>{Wh_ZRUDEpHx^Ds>5!E$`U-FTIGj164Uv}UE zh|eKzt0^)R3Nd%C2ndLJ+zwQGMG9|ZVK(LE1h~7@hIOFDzr3C+lB619= z5#X?(?VCV1vW>=eZ>Isml`#w zJn)ZtYZIx}*?`@$@C^eaV-_KiZ-+oO5mDK)(+Ok!`)6MR-;-Vl1ckT@c420`iU4D$ zV9z;+d2Jvx6uL0A9=U!-XfHHcX}UV|Y8ojiDZ8d-Swb!a#XI%ZHWjq`%07f46v;B$ z`s&HKnW7w}1@1YC92`7br4B-c8HgMatt}v#BC5IMWV|C<>R4h{!qNa@;+d#NHD!Z= z>SEC+_Yz9#&m?R)#_1s;>HtxFaqS~$NhA@YW;JS2LhWLy?sX$k67}wUW@Bb$VSe3! zEPhgzo{m9E;g_AyBzut(9p$lsV)i7qp_<-zY4PT?1w@FCnOTXOOx+f7`}<^QVT^Zy zli~$r+-Ovy zTk&SBSyci${u?M@r#-zaA<+3^S`{4U*`y4#8NU=gsB93x(=f7oB5uqKo-6WusV|QZ^0_BmFP;zvJUzHjmfRx+yBkZ3JH+ zgEd0lktGf}Jhu-(m(Y>VM1(vZ5KQX?m*345<-nma`o&tGw-O?sj0`3>M{R!pyWab< zun4c+CC%}yuG3)P{hHTFcJsO%hS2NX{WVr9ksrU+>E8uI&jhOV*TV`%zPUlXv2?+s zr9tAn@bG#Z)$p8*_k+>+`$y**2FiE@sV&ZHREX}CW2d%u_BkAGyOY99;|jCyRn*i7 ziE>+<&q|USKCkatWp+NKERlzz6j)f>*r{tMr)MX6Y#xTY5i~b9Ryjhr3{zjn^g zr|`6Tv0O=az14Ge<^2*Kv9&!bQo*2$-qb5^rx7!#BtXC?An4yWwr)s}p^)ct{StUr z05{s$$ic~BZGpJ_Er1UuAfJG9o6{^~=D_3=7&-P7M}am!f2)phnSMfm*X$Yhj1Z1b z7bF%OGMdiv2uxjPVzN3{az0#?W}-ko#L34=fP`{+v_``t&9&KpBq6k#G$@2qLLMDz zbT5}WH8A%LexRr>*>MlFrA1s^~`dnC4VC{SrCco5yCM zs-?UQ*6p3MtEo(8FOVUxYDaw`to|qP37h@w<$-}$DM-ST18Ye2neM0NJ*ZCD}(;Q80Kt2ZYVA*6HgL!Aaf~u70=LtUz6Fx!JO4 zQA$ov&P>jhMWd*@FzelwDo(hZ+^^SA)|p-s*Eqqc7R;jKByBCx@IOr{C23vg89l9c z@aOfuW&kKh;S26|7dJ-+_k^8mi?}#D-)L7HZUOGrZLs&v)!r?8JS>K!1w&O9lLo>& zlBk7?U@-YTZSt^Nrn_ZosU0M&rt1%75gU$iY%XtNs-dZa1HlxZ=`(bSUJ(Po{iy>( zf5UqwdqeJ2St;mqUcNix2t_&f-_1n4GzkWTbg>A*4;q&79s7SCq8ijbX;S6gJBpeV z0>csZDB`td7Z*)OC1;UBL@+RDHAM@;s`Aho$|YeO=j=_TrazI>Em~T{5b)S87df#z zfp^m_4E!Vs>|Y-&)(UjZ1-vhaFvD{^EsvgZ{YJ)w+?X=_k5VaCn>-K(vggcHg#S{K!i$NNq$^+N14H9&j8rP8h%oP~?)QJ&ZQ%a|PgG5H5?u3XU^cajPH zU&ZFYR~&kQd5x6rjEM2AozhjkEU3Vt)Z=gQK#L#RF@|6kf3H7!^>qYYZ+i0FasK7# zsGN3%FFUeDx;D@9Jd41A@iy!WK!79i3K0qU?)KW%-Myiy0hhDo@wsL;Cr|&+nEKi+ zw_tde=Gfz*)+fg~Fyzw8I4okit4?|-ZFEr~jH<=>j{o1zXtAF*^S(TC5Iam3{dR3As4GrzN>GyiD=~@)dPR?q6|B?mheejVsfG$XSR_>K3f_<_UjexSfi;Mc2-^= zGt-lgLf@aX`&}2{{-`KYztZ^{(HJAa{X*#ZVA$=#|E_AiXPJEALl42DW)QJRUOty% zVoKC$k3cy+zcW;6)e@gvG({fDdV2+u*NZVa){%A5w3qaGP1I9K%VR~CPfFJ3WrUVs zRA$(qZ0+g(ti$fU^S6O8`wh6idZu(j5*2TenO{u+ti192OUcnpAs>UP1ue7YLfomF zgw*uTVV<9gbBKtpgtz0-nMMjWd#(LV%x$JSMX|v#6&B%UO*5~+J_zFN!p7#~^SZ8l zeqQ}xA24pFq{8a{01xw>8f3%~epMKTItk7fbbQd7>lc&`r#({JH^Le8VP|($a#73< z9%<9h+t!gqpJ;lZcmdWb6&>f{E+7T6My;8qKrzYahCLm4l4I#yWNb-0g>Y$ z9+w^o~;H&l50QlEO7)?<}G&W=X zZQ=LdQ(a6%(37R1`ITUa)uYbqLf7)68Uqhbm0+jsbJ><&ztqHPx@t=!_|wQfuj|vJ zr{vv<=$XAVtrZr|)2Ct!^F1s~m3QW&fAjS;uR7pj>ufeJuTnnwF$H9(= z!8Yq8YS$|?z83nNf#i>ao@oWzAL=Lr?!MdgrDwW4`<8o&X7cYzVCW`V3hIOOFoX#=>3G6SE{&2S&n zFt6@(0jpx(e!JtYL$M1hQe1T)_R7_xZD&5ytwu(E!t=Pe*$WCwZh(Dd30iq|=PP)x zmw|}KNhe<|f*me|s4b;erPRz+;HrzO1!GkKSKuepa>e00-`6um5Vbvd*J~p$8GjPp z_ZJBGyp*lLL*DMJ)bQ2(#Z(6p&(sHdi=6LLHI_NHVnk1vOoF@X2s49{16EZ3uGp$$RMb^>({4zI@$U61p% zI+vQe4|d)t!~&0_Cikl75i#2x>lW$XC}tQjo#b;golmzzU6Afs&FE z3AQ|z&{J5LfShfKm_(?+3Fb$`f6Yz*=Ur%D%9H3IlErG@U|?4XM4`$Ns5XaKqRdzZ zBAKto3ImH60*UUXwEA~dyiCn`Os#RdVPmmV95fI=ffjP?5hVf7E0wh#T1Ue`W?WW4SG{1g*2kna}M3K(O5QbG< z_?&@Ha9q~Zmj|axJI6s0QW;)yLV&Mi@XspgzjN@Ih&*$Nvlw+Hq081GdINcq2_t5= zZtAN9d4V!f&edEA-wzHb-@ikYgYH#3D~Z(-2VN|j1P41L@!lKX3 zvX36Fbu$Jma*&@*^2Se(8jf(IW5Tg|mHhr5x{^}&t9I|tpD~bc8|$db$->z=C<2wf z7QErP8qyU*ghZ;U!CmHR@PV9U`oZ^5Z-W_(<*}r7<)$%{)ZUNb6c9sms<}(7Y%_c@7^{ueulRw~}H(O*>Tok6O zXq+~p=bzhq|V@^sHsgHy{%PINL_8E=6zS?q>=i z_Z4=BYZnfGg5!V!BVZ)fex|8Sznsj`O1ilTW-TVK*#8m^4(c*l-^ZF%XLOr!$<)$f z0CH=7W9U1bH*Yfx&+WQ z`tbfDPAVv!?hG}1!{I~VWX}av#qX7VbCk-H#D!Fi!B>OK&S<=)rK=D8U0+H6VQG*c zp#eNI?IzmKz*fV;iRK~0Adn7;a^@)SF&R!sEC;=xR~t`4u9W?f!3xa&(<8sj{fh?` zO`5?fr;@jg)!Pej_c}g`Pe+9bRXE*F<{rN-=bCsDta@Uf%mx>!IQ43kV~&w)8L-h& zfj|ofp)GzjsL+m4D**~CU^RE43-rHgNx)f3w&j*I>P4>=bgL6;&hw4oX)9W_Z~XDV zAeDI~@6)q^Rq{$UDGKy>F$PPQH&S7ndY!g-n+(RXWKF8XA+zi^&5{L4GHj1Wmx?kq z`D>eN2y`pSF5@Ot)2qhDqx2f$z=vG-6hJD?XLPetK;DP4CqWfI?-lO zexpv7nX3;r@0o<7u!lZ5Gh3={KCZv3t@w(GSVTo7GPd9kV3urcOCDWQ*|#ok;IulC zZ@?t_;62!;pBPM0X`QsIDeGL(?=@$RK*=sSq$ZCXEn{}TE{XUrB?NxY6BM|Cul=gV z@EIFHBzRPKmP27tuUv_WM!P^H`Ku;zLd6DHO~=~S_PBBZ4hBYt`VxUCkF{iywD#5` z=b`GmC7JB2YWfQafK63Y)J#2EZ@uw8pO#@sOE*G{?Dmi9x=V3j^Yp#`RJEkp-cY6J z;iuM3%4RlT8V=P>laZ$4A2tSiGEM`Q-i;ImR3D-NHUJ*j3 zbNucyN*vSSh2y=D4A*?&C-UAY&!+wzMqhCw2V1ama1@7Ukmk&>iQ>*lf$J1jn8%vSa-$cK zy@Y;+MCU8?WJu6*{0Z+TI`cJ=Ai}FJjtaoboA1aCJlXD)!}3w-J>C$du_Tex(z4TP$F+_ zR?k(DgYKx^d33qw%*Dy1sfduUQWp6g9T@Bee-H75Um`Cdn?K{XrE;HpcH({hhiHN; zE>U=J~L5TdQDW2mbQ97h}@de%FlZ5;BY8n>{Px(qVWV<%-C(P-F_I5T`|!OzEK=et-N`(pQ^`RMReMX=}WsgQ%N(LfIL(>x{%Pq zh@_v(tiZPL>MA*0P$&|Z2b7j5rXW9}ojclf{-|FzC9mzNw#(N$OWRIrqD!z)eE1a; zo&aErnZvnuGiM~XZ$f|5kg~59-cRP8zud^wAqZ|dA~z=0Z!dMHhsXqPkqJj7xNZLD zM79EE^x6=D7d0$m^JCnpu_xWXrmPSkgP^n!<@~yxp>idVO7OAL-=@n z0e!k=GhfBwRgs$~HF^H!PluqPm-5=>05C!=M5~$l~2rNJekjsH9K=q+BL|1-9BH&T#CwAnSFD;u|R-v48l{E zLXTiKQK9EJ%5RH(*DD|#xUWY~2Bfs1P7XeY_cFYRal+<>_u3?Rf zY7WU%$=e&xhs><8rnAYlIbygaOii>VCN)#nP(G+Ox%z30CwzJBgWM(HA!`Aa+OlT5 z3Rn7Lf$rK95eejrI6bPW%{<#LGBP=#*I=gYrTUdRe#QYtW<*pA=-qtGPxxS+ln900 zL;IU$hTkOhv9DV=VqM-{3!Iz0sW2Y=lfqpA703TJowU zH-o-HZjNxJEt})P1hP z@X`X=QeU6j@4?MKsg-pz6M(PdLN${OZH!2{YtvWu4S)6vf|pAD-?+~LB7hX{r*Jwf z+R@nK=Z)7gY5b-VvEz^H>Gh%yf~5AzJ}zmB~ZT z*XvTS&DSz2!jn0dRtY-xziac#+tNiW>{4LOg$SagL*niyHSCRaou(77GFy%;o+WrJ zA#`pIjC&Lm6fgnyB^DtR`AQFmu=k!mUayz8r8|Q$)>gF$I}-kHdxHkV=cpSVTqpAe z2!s}7Y98x`>W)T=R^{%3dqt}1V}M#iWc&>Xcj6n?fIXv35rRwnZt(G{g_AORuOK@I=opKctsBX2}nLnFo zf8b3`6nxqovr42sHjwS|yIv)!(JL8G862Z&H}05^{=(_9Uf=k zySI#rEBM-ci4q_{a0nI%uE8N#g1a@Y0fJj_w-7>bcXt|hX)FouE`dgZI{_NEDgN)g zYu)*JXYPl&pL(tCbNXmi?b`M1-!pO*uI;I%km6V|^J!7XQ_zi)=l5FoZ{BGR-JKv1 z<~eGU3xinzEa8AWrlnO-5bo~Lr}Wa}HXSpWhSuJ(5hbNBHA)+nUd~uh@JW1;FXczA zOXe0~o~K&6NIm5tlRTo@>56M5;cLMT>jWl;{C!?S0PRA~c324dUgO>NG~i0mwl^rC8cNIM;r9m%SLEU(9ai_+b!TOmLR0CYDBFiqyK|oW zdNa-Ro=uBVnL!HY+%;3JJ5zb-M5pVVY+dwjHf#He7vZD&r)o)eZtxNFVYBg~IAN@r zw;pR-)Kr%TdNxF6*bmobOBQo;>(v;%*y?e_@~_9BB;odknCBK$jMH&D@43K=RJ0a? zEUqnnD_d5v9J?&kOik0J(4=3ud)mjiD7bic&3z@5Z%(~CvhC@gn#!eJ;qIEjuR0h8 zrKcy+vET?qY0C-TSL?1vD8Zf?{EO0Q5;no6kFQ~zn{3fmSCQ3d-f;?#6AcF{Cv$2hw(Q&VBMny0S) z3M$&KXWsnv3<=5jdsJS%a}U{cfM9H8er44L(Y>;QN@)8v^PFznKeNR@t@#!V1qYG3 zEG4Wnd^a}ohGD97ccte}{nAT8BS$DiK_Ws>OuWx5%MVE=)`7%LC@H_SbBIfsmmTyT+{bT}G#~kVt^0Fp z@XA3(p|lz2d!U76nDx~aO;@R1+*u76)ld}G81HH zL@ue4!jSCQ`N1=c$X<}OuSVrNV1P}^Xl@oQ|%KefoN$ZSDF-*`$^dL9e_Um|C+p4no7``!}T zr`GQrSY=>BvTe0~W-|Md0_WzH&}JLqbgN?wJ4^Y|A2U@{apD1yrWHBbDZC>hswPaF+ z>6HnWswr38=A=eO(IAU;X*M;E)l>y7SYG-d#kXB<9(XYJWg(KXz`HDDU+>{4GT*+T8eD)(6oA0PjTtgtwSMAp`7dG14@y(6q-244S@UW0P zA`XOC&SFPey>2FnT&5z@1#UZQSlQlv;M)#vl;@;r`6*WKw#phPL`}*0cMyObxcF#8xvE!EN<(pP&H_@VGt@%s?V+ zbAJTHIm(v}wkyF^`4{-sI%*%FMOnKYuaHJ9&f*FzC3iu@xwZ3uD3|lU#!jNWVc%88 z#Dvx4#Dt$cegxvS%&gutAG#FFxwae`XinzuVu|T8dqt&ul`5AN{Y;g>7-uUu&fd@e zMD=E36w+f#62i}DxDgP_gAMBP4O+S?(;Zs60re z=aaBbY`mSqU{HAVMV<&k4OK|TQ{7lZK$t*J73}$yfkWd8TFPp59U_x|b#0)cGz8<4 zZhQZXAs%&F0lpgxUtpB(OWB<9f0zT#4gU~Pfrz8t;?4z5DB8PLP=PaDBa{|S?T?*r z%TdX`(~nzoK9PwLgGj5;&FRtq)z6GOAR~+6q_2GPFwL$_#|q55+Ixb4tO-QNZtPv zf`?I4p>PIys&(JUOyor6%hBP7iY4IVm(GJCI#q(cr$+W$PY_ln2-ebc$rCOvE~qMl zv~t<$ndo2F-4i#L#YR!RMuE*ADdt)?GZrq$-061i~Zy8w+XqJI*s^Tn^(VUvyvKtVSP{rDN_b~u&Dw@*;6(~UYs!OmJ0Um;8V6hbR^&5OCSl18i zI+>{+=i}3q@7yv{ytU{^%i0{}QDO!r^7%*jK9Eiq3K@5t61ga;&Nzn84u7V+OkO|n zpakS0+-q~~WkJauVMTg7xHw-nO(s==L<7W#F6{ya`j%^x2Qb2f>YWWQcF zlV@j4F2K!G(pAHfy1t^KSDjCZ`$)O5*yXq;oqRl|ed#__;&A$(*COyItrHT*Yxra``0+VSsG%exitV~Vb50p;WF5$mb{6*Xq%HNkLrN=VXaIvC@w}T4d z^0p2Tm8%hINEs10#z1>s^!%+rqb}%&iHQGZH`(T!K1CtD3Kk)ImC~$)4n>TXoHj|$ zszov@l*s0fAJ|i6(IC5eJXUWPGO~Ad^ImfZEZ8P0vj$Ve;OOsElvQXhBuB7LZNd7y zmbI4Ro3GWB$y~TK1r7y!lzQrcG;)>$a_NEGA0J=8s4_Mv*mhNO_@|a^szf&}P5TK8 z^_vJo>WgiIAz!^bw1@(Exf60_x@`j&oBvE{G2X$VI-L~j-@MX#E?0Bl*f0x^cJ@Ao z#q@8j*FjU0ikn2G8-&F{vKy?OhfxF*rN#Ak@{JEV7ENY1%nmA>Te8MEg)8*SXth>n z%js*tRk8IFT}z=`EeCZEVJuSjpp+bAf|D*U5?MiIG{+7$vIedgt2eD!dng zU|2DejS&IVZ?oQ;Y7nSuj z4VCpQjOXx0um8>k^jB1r8FtHngx_#jq)dKwm20)D3r>y+IvBM1!Fu#Y!ZbsHWoZS@ zi>HGZgcigJ&$uf2c!@S;!6=TD{rNsd@+%gQSB<bgV!X4fjO`!llCkJPj>6-n@2Yc{ za7b432$%OLE0XR4oRRk;QjfPt*c}b+^Yparh~pa_6@a6vtomIsv zm<>=n%Yd6V^GpQ$18ot4YlP@9hqFnYmMmvkZEmJspmWYjG27XL6s&z&VVcE0Yh++3 zU?BON=pMUUCo84xL_h@5MMIt)O9!ECV>gJS%4NhW)yCd<`e!+&%$EN+C^G*c7#|02 zt*)`TZF5*_Kx;`!b6{XT6iReEH>zX+(SbxIYUt~CBfXq-OIi1ONMsgczcvtPIp*DoD%3^?fc4eaFLtd4OkWW5bMXaK$)a za=fzgJ7#4iCdO!APLkG4a&C~n=?8UUf@<%&nwnZL%F*emUL&&Hn%_sn3DD>4&C!Kd zn*QEZ6@`UKDdF4N3{prlMSuJDZCry!zSc^-NlxOL3gyV&p(%~1)gFgt9Jw(5nJNRr z9a}q+Z@Zr#pneq;=2zSH%yrXPZoTN2oa6IJ$qYuZAKM&Zj02ZoLP5oL@0Zov>rYwr z<64a+5tJS!#K(`H@YJI{ZbXh8~0&P zpFabI)eP|r*-G!+dX-S+x3?`yiI2{XNZ(sO2Uc24&oWNO*hkmTEC3!dWh_jGoeGpN0U;1%H@bzXl+NOwWEOPTCGgnODhL0$dP$6vum z_JcqEXqI?>pW>M$7xZY%H)&~Up{L5HqV;g|m{{yxE;5vfXW)37?u;hXcBd>FG$tnM z-Enu@%-BCrr!l5)Vy@X(R%Ro%bhkO2W`v{%iNuhOqiXynX7b%w5)&e`tQS@;=z8X) z;4-~jl#QEoC5BLAQ}eQZ$zi0PGURIMa14d?oR(vUh-GBxKS4&1HlO>Ll9Hm3DUcDH zYTVesWBw)1_d`}4-qnkfl9$%5`C?SB77qp8ipnAzlEd4ZL@gkC65j4|&VPB5C69^c z^~!URKc#`#|5~}@AVZH|>pDD>H#x-@oMVzbPB2$yRySke&jOl1iwpc)?#ao?lIW!6 zN_6I)zhS(zW&|u0%D6(6zKVJaCi}+(ENQV)`KnU8Q;bwJS1m2OPO380B9+9MN^B1AtYL| z+w>Q*RkM=)FqA{)W~S?zycE906U%cltOxaT_zVfwwDLk#3+`O9ZxEsvB*h$cyU*vZ zk!-V;^(i0)LrFZo6t^!?ce*_CQc`vV`CU29tKUum87oaGBO?m~{NK{t?X^pT6K|*p z1uHXsHVQ$a%OS{(2a{=2y+DgxhV79Edi~&`Kqur(DrPDKBJWg1G;)3q^OZa(4Gm3e z$CWOxZ^Fk&YFo*I?2s`!&(n{>r!s%iCVbP%`d2qRle7=XyeiT=nSTB@EQVBsiyzsv z54i~X5f^DlnYZ6PX|y1=O6~Ozcq(G3V&s`&kvKJ~WY=MRdvlYnmxB4Vq@;q2iz8l& zTByxOS{kL4v3VuC0zIWaIX)im$ySPoxfJRP)SS$tDz=sb((2}ZFTDW9BR>>8<2QnsQ~!6AEn3Onbig~?Utzqbjm@PYGDU_rqK9; zLtj&MQ(J|IrsQX!(hALSnj?>jHa;<4nMj%r*TU@i^JfrxSaETvII^s4$(V7^Zp7a5 z{=TU2>WWd$NG6Bw;^Lw|e?omuPTC_Uc|kTRcQ=o*5inqV|Bla}U}|Pk?|=sMkL=01 zlvti_9+Xr>kz>Z)AzihFyY5>*g%+PlM3Ai>97y{%*WKTBgnft#Ttx5wx(_`mpLOhj_NI-eq+3YN*O?N=>ba@6XFDtDRtqzV3t) zqz3NKLN>L@u&&lFg&{n=d<6xT`swE-_gmtNMn;SGJe|@ zp+xvIUa?HxX)~1QB)k5-t@SQV?e8B1uXt7(CzWN9OT^h6g>r}2?M?D~zNy2d_Cjnm z!VXBlSX2H;KDB5dO5(V#=;5FL1j%` ztW!mfL2FBEvgwz#n!<1^^X9bgsDUy>pAULr&~F!wo!>6{i)ETb6oj{DzJ=zBMZ6Y_ zkd^8jgj=t4((67!C&aW7$sw%uzQ$iDuq?(pSgK)sD;WMeYH#J=maa&3O+(>!M-ZkG zb?~EybK}n_acE#yuTE}ilA7@U`Fp&&OR>?^CSIoRXVMpAa?k54Wd-bz6i{+cVBqDp~;HO_-f6(F~3e`%~Wf68gW)bNa_brPQMM>vJ~irWZ}C?;-S@A1Ka`ExCnkn7 zA>>UCH?z^J1j6btlD6h$v} zb?tiB5rtwZX?ZzSIcgD|vv6*wqN~9=H82vO1Y1N{@flm<^L@%HDVeX`=Gc|8Da+4~ zhbGfcq-}4_MvGovy1&fY-3?C79v{cHUBg`rrU_BI+)Uimo&NWkCdRx_{Bd?pbHiT@ zQlS`rCtZN%W#}KEr+N-=ZOi(#c5!4yV=58_|_?{AY*QAP5AE9D{5^= zbXy;N+k-wFNgci~gjrVG!4&lT{8s;7ohoyG{Mf3HDKzG<^8(dYs6xb+Wv7n^d#0u> zKc=JVZ4k9lunJVb{l*+w{ZJPjRV%L!HZ}6msJ@I>+Vj1Rf#dc4W#mS|i28=}^*6C0 zHeC@JMOndL=dRGAB09QW*OPyx2bLW#oH>SvcW}z%6XN3Hk1}W2894%2%54vXgaGwL z+R)JFqmNG_@eN9rGw2KZOsXf>*8H-vel9PUmWHjYP_{k;eeu*S`m@K2`tzWQUzdV` zkABQe(S~{1M|Y~J_32Rhgw~96W#FUO^7c$eg~h*oKeeq_j7?qN?D*^D_nF9}Ke2{i zYd52?-X*Jp1mz=mkQn;;DP-nsQgBO0s$6bjOegCuc(vP(N>Y;6B|lpw$#iSsac$|x z^C?lqFT|vd`q_V;Vn)0!5PU8(01vI9m$0x^dI2>fR%!V@x`7^8ar0or*rK?(2f3e!ye9q3!dLl?{Z%bdexSWXwMXo8BdH?<0l(xrY+8Gmz&BVm)X`%2a zJJcvDwHaBj(Ljx1syEtLyD9zRg4ZG#W&6K#0hVf?yF-ZkG{DsF{kM5p?!CA<3Df*= zb}Q*-^=yxEv|yd>-|qt~nxea%THDd6sqXzgOm8R?mLDHJPN(Exe4Aq@jDr)~cKdcD zO$h2**3@*lRkd1H##Q(kUstV0$d7Gz4Ec`(Epbko82PC*q@cT7ca;A&NLv=9FahjVO{$iD+N^@^*YwhoPm(4;W78fHU!?A;7h-`>+djc-1 zJ1DD+_EolT6$3+6Pef+#T%^m_UoAfq7+jOdmxPM1N*e}8So<%`ncrJV2856fXr{uC(mq!;ruM>yMT5SF; zDc9H3q$EoX9#iSyBcD5;`ua1~7l`9CW(J0$lCu2woIJWz6I6Mn>LbrEMyF7`M3CPZ zuaFYX2@%`#5WhbS!7B{4;G zs4hS-*vI=O?wWR&@-f?RYHL6sHSVjvgIg%#Ic>LB$jG}q@WjMK5NrPk8G4xoG06v{ zp|4R+MEst}JUl#eZH}#!uV3$2$fjpz8Z7>nq8RPqnw5#!^khGB7M4*h->ajP)ea3< zvwH^(mIgynYr6M5f44G+x|WuOrHl*&@^+WfdVjA-(@Itm!ca!X3ebQ6lVgfBgCsJJ z2cM04I;w9%q29Eb_UClHsbrJ|iiWEVR%5zmMN}|JX;HFjW@%OVGntHMq6fxQ9yANP zNQF^P8?{+z2Zm%`*Yq^e$(Qfz2URL>H#LvabVyx;{F4(0uvBn*yo-Qk#cQb(&3tik zfZ4;){geA8+b6$?WMEY><_aD&T|9j_+j;-N^0#$|waS-AiYT#EQqFgj-)W9^5 zMf-r6tJIqm%?692vg&lN09$yFxI=I_*gHt?3$@ZO!fhL}S z0H{)swjT9|pvFnKTQ`GmRdn>Ul(h%J*I7Eb71yv78Pm8h*UtUoV{9!*Kx<8^)HlOl z;IClBfg<|aNoIq{*1^{4@Z_o-mj+l0LzNgqbjpAJlx4@VME2P6b9ngR4aQ#mn@&5)>lSmelnBSg3aM&j@`I|Zic{$w&s5jD{U0ErX?>U?ZgW0lm|G>CW`Z0ncxaP8vj?OIU8cc=}byFuSHeURp+a zXt>Y#VLOd7E7ce(?4v0EClVNuueq2Q-u#SA)l$~F>~v(E=-ec4v#~Pn7?P8g=Kpdr zd)FbUkj_UN+xMsLW0mzCJh{e9&e_GKx~48#it5=jarb9|U{#x#+m7Gy;PLKz7d!pc z_3dBstls~Q0wg196h!P@28;e;{WWA^Q5cTEkZ0Gju+Y->*nr9FxbFX{P@)4br5_f@ zP83zVl&y}_zz=}rK05@QvSLrXXVJ8ozSQkmQ3VUSdP4VG=>XCSL*wM+OcQXtTmGBt zTc#^&Fj9IVN62&4L`w$H?v@t*-pCm3HyfVfUDTzFjrbIO6ASxO1R2@iCdVHWC2Jje zAujI%Bp(i1#l91T=<~E2OnR?nXKJcGY-YeZU+tZ^cms{46}Y_+)hD|u3nFf?_Pq+6 z(WG?;wgcp_LzZl%*(;+iYHC?>FLnz0WTI9DOlfZJ=@Os&v5}d=(=Jtpsq0Lyrklui zXEO{^_J0lJZ5suSC#c z`0r>C>$!SI#mVJIfWf|xgTHgIvGd7J@&x*->wTZ>h>&}a4Vu%YQYw~O7yzQ`>gn$7 zTi2bWlaTseT*ZpJE=n%-lm@w<;=0jgJH8mxC(OHw}by>zu zfyF?7dl=u)c5T??qHzD?OUK6V1Do-0W2%%Z1pt75;JHS>@J;OQ)^7Erq9y;<`O{|u z7F5t&2#LcQ7icDE6f5hiC-1ISb`Q;W)jWi*H?G^T{&wU%w{KT5wCLEdfg^HsHd>C3 zPvD$05KBbw-v(9~HB&7?-AiEUaCw=yG~NmYVA=53MC<$8+dxQRYN@TFt*@ln=zd*3 zWyJ&V-PH-`M1)O<;rYim-svQJyF0|=;~cBl*fZrz*omVD6g%wfW*&~@>C zcDrU%M{5yMsHo{Bf_+F~J@0ZL=fa2{-Z=j^X@hg*bxCi-`|52r#nI(@58r> zhr(_b)%*^wI@N9;m9p9im^XJ+baZsowS9!R4@TNGcEg$Gx^<@akN+98jpJ!f5) z?04@oJi=0iy!JZv&V>sakm9j72h(12xn)H*5Xft&t8Z-JnQpF)W?GN51%Ra}*z0e3 z+}Wo5`-rwDLFmolyV@s9G&WMGhos}m(wNptNTwD8x&_tSOq3%nN(eAyz3@R zKHRrO!rKvbu0rrO$H>1Sh=rR2V%EslWclgFmX?-wX0p#xsT+n1Kb->`7L(7WRrL?8 zs17AKh26kowRIW?o1V2~RH0#fv1!EBFtEE7wwSW?E>(HXYOPScHpApw-I@)7n_+Lsyq}H z6?>%PyP(Z-^YB=0pV1?{&hAnjIciQLGIH@i1H)C(8~1jkwPbw&H7}p z!vk8fwu<;?rtP8SlO8tCYFjlj$#ZU(PYKGE$7_>b1x+Wqbd?_2j~3e;;XA2TUrI04D58=PJr2j%f4VG z=<~FNM-PF&g>IEYcxL2zjiSKd5IsG!=jlFXlZsVMs1Q`cN~l)xXRe{y}OpL5H_$L0JdvYlMOVQ{3!YB7!IWOI0BW8x{^ z8y(AhppAPwc`AZkN1{9?K7Rldgd>^lCr9eOjCS)?%@a7-W28LnJgn_CbM`8b33BhV z{J2TZg=Ab-)KD4g(lYvFJY0O{mQ^8}DYGZWX1TfTm$jGk-kp_nvS^_xbJ_@-8E+9SCDsmxPdP5K{krc(%7?p(!lPt<60E1d z6eP6{T`)sq(aY{nVy3x9A*~3rcPPQ2tb%;=D;xsi#LD|o<<>>`+TNvk0nv~Ye_>Ts z-#aT#My+Iphzj=0e z;hK@L1o$H)7vPNyOa!!fG?maO66WezuO^Us5Se%N*ZDv42UnPXc$gQ*iH3$Y{g}as z`TE${Mx23JaMiyj(`JTVEFyy!pvU=_Jl3Cu)XXKvjfi{=*!sOO95b+vj6r&Pm$=k) zG0q}<5BtiZ8k_rk)N!l|rZE-(Z?$XZrgCp=s@nanvf0H%&%BNuGtDD>Q*Cmcf#H-4 zYF>!TLj$R*3h+hrfw6)mUy9%=4UY!F)oHuD&fR(cd`p0wzTko>JGAqg^LNC{Q!KMG zrVmSX9tI70zDq(hG%EWQaPwrjSZfi_)A8ZWeF4Pk@sjV|X=GZ9SL-EAFyH(*6mw}> zJr6($4m=S=Att5iDiiFst-C%9T0<#pCdU`{b0TO#bErMxM0_4=l@&m6x{ujjd6wHF zC;qxM8A16CfjWL?X>2uA9vWBcwC|*8-fI(TdwFs=HOF^)ivFMz(Th_K$^&3!w5y$o z%Mf`f8K2b!Oasp&z7(H-i~LQ=Ry@{sON@3z<+hfl-3u?8--}b{&shL}h|8V)8~d)R zmgDOG&IOnN@2I!*_<@0%I#>ffe+}niuN`XtGLJ4Prmg{6x%)_^)$DKQBMBDqpOWM- z4NugT@87>mW_V;U=#=IbZO5_zVEf-9tPTkb;_-GnH^0ox`b?augbcR}Aw0--1k)6Y zYT^zK{_EvKM*QI0TW`v1iLEmif_IOaS&GOc+#6h_9HqQZeHDehmKK6lD+UH-Waari zj^&CKLO?koOJ|WNcDxP}uX zdO-n;;gpSiJRS^SYqVOP_v_Io@H3ZMJQ%`5Sk#{$HW?p<_}=AznmHqW`S09wCEGLiIc9BDlR{n2w6fOj zsjJY=d`~Vw0tFxY3=h%e4bvrGPAjV(m0BLkENnG%7$<;aA>K#3&8jCW4DqEdSh^ z9l)4c^!-=4_-fEYgw;h+T6*Y{h9pfaxsXFzTT+ujPdHij{C4MP=TUB5PZl8Lpp&pw z?LT?OtpCpS3;~7L>ar|VdlPt{X99bH*}e(g%30U}c}E>;C@VEBvZtpDp3%w*)T2k9 zpPvt0BwD1vtqAdqvs2~aOams*g3{8Ltu6b-t~1bo1CqW?cHrEA=DgDWzu5Do>bk1G zKJxMdyiRMpfuH&%bTQAHI10nb*y8lK9vR5$?Wze{3g>@c=2^P_@fyFwBk1D#>f-uR zB_IpnRj`PGzfy7!xzA?q2nghzu)0ZO#@QQ#0~-d%(4;k-c5j;CVlrlk7k_H*E4it{ z3EzL7Mx+*{OpX6W+ZY;Cpry&LwW8|^US)|_6S}^-CQrQ2Zt#=pJW zJ9@UpTS9VI6Uo~-vV2dJeR3r+fHoUxOXR`DM~5Qoa2q%j)_Heji#}HY#0P|u(}g*0 zSX!;;z5j8D?4OnJ#Ejgpj}BuLg}mAiv_9TxwMNthrKg9xT>bc!q&PjT4j=RK08weR z<4JA%aLO>po740L=9}exjflNJ$4mW7Abk0G;dM4ueRcKyTR6qU#F0lyo;$}Sr3IRxlF5hm zwmE$WiN|`Ou3VpoZd!VQ90@Sl#Js&2GSfw?P`8&3K9EuX+=z!3g#n7ARRi2F!(E%U z&zC&Z&UN+5vbu!acGYaJ0yUNn;v9`e&yVKGb&DS*rKWnH{6W6=yke6~j}bkLio$DW z@>JSXB~wkhJZ}##6|}TuAr0Nk<`BXOY75r!z`C2S6z6X>ztdg7{muE-z!4ff7v>R! zC@!hkY{e>14%V-ty+5}U6@9`p@f&_KalSN)h7OirNLw_;3{#GnGriUxwXWXN@7-NY z6~Z_oGX=`h%gft1l?nq|%NCooii=sN^3z@pw~0s}Z18btqG`9A#AGCwrJtQ1d0dSl z*R=yXvP|!P+;#%gnJxD;@u3F>uy5K|8J@>jtyaiq?YIYMmsh~y&~J?W%svK#jIYh6 z=YT%88^S-3DeQaQ3%O@xVz4!FpDVk+nmE_fOSABps3%S5MLGvwc|8$iLf-vU2Ou3c z(VPgESts%k=%UUyHKp;tyMqNyKqlQ*7a}$JyJ%@FtV~%2ZX2cO;8mWPHLcK_Uaz5N_Ymk(bCc`5&q~`B`r=LjM zzTk7E0aK#uy|#fjVMy;D5DsrCT3H>JsOq>V@4N1e&`P7LliW0NZ(kscZ0=;E|RFc$Qh zjibh)(SPC8dcG}m?opEk!x&1^r;`Xhc$6NP^|1oNK|Zys{@+sHhw8JZLfKD}>~m$h zXEIxb1uWmmYpAL}cz!acBZanQ2>YBnmm9Nod>$XoLuNNuv%_+ zFL~X^YTTc5@_27;9W|4?>3UA}FZu5IR`qzuDr5@!9(E{hlhFXJp2Tob>O60qvopwN zd?gl7!Txz{V&HRr88laQ&HJ}iG{O65OmWGpTl^dF02*aTPmM|{;6;q@9tvK<8OtKG z<)*Tp$sSC|O4;BhMqQi*WgcZbr=n%O2dNuYdS*M51)W2W%6PW47!?)#MR$Yw9&WF* zu9@1_7WxM7i(xApBCO?eyb^uS>n95=x-E3!3n#s?-+Knz@3%F+>kUBTy5w8#4kT6M zR$6}n(A4$uJh|ooco&ZUni)VAhQEk=uuR&femQ#iZtob2x6eCLXkk3tOKu|ddL-T| z0e=1Np&V<5vfA0fOd_()bZcG~s-lwa*Omzigzy*HX>$}cT@*0XJ}&y~2byKNb&kvg z>0E@``MTZ5vO15{k2S?WChkB7(~67%EM=yqWp}qmK(fvTovYwAh7u_ym!RWDEqxn7P(Psb+fL6t zV&+Pp32sSbehvr+R4m-obbak$&hx{q3Mc1HvuywgQYaAV%G41jYat(5< z)q#P5B{ev$8>()(iSGd;^>ygd{RNr_SNRy9Bgi$+Z9g8effX4cW&_UaC%Md){5vvz zPegY&#UApU=AppRmlrpltjTw~k?n1rBd`+sH&va96$yUKs&VRz>f8oaQ$NS&ORTK! zZ?2cz((fq2Pe>XSXh9DOX+Nu;*&b;im_=%&`2VCv<^Qlw4uQU=MV?v0 zruguvPfAKm{uZvrK%>Bj_wK==Y3tzIARQO_KkGEO?3iGmHnF|)sQy9#=B=Y;L<>LW zQ89_1ODO&|esFMwapjg!K|8mq7oIJT02Td0#+X{nJCDzae!@6le^0&Drwtl!;p5K1 zW@~SVF)<;;P^CCc2(|{Kv5D7ELmIU?+vkA84(3QF-;!B>Sc4GV)4nQM$~nS##Caq$ z9zkBM_^|NM7;``p1B!6xTWOZIv7r1lnRUc^w$6tH2093pm9viZWDvI?{rup1pmnUX zbO}R&7D2y%RSr-YzI|=^SMD_aBX`DsZP8FhCAh*7XZ4A)Sr#G;Qt2>;M2mh|N4*Yx z43bTzI!?S0VT|M4;qHU0tc1ymHVJ8FVC&rM?^=}ZkUn{;*IG^M+^P}0^ZQnKTGWcD1%aC>{ z*~nG%pm9av-pU5Q)ZpP63Gdvmr6u^HjJ3+FW~{Qto&0n(s5$g#cx8Qn$Qp^F(_z)X z*+rXrwu@%$)5kXit|luTW+s)gif#LrJ3sif_(X{`KRQ8H<+10%pS$S;&V4geSHJvS zePYXPF~DvMKNw7W(!FrVA;!??rkW^a$;x(UwJtQnb#r#YIHJC8k=W7)ozXDlC=*Lm zfMb37`yr8D;TJ2djU9FMMe=;bRs%2}+6`T)MG1BoA-~%@lI6xd3{Z?XSkO9C(G2Y%;~C|r}xE_o9A5vKU5BbF1RmHGsAgT2K} zY!z$yzhlRH68T{p@NKNiqQiG7MUdViPUm9wps&3GGw)EPK^f+`hkUZbF@dcfgS z_kapj{x*aA>ew;BVTbtFXGBjQIHlS>ReY};O$>p2aw}A2)c#|KwUBaUsPS2l@FerB znDw{m7ZiGEy_=OiwpwNPJhFld20r^QonNuluNms`XvgZ}%G*#9N!se@8`v~ z{(Au#29&P|YZe(^wmriTA=PMyIPEyjsqsOxTS*5L`jWPl0?0s9^4`kF3)LU636A6B zZ_FO&<}3iwC6q!X_Sd?vDIPUGrrEMw)-A7K#TmxnIt^W-za2%8H<^(mf;|MkJeFrY zCFu;zYZgFOaSx^`y0q)wUW&1jZPan&cRL2MRM3$i)k>bfly<>}*yhOT56sy??7!NI zP~wKw{*fwCADhfmNwUyhr%P8NW5)}j<$Z2H(-sQ@a>(9ms3&GZVUGqu`WS+omO<@A z?QyqHXwuS%w)Z$}?|Z-a=3Tiur=>>P?(1%OuXOh~AZ5+0RuEd}k13W^c3F(8DpKd% zHmaFxf5tZVt&`LE?U4QUei2mp;bkBOFM}$*6$Vkg5y!L-3YR$GhK*0mkMoWG&Q1)B z4Jy!xN>=)cY0ogJ#>Ko$Ijm~Zc_5MayArkY~4-1**H3vj7At@=2 z-y^johdYYdlSCU%$KgJh@O%}zazF=+rezvlKsve#LJzDXT)A;OKmC02HA9BLT zZ|v~2Vcg>ynAL4LkCC{&(yD9mf4C-3r;#Y99Lj6c86nP(>o|{airkDMVTHp;#Fz!P zX|R8eXV7W8e+$cfx*|C=^{0XM%`%WUhAC)&T3Nus2JDeNDr;@YHL8q+AtoA<9HFG9Mn7_2ua8+_&@*vd$$`$QwX2GA)#F#6!X7j3v#aDN zi(?P{kQ|%3gl8L;RgRLBNfduZPd;6ryR6asoyKyAE>B$|Xaa>J2K-l@YKGqmiEcJa zcrAKfmH4lo+TP2lmCNNf3Y+TX7bp*QOkV9S*3`}%&{_DnVP3o(BlV>3{mo`LIl+(2 z>P_p0%44Qs!Om0F%S_onE!(`-LordS2p$yDT+w_+!W!sz-&%V^AB)u`^RXB@WsAt# z8msv=wbmahB$plpHx6mEKySKtRJ76qI@3f(y8T^m(wwUm=tFDIvL=lh{}F6U((pZp zIHoov?@#-?+M|@Vhx5;97b?;FS{c5R4l#)AvAd}oVdfN^{&jDdnZ5LxEPs3I*_f+4 z`pdd61p|vk*Y&v6X~l!+^-hiRj#25IVJtn2)lE7VT$>2&NGTwGvfS1gvl|2LM;_HZ zDSqG!KY4M9J+uA8ZI+;Ktdrj*)_ivOqbj5~x1711Tslw#UQ8msTrHsCP=2)_7 z#Y)=CJ&^BO8HgiK!Z5zo#R+wh^Sm_)S~QsL;1V<{AO7wvom|uTKD50)u%$5 z85uL0%n*9ac(aK5le)wdNDHy~D&GXPQ)7BXla%+Tg{z!KGwk{=>E%T}_&R!Su@F|6 z6;w&ALDW@VYaehh1czP?dG9mJ3wqnX{95uECKwDJl#{^%9~FJFrK?5%aLi}_55VOp zUxY0%_*+U&2VU|(b%bzcW0|VUALUPF->6WDKy9_Wm=W}Ym|@^t*EB)5Aa=7)h7Nhd zfGD;!lo9AasWce!MY5BnM4|&xm9J$WnTl{&!JC59W`4~Cp+EG!(w5SgpjzR)_-2bH z{wsritxvlDX2FtdBUg*!WGQQU?keomQCM8xmc4>K zsszX-A(<2SD{di~$}tG14`(q}x?BDySZssYWd0{;E-`eHY=C}7ecoL`W;XZ?U_FMn zL}Dso(f(sNs>UzuK+v`Ug0^4>Mj}E%WkdA;j^ctL1B8Tv_D26RtSeuw=gm&?AB*iI z03Dj2?a)Qae2AqO%Ee=D%atuJLwCXd+VKc(V|w59myjn{-1qfFT@{FbvYI)%qr|$X zPPoQihQ(a&m@89b*noWI!N`_^>~E}fb>$%utgYUkNlDg(G1e~) z!RnFVkFoUSghZyF`dG_v&g<3Qr<7O^CZQ(fon$+r*i@* zUqJkUAfN4h8eJf=kka;=xjo2O^x#lqP}8$<78e%>&W>J#fnQrlT%0$STpA(`kmO7C zE+s8h9`8;Agf?kMa(FoUsk1W><)hed8V_egGp@b-dEs__#oFji&jU;w{+;&NO-%ba z_r|ieQQ$)xJTu$QVInM60}Lm2Iy30+qWGOwqu+FHgg~F+aYp zsma8~##zfk8i+?7M06F@pYOixkO(Ih@(_?ud++0R7{OdN*iuD_EMdR&TJ(FQknfqQ zi91n%Z5g9l%+tsIf%#l|0s^gXkgB!ZmZ z{eA1+9N#o|z0=VtCJFCn-oQNO-5FJNr;^eSiu(y&u47{Q3TGkf15Opi<;80>YwTLy zHp~GB!?U6)?phY!dMCunl=1I*-vc;$NhOb!%y9D`a!VTy9I|>0)h)BoS~H@m0iQ;;9Yl;2^U(B_~r(P*C2k>0TZ*?whvO z&xv{0Bfayx)7?ls!Q29evo$sX9#>$!R8trMoQl}D4#EVf(gj?$Znkme44@?Y+p9b- z5!&=M?_BU);bKgSn%45=#S7$CnSlK6$#gBrj5$$Rna zX|h$dvX`!t(wCz6I{6P3uc9@LtZh^l6wNc+=Dvxg1}2@DRgXhLLr}Ly{w{9;OC}zs z9AU_zm6l>A$Nh*wLKWGE@+dp)hLDeu6rc4_TR#H(EseV)S%@(X#Fv-($yX1yMpRHf zaFhGyYVzslDuS8)(W)_BC zDcRsqp(T~S{e4|rEr&=18m=jy7}QKmo-MG(e-1%Ib4xrF{sR2v{L)(k(gTd;ot?F$ z?SUKOB?m2VWO_+ZfUTX``w`Lg$=J-!$Vf#+RZ~?n>Xjn}BS*ON^SOUE`py08*|bGr zOwm%;=!7l4=iJkGv_<?Tzix`_3!6sa1eX8-65N9Yg3I8p!7T(&a2wp+HMm1?cL?qt+%+?} z+u*Ke|DOAP-tX|%Ia5?k)%?TWYwvYky?U+gZYb+G-NqDPWwL~7I}LWUI%fGCDA;U{ z#;n;?R4-0|*f=6d2tK|iF)Y8A(A3n}+1vXq;1SjsS^<8L!Yt}gPA@4hFNC0;s*r}) zPG80DM{|y1<*hJvAXdHntk3Jn@bF*>4!VZTvdk>3_AHO(RdqI&<^6u?KW9sMur_at za9kGbXg)EZ83-Ot@g8=1K>#L3*XtF=(f;N9s-mIpRS4JXlsFNaX+UUkQ(Ca3yM?T! z>gMoPsMBkXUB1&i<(sndvKCZyIrNqL&KFS*TYZ^F5eV;U=Zg~|0oM}{JS2^EVgeQk zH-1<~)CHkL=hva@m9)zn+`m>nl($!GUvMEL6ipOh6rOxhnsl# zA?A3^8wen?;A?ih+o3G=R;qD^`MT%sp`lhIpgo@ zfK2usx!KcWQqPWf(Kpg)PlVqH6A+;`KC{-wMmDt04r0zKs>?-Y3cCM7mz`j?xeC}f zEmd?UV6r$Z%7R-PZ(5bbQso~U8A)d*(-*2&YTi9vtM*}p)b269M*$MR@RvIi#Xf>U z$*A@AEB{=?WRHH0BwSYhKiJfZ>H(|%Ph&1BgcfgikBE87cAbLXQ#xHnPIh9%ysBsl z`kbtDnkX}G+wkzvnpoflk;|{l0+iPs*aw&S>Ytslz84}nSAA0SIz~i0h1@&ht&$Ot z^eW62r3J_s8Ra)bVXUCQ+7NEgqGDPo61Xf2_yQ2qZ-cEk)@Rd%QvcAQ-ttp-}M%?!3JrbjMVhi#w$?< z9yWzp0$4#&F*RWHE62!~zO}x;eR#5(EIw1;CT*rj0ybY?6V2V6TK}29A2-V=MMDKk zu7xeF6abc0|HB0+#gcuukd0HO-+u9G;ng~y-U9;2N|OqXHyM{#Q}8|hY~&BxlfEw{ zkhP`uFuGGM9MpccDJ`uU*&{}#X614EyNn2-P}S4WQqz#kW+@YEX?0hwOys}Y+Ryc7 zD2&(nJ2R3lWK#d;meE^eANG|}{tKR(hM&-{$xm-IAyd9Y8 zq3gT9c^v$N;yLL!1fz6D|ILFp;yvZ%GqUBt7+ldwvvlcg_77AbP!sTo3@h_U>!xvw zSjW2=GZtR~iO~6_4EfV1YIjC9ew)FVFD2YMFg!Q^Kqzo9CKQ ztO;b)*{cYFMETifO(*v-=knlolQFECPXRe}Od5~#dhAb5QZ6sfkD5BwKUEnCG@MdR z#alMkeA#E!n(q^(Y_z=SByl~EvB>yTJ&pNceyWn8IxnXNz6_ri8U;~zncIN`M*MlV zM=XLrK-!lL^Ssfg2dvGa*XJV;3^u!E(0=t6;-3S>dUv4UY;E&WP+HeA`ELGv@#&J^ z`>gps_b0acbuMwSAVXKT{=w()<1#L8&cx*8DNIf^-w;^y@@y5|P*Ng*JNhvklTtDZ zL95!H2KxKM5{BWg10UiE@cR^|6oW%|S3cs9+3#+vbZD4^0@(#YneT}eY^hID!H|Ch zAGo~shwR&3Io%(=oV<5^NCZFFYN+^ol#AI~mz~RJ@=ngokJu&MbSCiMbYD%`yu0<^ z3|XQ;zCD=%FXj&lSglf3(Td*wF?-yFXgg15a%_d-Ugvs#tsuuiT?{Wg)i- zxN)b)sBt;02<<6{&v-ZoDeT>Z0*c2`U=yIu)k)iH(7R}NSADTKkB0^af?R+OD^=x< z#Ve_*upSMI)4cTZeuk6#8sYPLP7FID;dR>wGWODFwWp!7W(nvZ5&WZOgLZPabLJy7G9>QIA`5_-NN+!-_)Foz9Oxl z-)f9=W~8K|e;|&w>ypAGTX=w_>RY>198D>UWL~qnHMpuNJr)9hr{&<<>Scj6xVfUh zZBo%Wf{BH(p{B-|)R}8CWoC5&b0ws?bnd0C<% zdkU$z;j< zymJiFEwQwQEWbI9A?`QZwYi@LS)I@S0jIPdA|Lf33R0fgKN$JWfRQbFwvm%<=A7Uf zK(~ZC++L}&05$?kxuYK02)Y#l7Lc6lCiuO{tgG|I*M(dKM3%v2cwNk}U&~p&OfJCqgDaO$OFO*l%JBgzn@L zrmpFeMz%t4Guyv^{dw41`Uxaz;%E>!9>uNwkN<2rJvq>{Z;&$s$)FSbO+kSR{5U7a z$9v%u37y`ub7-usb9JysJ^45>{z3mZxSMl)Ll)J(hq436YH#1tXXxHFF~i^9vm0DE z6ei1@fV9Vi66?n_4yf1L9#8Gc$CPS0N)Ls2yfD{ldIeNAKL8B{vvf}4kybV=a-oCa zGv%(K%wax$yfupr^B;~`3|kJ4s6BIKtjDqO)+<@= zuDgPg+)OJg+i+k_SR6#{Shwq0AoUhDb|ci2>~y>nob{RdOTc4q{!HBJ?N{Ba`{}J> z<@>?u;ot~96TTgCm`hGbHJyUEI4M}L`Q(c>L`h37)7HFGU*@ozzXcwv0{#oL5bJ~C zuAbjXW~9{u_d;a>E^M&ND7$~cgWw6YI-$@JEO{ANT503DSJo(0FyYflD#$_UBxHmo z%imbB7~QO3+wV#4txc6YRV1;Z?CdV1+6dF5!EU%o)Q}&BNC6o*x(Or2awnes-->M| zyuJ0@El?YDObUymGdbt&^elNE9~a3zZV!~&L^}bknR)MF_lKDbX4KkgAe(;n$qn+P z5+_4*TsG~v5lv`(*vH4vzyWbUb)Ml0ggSq?`kD&&Uh4Bw21EKNIw z)#1$ZZa%s3ftaq24mD)${;E>Ne{=BlDw-a|rC2Qj-tmkj@5qD>j}LHL_h?GWOKbo9 zDGE2}di~Q}66+l1qRGxndD1n{2>CP8-P70nMpR)G2)?W?p&y+DpAeWE89`M;0Mpo7 z{E4Yx3nW3ne*qKa1a_P!w9iRhq4dp^2p^+?^v$jHn%6@=wo4RZXprOMAE3uWeEyJn z2DJY->nDvZEl+li7L#ej`yLNN3Lp?Zbh&F6zX(A|FHkwOwAMW-(kygt0se|$;`DzX z*S^1fVBmLctxFrE2Cka2k+N?##q|Y2RwKn2V&>l^7?JaUNKPj2Gt{EeVBhl%on`Kp zIx?i{8=J!hooTDZuDx_2gXY@SrD?D<=JBr7agIwiWuMfczJ~7Ha&R#JUAvJ(T}GQq zTdQZi{YMz(2ozKq8Pk!2@m_u07Mt+1W)v;Lf%xr0;5Jt1p+< z!6H9mg-FGa@cU;(3wc^(xLqqLm&3ELT*>EpKRASb0rU*Yu z%0*}&T}oGjflySLkSHSQfr8}ZV`2J;jGV48m+FT9y<_x?^rk$0eB_iFNoa=;JhBxQ z-$|;~gV)C2Lqp2a+T4w+@ZC5SBqUC#n(gl6PI6cL-t-{oK=Jxq<#Vbt*^ z_gZoh2i0~}4iViSc0dBwo-97N#dM{;t#*Ivi=4kukwjZn(p>!D`1FW%Wc@b4aGQ9|AkgWU`) z@COO<`?v7l7r4TvrXNBZYcV_i8!_!%QtNN0vEhl4d*+8w-}f5DR|_-I^ciV!WrCay zG{w>6yHdRc}!42f%QJ+cJOg5NXU`M7%aL?ZI;O8NUuA1+RfA ze85cdo`l`*%&rf5dv%c;fYDH@BK}bl7v|+J@*WR+SOMQ)nI%_w2sSw#4=im9h|w&B zJs*zmdvZ5$ZPIf|3##Dv!>2A=FJA`hi_unFeWFfKo?+er1!ZOT=GbQAB@M0rff+1` zaUBSizsoyWaY#9Rg;i*6Q8nYqacI4FDw}KE1hFjZ&k?7T(KUzP>4yxk_r9R<-{t%_ zIKgjDeiMg49{+2$R>3Z*G#!*9?5YVZHplh(Tt=&2E0Zd26234$%RR-+=1sjR#c3e@ zyxHQlJC^^%JGGH}Jmx#a+0At}x97`P3wn#D5ErjXTg+k$R-dvb=(?UOG6qbhV|7@e z<21Rd0B$g%Q`#!3b3$q>t1w@stgmx5m*d#y^6s=Va_*=CUquVMZ=MaY;ij1?1-KYA zzr0PH0#)d>>_>Z2<9zlO5b*X=OTd}i!>##)dHit%rt#t9Znlt5^EI@~?xw)t$9tIm z_wU-PE{lPv_W0(+4DV6ApPuz}Gj7pcPnQZ{!)`BQvQ@O4#!K`Jdw?;@cddWT?rt;1 z<@E(Jw*)?z4JTLx?7z7C0sc&m+=pFgw>|!b2>}i=1-0T+82xyWFvu)8l&Q1O=IN%| zu+TUAm=&7+b?W!NA3LtehpIDi7&Z_CYz*dhT&0q{yiY=yQy0ar(hKy&aJAMhcAZ(i z5fUx>-0p}g^x`jf;+}fK%p9V>nE&4lLC(8CxSf|PrQ&DoC>#KCQe!fma63FpCC7wo z@Na1p$dMn0#jOzQcA>GRm+me7miF3YZs+0Lo(Y*C<4F95PP zxdQ=q#fe3W(89UFnQV0xGMk*qYtJdzps=N@#x^`RmdLPnwFiWl=e2U38cGHuX1wYY z@)tXjhh$+|AG+GEY#$tm>!>g?K0FGEVigrMPc2O7>mZIzj(6rby6B^Y0dVE2Gq0(C z1xrXYxG#P)50!9<_=qa0uA8fb0?M9IHTAIkQN4Pl zSa{nMni5moRQ*sNY3PhsaQXsZ{8F7y76;2<*>kpq#>RT8q<;r=D<~_8g+;S8m7U(R z9xHWHYRWm4)J?*GEeM*VB6C%JZ9aH2y~}qCt(UWsv?pFjv7YPp9G$hPrl3N6I@Bh6 zVY4x&UUubat*eD^i-`B$=Kpd5?o$_lf0|I|+eFiS_ZD}z>5D{_<}y`D$$NagT$6ZALfcf-lg9K1rUF$)3o*UN4`uh9+ ze-*O+axo7|XXi7C$VCqCu$P&cqYFctY_u%cl7!&{#nVi;O-?Em*IceJ4Vo+^0rP+s zw5pTOGy53wYnB}zp^*bP9y;1q-*WH7vO6n@7ndwuEK++~p#M9iQFr2f;E|?7fd%=2 z#qfO6;ROyDsg8Z-bBD@MzSTk8?5-H}_G#|?(|>$4SPCQ=-U9{sK_d=T7(N0F3AEm( zaASA{^2iEtK4}EH?!jp)0XdBLz46bVvc6yV$Ayaf2C7WwY#sq`oe}0WwuI50WeYR; z@v;4#!r&NE$fUNAtBz;3tz1)Iu30}U9S?8YqHBFUWIvuVype*TFycsXeR~tfb>jg2zngPDC5*Dq#xGXts%U8qM}<|UPy(9z$!sCf?4QA6 zvTf$|CIypVZ#}S=_0?Z4-y;lgPN%4r+EojO`rG8M3c+G;1sSyUR~+}ZYZa_srtwyF ziZNtc0YNx0V0&j%FM8_Y>?AhLMoP-haI`cdAK4+)vh<^>9oiIAu)Vn|0LXnn6I?FU z7=96iIw=hpg$b>{q?;NN6F;gAVp@0}e)zaeL-#i=J-vL*$IxE(C#AQvjdoL6QLDq$ z6n48-5H~4+!%!rtaDi+c32havtgQHU@RqhmzN*_MhHSfa*VoR37N0-R98?`h z=8U7jv@8aXiow12b#w=_3Z9}@sR;7QS}JjIS%17|A(+2e8=6bj$Am=RhZg?rJ+@!(^awkkd{)jbVWdYxnpAT!DGK#UNmHt=_-PBxh;_49IZvy z_8!U0>s4sWVi8l-r2Oy1-G5tW>kb4q=)m{?KUtNA#yYEw zcD=G6Jk=_#dImbj12TeX4B9MyK(sUXCMOcG1TDro&BM9|M6fjzehLU8w?@ZF1>sxL zliB?I^xc!w)0A{{pwGO{&&e=ADs1k}1bLDSx-AOtlU5?o=QsYb&E#k{17~AXwX^dP zRra$^BkaL;HhIC8!*WXGAuTy8Ej_u)b^iE3%{HBrnV!D;-*9bnGbas~^JU{ozjqO^#~*VQmf;n(&%gK@HSJWp^Z(W`OC6>zSP5mo0g8wj`5z<;9#{@ z)4^RS2U8^#PWbM`Z|#jY|e=~ZQA zWIPU3r-taZS>B_|T4X0SKr%TX->y%(d&(dOw7S||=l*ft7VZxe$E&W&{FmdJSq5&7 zR%r)-Y!pz>u%2o#fvNb;hD}Hz5_flQOs(z{>;BIj9qkfSKc!3;!qv=xEIn=xjDt86pkrKb&aj@)e?=(4OF#2do zc}BdxG@TDDu1-(X*Vo)V<-1B@#IWo7?43MMwqI#`dk1c4%ofXgoQ|geO4_U4;v$pf z=k=|7#Nd!}1f)CP%L7lJP9cxWq^~>pYtMHpSfd!4xu<@&YhDA;(b==I{_Vs^a&KCe zF2A<~^$Ms6bXuN^$vyX93g!02 zU1xs>L(+u3u2ENP8Lb*{;@v>lq<7nYFu_!`3Iva<#4IYuvl&X&&{>ww#@BW1RsK9W zxgD3j26`)@*9)D{Xfm@mf*En&;>~^kQ{rNt0aC19;7jqZcNeV(CSuk&=vjVzyOcFv{~P{TiO{G>FJ z!o0k=+W+|B4j7{~`?XK+y6FWUx&^V;d_l0WxrO=ZwoD=A_DJvBdud&<2sxSMcCe<8 z4`s)tZ5k+H^?p*|McLW;daZo1!3kd_aQ-pWj78#T!pXs5YV6m&{XKcR)xh6@%Za@e z38(dhQNH@{eJI^AkVXoG$5&RB^19tEohKBJkBuWq-xO!$4W3=ooeEy{J6^rHItim% z(IoF0m1Kj+$;*6gWCay7QG%&{laO{jKLyg<3VEG~eSzQa`Bfi(1xUbG1U!)xe)D+W zY|v#_S5yF^-M#z#CWB0N3jqb+hk4ggpNA;d>v`W7c^!-nz1GD(?Jg`Xp&g}onn74}!Kxg4g8Lcir6 zc#`>Cbm!)`YJ&A{LEv*@V&c>0Qx%B0Wwpo4uyo35ODe7T(bM$a+Wsm(_~f+BGu$IB zWlg)uzRpGHBh-9veh``vuo8wkdvti%p!xjptO|^XK*aoxQ5F!Hc^u8-n+Isel6&t;g3;N% z2LXcq_Ua%<uW4<=Y-yeO4)*4`xB4Onz?Dv7oCHRldn6M(pgXB zh4L_s+g0aBKzc2YOQ)2r<8=%FE(e+8Z!}bWG0lFKI$cIVq3d>o&bi6He#7mlCFKBK zX%^7<54Z7wU&O=%EH=;LM){}(ua^Q7V@o`)){Q1DadC2)Mjfl$wZ5y%&jKR$-H!1d z_=i~~$m|T0!g#t5?z46Lu+Z}b|4MLa=k-O#sr|=N*{#8Sedp2Ngv&zbnxj4oD^GD) zLXQzHyXKnC)w zRy6hzy^aEvS`OIqrC8r=ZS8GI3co_@caoteY{zgVl50CxbvZTrzSW(T&_QN?x?8}H zz&KrOBJg&3xb38-q$e?UzposcCow>LlCP<(+z$x{hIdto`Dlu^7YcRE*}YV>Py$iL zZ52;cd~XS%MY=kb+fceKYfJf(7et*hdg{4t0l3C-Qd-9pW#c8KFR$nlieQ=kqWoO1 zNul}n#kG&NPe`zyOZPnH!AR*b^7-+GO;@k&9_o1(>rxaIb$wRS!&wWc*SLz7jmQZ*?17I)38bpL8IX+=tQrZJg=}8|9qq zEy%E-&qP6hE5g(tsK|Wx|0~@A@bJyy@S!n8RSpl!?l!%Xw|{6yQH|#LgLE2Czsf3b z=pF%4KDihudg<>PlivtNu-(WyIN5E}vTO6ue`5NSkdcEi`|onvV-Yh(_4c}GJlh7_ zbGal=T`G@gav{^x%{JlYMw^c$#Bxj5A_DT_wC8(s&F<)U86S_c+AuaY$6LK|QR!ve zh4SEj++QlysW91?*+xukQ0PbSPdEVWW!w=lKsxJN(`V{S@F*aFZW;H`>nj90OP-$R zO&y+FYuoe-qk^$0kv9n`kEJA3n7?emHIUH^B8gFJAhX4l# zrSJ3##}Loh^WkyE9CY~o^IvS#8jA~dxVuHB?dUvw+>24(?H%u`qc)*W*J!Gz*3%0S zM5lmGGRtlI#sB%SrIiQ33pBKaUtTY>lcT>=0#IS&tD1DQ-hz+o_R?_jx7?A&u4)#w zlr^<_j?!i@xbQ@llsJ27Cc-{^xIXf@+VPA0QMg%u%`W`W=4O>$cijT|WXWT^T7Yhc z3p_llkfyv$|C-V>VQx&FK77JAd9O>lJWabCeVIIYTpW`AcP^el0(?t&$ls7jVXrnN zH{0tRGMd8Ar3Y7p1@RxP-k#Ft!DlZ=gQ>K!ICbSn=C^SY5*j%AJZ?8>qe+BCJ!5WJ zI*bnc&zY+xsB-BAIUHdjOn_0(?95NL|6Ym^YS=g1q4l9CohD*tR;z~(HoXw-*C7o^ ziM@_e$2d8tuA;(lsC%ed*gIQ$t@*xQiTjJ?d%Z@RwddX=+atW}dL+#K!FONPDm_n1 zr6s7alV+PvA?29|+xy)L#(Uch^@ct^Z^3WDEJE!IDuS;Yk0*xdc=fm`F9XbB8Sp^{CpEfpO6li6hIS6sl(U>ZYk zS@Dyg_J|9k&wZ7qa?T9{L)Y|9GA{?2=WgMzu`ftdb%aJTBNM}d-Uet8&IOU{WUtfQ>x#jwqayokP#2Y!!XsdKrz!74s zL!6O88&iDmDtMNIxzwyI*9K{O!fzL61k6!DM_V?P5W>|uO*JJbQfMXA^2SLU-2033KpgUdy z2$JRTVhfrq9*CE+j6oZ@>sYa%YiYjGk&oA95?H!;>cu*K^1 z1($Bp!=qU#gME5&Fp>e>^?G;R%YV{mZaLKlIPS^%=)NF>!}qtISMbSK0XZnAC{aOMgbU#RqqfKF^%$tMXbbr& zTs*EvlAYQ=C)kN>FTHd)lU#&JBGe0^Xm=e7we6C^y+T>@c*R{QulSOFt8k=!5cnz(YH4W(E=gmYQdS3d zrZv?<@nHOQZ_OESqWae){KW19X$QE+yU|mhCt&%MqVMav5I|FJ)x#<6Ii6kas|@x8 zVOM%N@Vnxk1E}zJ_T9>r@67}pMMP25mYgeSCI=2j6%G#x#l_Y25wen*y#jowkdS2P zBb*pWXYK`E;YU4ODJb?SCnr7K&CCE(Kr>sjmrDU$PfW6%eY?-h6NhZ5<6?|*j!W~7 z>tXJZntGi+R*zZmq@I`*M&}~z%$dTGVzCbx*%1ZEG1=hd#`2O9l;xkme(bsL?GqrU zJ}P#l`$dT9xyPcXPz2rGzm%!nL-g-jCFkL1Mf-pr>ld?D{0}{aLwcN=npQEhBep-b z6gjotb~YllXw~ykwF@p{lvHOy_UqT}-Cf1(HlEMC!7U&T{z!xZYMK%Lz@Q+WC&0Wc zm!W@p)n&Rp?R{88cqXr}>_B+#ot5#yRGxRrXO2B`L3cdurID`@kBzpQsabDC58rDY zyGn@ZwznfV{Gq}8jM?+kJV%K$YL8zr?rLIm@2>O`>O#JLCLt{)^$Id$Yu=++?oz^v z&M#A!P=DH8_<_x4e;j6$skMTW)!MbxaLPKU?;pPzYhs&mwVf~gahF9)0TNZI z%~O_0)bzfuTMLsP{X%!V?8y(PkPOhB9v^F=Iw6Snm zkJ4v@uVu@%w=>qrh7U0jd{x|R7VVCgd^J^t1x3*r>>Ru_No5E*h@u`<(01>orO!DV zK+3}Izmm&5J2>nz8E=zGOIPVKqdl%7{ zTRq!@l*)H+43BRNy}aNOB|dl}adT;WL_r7*;+O@w8Z)sD*WHbdFns>N^T06eh56+m zKfkhYfKvfvqU75PPTzc!?)vCzP5Vr~XtO%u_}$^FrR-0P=+}#h{GO~arZ|~TSQMhNi5dm-K%!IxqyC$`&B=wkWb-hWt6iTYmjoq?ut@J zjO_XC>S$=&U1UT!rXAEviTQ^CNrrtbwd(~%YGHSe_S&n{@~c}o&UxwWS{zqZ4)aN%O`{K zNU9Q>!eXlh;=nb+LHXesZ5~$S{=6%wA$jrdggc^v8?2>y^c4>~$;;8VE6jXl#=h^c zP+1^=AL|27=wLQ2Rat)*?U%8(%rErHs$A+CU#W(Kk+PZP9M0!{-o=_AHyyXXj-zP)lDwZ4@?2SgU&@lx}D38g~5e(BK7#n^hA*W7}!n8ieWbzHd zUW$juM=x)Fj<0SnjYT_2?sbnB3Z_{;jq{WB83Qz7%rUg8G&d{T;LVA^ZoD1IyMwh1 zV+t+GROCWEoQtoc-Uy{SQ(|3m()d}Zka|-Lg|LWdRFn4U`Xcwk2_yY_-dQ@}xJE}E z<0&pcU&e_@sQ>#?k@T60;dS@L6#J*i&qkwJZ5~!3O6+C#>DslC$2`|Uj)KJEzv#9)8uXFbCj9L%kJ3EELabsA7Bn(oMjMD4`+l44VOVHf! zg1EpqAJY3m->t9myHFoNzB^9YD+HpG{q6H?63r(xUcTTW9?dXGJ^RD~@WDcvd_0%( zQ>~K25-ucqo$m{(&UQOM1acHp)tasrRb&D%XroPUBekISO9FxAQU67Xe-SDg>V{CU zTpRbNkaq;arUY#29C2~UHhnh@_Yb~?d^J8=66y!zg+BRVtTuCYYZK$jKZ=0*kj++_k=jjVY|y|D$s8Y zZAOysKR6J+A?5qKyfYU+Z}+A8PEJm)>oHbCKuar~MUOS3rQE;h;YOjn|KCbhYJxI4 z3Q8<0;_71}w8!yf%);BlDY&}>Ifk*$`mRN8QFd6!xz{{8cyD(+^(!74kMF%l@1$I& zNSgDH#n+rEW56Z0@%T33B|~aW#%^z+)d#3Si{mKYl(AELSlHR$ z`O&aXFE<^bAHQUWQe3}%tA|S*@#=RoHD5P46`>)n6>_F{oTklrH}M~ar8;Y0TX(+>`0 zC_h1VyZ6)fjtP{v!Ns^*@|ySTXgv-$4c$d7-{tg10lYLzBq<>!{_X53c{?%DJ9Gr; zMD)_*`VS)Y(?jJVGWl9;4a)4_sEYLTgn?WUE=(fcxIJ%56oXpFOKr^*mouDyjSs`v zNJJ*D6HMFle)!0%`?hPFIf?twHev!Fkra_OM13~Xhg%l1-YTw)#`tL+5-2Mz9RMqv;qEag%{Pwn_&mrOX36H@C{=@QjST2LGLPc9+-Az2pnI zu;Z5>c6PVlij$*1l=rzEM(Nz<4jUVntX0+#f2KAv?7Agj{gst~D|$%h#Sl;L;%Rf+ zhyl^f7wDdAH-wp*{*z{l=rSn>{qAsUXm=F5G=Hrc*FG+6;q}`z`d1b;mS=Vt#0GfZ zhet$PthIn9>pHx=GW4Z#;2_P{>!}Tmb>*WE8j-SVaI_RFAyJuPyTb)+TsB^?C;LOq zAZZDg{e>7p4geX*8c93&q7QI4PX6vn^o)l?*bpDVmHhx!cQilcX6GluHLtb)S9`lY zoiHYoXCWfse8@#l&G~E3)xX6YTEw+Xhrq1c(rNkpntE~<5gBIL)uR3}GEAipdHnU? z=0rj{$aYevJ%SJ(akuKVl5T+u6Rs0sLc6AdD9{Xhn>^6B_|4q~SBYB8+vkTXJDXX^ zkh0P@DOxIqk)y!ZmPk!uWC!jf>q;hB==nKE4B7;0Wygtk=*_{uhP0@pT>s9H5N$89 z%@h_DBdy^bRznaW@wM98Vpi>=PlDi>HQo#YogVRIc zj%taUPOlFa26EFXqg~(;5$}V73eJXPVl=Z-s#Yt;i1JW+_qre1ovsS}y*+PW^9pL> z@Mv$(#1VsoU=Y`##cW3#bY%WyA{2~BdL_!YKWfRiO&wl=OdXykuDL}ub#)mTd9-)$ z_?(_NUGwv*@Uho3h}nD?P}qyVMgNT=K0G+|TS57y55NTfZ}ibt;_oA}nPfE#7wToV zq_F~Blm@flOVZywd6Qw;ily=U4wo^4Y}8N!=IpzFA^fE-dBJDa5r5|XF7aP4sHRJ( z5WuvyeMT1cEekO}nfe9zngOaB|+5&O@Rg}jWmn+i_!5dJklCSY?iNN`j| z;iK=Hv|r?3E=kIHC{a}L-zt1!pi&J?M~Xy2D8+jEbi$1w`W`_vHhqWOzKIegfCBjU zU+Ck3pMXC%KPuG!zTXES|9?OIziA|ZdIi97q^koPi=RbBWwiA4%KCqT`Xweo`uJ74 z#sBkmSbq4Q?!x1H5t|gOMT5KMdFHkoV1kH<_#uGe6%7s!P8)-BeqJ2`5ux-@RbBT= zkeQN?wz0W6RqQ=NDbW0@IewXQcH+5R7mfNRYWv^*ouzcVZPCg#^zN$S!gRyGN*eTdlm0*AAF z8B4>NR0Pur9gn@9{Jgxp3)R-vdT5P9ctL?g#<%fXn>Eh!E?!?LI#Hm`SKA1-x~OVs z0Du)28~gr6Q0T@}*G*#kTF14+`-vVwv@EjmTOeu1LPXfy_k)76ymxd?N7KR#d?96c zz*4~GXfA%Q3J7cnD%b`Z4q2OUmjlcNfNs)o&6$HuEGg6zqa00E3eVUcuBU%o2B_#O zhKhjGo`2#EmF-Z1DP#&aq~i+8v}e59olivvKIdwDAby11_2|v0swy&(-kvVA+e41q zpS;Sr?QQlrT^~LO>VZuQs-p3{NHYGtJBD7S4VDiuE{JU<0XKi>bTH>nUjWbsf?gLD zB{e0jW_bv~2zrnv(wQ#M@0z-d%TDpZ(sZQ$(BvW{uVd?UMIsJ|jSDU;GU5Ce?jJ!q zJg$6|vF59tuOdLnu((s9M%5@p4|pw}43t(Ba5j$lRqq5Wph9nKh&k*%UJVu1Ng@#KyQ>O0^596L_qOlBl`SX4Vjj+}1te3zC!A=CEKpDeKAor%s#Ms2d z#YPL{xp9%+`AD=XE@xCln#8jkxRl1-*eJ(JP-lATkMm=x!8|A6t|NZsQX zy}2W~a~>*@m7wEY`Zt%Qs4d{SThsHL%C?U7D^lqVd|P^1SzdquDV8Y=p1(;xm3yyn zPY1Y`G71_>QMj(^Sii)%xtZCos$6eNFsiXSslR-oGAt>!G6H{Qpb|6ecB?Z#`2{*{ zf2m?>vH$dm&+Gg!N^*2j6(vADlkZc!t{!AORR9xC2k>iWAs*DX$>emo7+YS}E!*8+ zUrsKKb#QQ)&~0|u?k8-epPN%A=XY3If9V*aCD>T3)}E;y^!qg?4_uCKFjnV_6$otf z*U#4Kdgk7#n8utXia_AUR-@kBnz(3Z#rWdS8yU$GFj{?J;!lklSh8KytXM%QvgMOf&@g!q zors|r5|$S;+zfi%ZNFwXI+^Wh!MN7M#$jNDUS3!>WzYsZ_06%l>I`K1i_l?^@NOJW zd*@hGWN7;-5((K@MlB_@HuH{-4o_#ueXG268-OHvOk`m4A!o2`gq3!K$5&pmZKIrH%Jnp-y z$|%uAqA%VNk&#$rg7ag4Bdib2txC)2HCMM5>a6w_DoLCG60?Dmrhfo8LA7&mV5ReQ ze=~`A3}kn=(igno5Vo7dpec}gcI97|k(4fq=tMFeDrYG~$)9LI! ziG^CYG&D4KhXvcl=BIic_K&?u!~%3FhRKq4jlX{Vs{ItwXlYShT~0?uwfwgdnPfu# z+xPG0hAVImMhm{Um0!j*)Dscu{in{(#-X?E7hcj6@H-noIuS7M2?-AYDheqyNYHE3 z=i)f{_?RRD->xxhg^!oBZhn3`#7A*8Mn z`saD>U*v~?ry~R}OkCO%o%b}^m9DSdtcolhEwx>{yLO9wA1KV(g z?2yb|^t+s0Pd1ZyT-AecR{xX=vfYchh}heN^2-5`(Ph=FI-0CbE;#;s)BO5kyhW z{*nsU$f>I4wIf8JUFa-UAAiKY-m!YGkuM_?mMu^}*gIC=j)3&wL5Fp!S7XdIsQzV) z%4Dcphy*RXn9tuKyfhYtA}g8Y_tyRHb4Ze0Dq1*Fh5eBxGa0KF35NqPp=Rk~@<)n2 zQ=(hk0S2}r|9t`N9SFafhVNi*Lr}Tjuano_?zW~jp}aDIlWXoEm+}4{@s?b$uuN_% zL@IJ`Jm;gTs>4VW^j63lb8gz^hl#~>nR__o&FFaDUUk(U!E^BlEoh8j{#hIciR5>g|n1Y zQA=8>nw<2|+prJ#_-oCU7JEX02M$vJ!=pyo;@J+YwFB0Q{fh8R^Fy(6L+M%4L0cOM zW=sC0_f2eE_oY$TTH)c0z#%pXM(VS=HSaTmcXV3+c>iKV0f7&Q3bbLNn}&ZA&$o(e zNi0QsekPdKwC@2A-2j+lES)~1>0oLuE{(5W)8*N?j7FM)10mEs8%D()UUH_*3Nl~V zY?!h@3Bbi(UO&wrZ5ODc*9ZE9XNjrMIca)I$kQuL4aCN!@|3X__@ZkIO z0S}wz)2GZytMBJi{uPug{-QlVUnC+ToIz*sE4J?WZ2^P+FX)#mweUVQJ^I2I10JIjoHA|Jy{KQ|QO|L4q8cfHMX}!;#ZP*cze<^iJLnzw)NJ(K9-*Q1eQ((if}v#qmQ>}cpYKO8F=s~ITaLtL`qyDkK{sj00Ge@n*lj>*u6 zdpI3P^it&JV7uHuF#T~qfGE(XPLK(U{0@|oLW+&Y`#FAGagg9wMZ|A{hbruQ{;+e@ zM4{Sa@Fv*dhcb#A{Ae3B!aay!u8EE`I{bN}&XE$gCb55jZe(~w?9;ZVu0X2%zPOF@ z9J250$}3caTZh~AjSdSZhwAK1x3FZ=2&UL~H-vCwcGJ5bd?X)mM&jNWqq(gfjC+Sh zzuNBU^_0qN5<~ed99(|KTdn{KejcA?DY`t^K$p_cbPn+ z;haDd3atT-UGmn0x-a3trBrQnw_fH?gAE!ID^7Hz5&^debUS{PK_9gjE6?APumk ze91@VeA=f_G}QYh|8E$MEAhpX22U5ULnZt6YNn0$M;l9xTSKU?_F-kAF)PF0^&()6 zMUP(>QC7YZONyw=A1~-V@-SO3c8XuoF2$#j`tdM3O!|N7I)3By_yWKCWgB$5di#2n zwi1tKANK zR1*H0*}0|E2aN8ZHoJQw92av_ISuq8cP)AK-(^6*S2)0oR}OKgK1UERtmv^YIIP-y zbIeJ?w(gCN&N53sG7=$xg@A~6Mia}wI@3OO==0EPa)QuwvQo_7mBAr@wSjHYXDni2 zKcs9f-xn$t>x<4PcNy$h#38&mL7okerkNCUbbGx!M@hnz>Nh|n>hc;DE$vrZK>J!? zQBW%RPsi(g#MveZp4M19FFZW_-*=r0fk}>-6m=T6`}En%k7Qck^xYrt9F8$CB6IrW ze|{JnDx{_T3k1rTkR@ei_6hz$5cR?JacUAh+FlJDv>}CvU+ygV!^EYPkj%I>^xE6y zRz(I5li5+Nbv}rS>PMF`L$posN`W5RUA%c^$-p46g`1Gj@=1+As`P?3Y?D=Y+PtKE zdILYkM&%=1Fqe!V``yXH3i6f|CQT-Tu}Ogv*(xqJAt@0arpfZ+y7DbP%jlyNLTQ^{ za2wnwR~41%h=z=E$RyDSpH-}+!Y>n(HwQ(g3hywk(@>l7em*jB&dndNPR=J>T%vmk zBh}k%h;TbQyH)SwWPdN^#f)!>__F(T`ycP`ttZD3!kBk>PUgGQnYGCi*<9|+B_i}z zR8->PVg_B8y9?v+u6RXZXaeT zou9kgP4CWf<0={fce6p4{>ra+?-;TWs*wJh7#M{Y4~jIb2(d2kt0tN%_Z&%cNXjEj z26gtg3sD7K9|mmdxLj-U_X^?VW`ajSz`8(;QU;@^mc&{fd50PVDca=%?m;Al7(9;V6=M`}lqk#W(B2hs2~`dn^W_3oD7|`PxlR z1&;-|5)wfh=M8q|jR5TjZo^VWxnP0Q&yu)7_;pJz)Z%{o7FJmHj(G74tY@E0A|WOF z^twmMKvPFgA*sxQnufZ}BTU8ubl4RQ?3h-0BPnI_OpF&YHKEVUExFxO8KvBSY2`CB zGg71}hiv=0@}VMhQ5o!3r;Ql>Sx&qAojv)qK|vv!FYl_DVU4!B7%&c2ze$7EvaiAT zxXF^+mH33kX!YQg0C8&jA2ZF^f`XuBN%aGn_5S`pHX&GKLVB-Vq#t&z`&MSqbzS^=>2 zH;O2}1?!D@>iCQ8MY@8{XM}t3od?<*LnTO^vv|e=Q@4=U;o0g--=ITt>j=EH43xVf zK$|=w!@?2o+whx-sK-dndKtJQnMK8_kMga8erz~Pqk}OEBx3;~yp`Psbj(6=JjkL` zsYIZME8ZF+y0=D9*dvy0%5Fqj>G>)wV@_SJRfD(5DvAoVl$!DxCe(Ife>7SySoN=m!Pxrz3)HsA57Jp z%*j;ES&DQu-8{RWzV}+|T3fzgU72RX?Qp)r7Ao-yuX=KG-eLWBwBj*i?5#T)*`Ggr z(IoLENY2i}FS(8Ihw~)DFE6fW6U071VX29>wYD}13YkHE;)R8PKmQ!8L?PcG?gHtG`RsjF z*oTAJ%dO(D)EvF`_3PJ#Hn-nTI@4*mR-SI!%-J0Q{TAL?K!-8vY!s)3FxniR`lcc- z?)zL$eckg31{g%i(R)<}KlaCxInIm(p^Tt!qSFEm8!MUX>3I1nM1i$$NmDUx4C>kqfhJSt++dn;fG{n76K9PGrA>kwEPm%7}T~d(=bxEzNcd?dygFx3Ig+j<_G7uQrQ&_mY z4M#v=MiD^ZC^D*BlT{E2?!U`B)6xTJUXEEtd@jd5=~u=Na7T%X>cb=k0+R(w?Y<}v zroVO8z5eRAdWVd3zOis0*aNbG(3L0bd=(k(`r>Fhi6GSJa72+IIGK8-goJfpb9;9* z3n^VxO9UMk^K`b2!w=i>dCmYyj6o4hJOM6vnpwrB5x2`cKP<#Dxh*H#BI3%L`}R7k z-MOi69)fjV5fPDs<#jbBo0{6PD_rzWe<3ABma^M;uN$s9JG%s!nH3fnYda_OfQ`?A zHc1+ zVyBEy;TV&=xGUz@DB`6CNJdWOY_N-QoDxIS3qgu{=khWIEJoL(W2yeYPY`e3tzL!0 z5g1NeFmI5=!Z%yqguhlA{t86Cqq;YVTHW2?zV7X2L>}gCf*&r|ZbBg0ij^X<`Al*b*B|u|p2+s&%+WMtY>qbwwCb z6l|yj)yb8kZuU6pEoRXPh4gnBCTM}xPjXWu+Bqgs$O0A>;Sfcqm$R8^ZyKHrl(IWk z>gzI-&7-243v7ILYm+$*Nqz4~1f|Gj6jk6?>^PaWCXT}jUs)$*M=pLSgmF4Ov=V5` zU@!A>0!{I+yq2b56ZQR!Hww|;t~1K$oRF%!^5+uMNfkA2Qa8hgsgb40DT7?+Gi)9S;CD zO((=}#3}M#XTta*>bE)BkXM(5=l$g|?`s7Bz-26~{MF``B`*aE3UcUM4sQ+Q)=QwD z!U(AvLcPOLPOsnCU46tBVY5H{j#s_@wE>Umj;s*)cwdICD7hqw^)_(JttVt(^*S(Z zE19xg&CW_?r}OitTYOTvhVfEj&Gohon+7i{`jZJ8Hm7I4$>Q;7Q%d*|6Ekz+Bwv$? zsHv+xiv$QeJ#@2{5Hvq-{Ah?HeLJXE@2H`!s->oejfE37PlyV`co8+d_d0}33Vd_X zta>-=#iD{}*#ap!Ii#NVpm61-`)V}5pu{uQ8#-02#1IRmmdho`qBMj?R$36J$*58KLxI_;PIw@L9QD?XoSO%K@ocY&VsLJCb2L%jH{ zNl0f3=jSlErQ@;~y+Qe+`a43y@i>LpXCs+Nz!~8uPBJ!5BX+PN{xGFdI2y^P}?|BMX^TMs=-dRbZia300N4%Fm12yQ) zf(l(S8N92aEuC<&j1*^s-)})_V!8K`<+R&)pW8p9`(QHNQ-TzkH*$jXHwp@hZxnQ2 z(6^PLg6T!jUUt-P^cXJcWrjF3M@eiYWuIK!3x?veS-s|@w@rz{$ZpUm;=u2urs|0j zWT0bWVqh?Prf2vDE*tSi5f-M&GX|~+K8+}Yx#eDbYL&knHMtj#BFI<3Cmk)(wN!_R zKC_WIkx_h|*TAwy+MJ-Wm7u&qTI!%7A5)W&?3G;P<1>DWNF?x~A(yG_c5nERL3!R6 zq=Jc!4kK@m0m`3K`JyRF=fV{&Zz%C6&yNAHkRQ8Raht)zq4#r^&hc7pOXJbE ztD&pOTfb-=MC+{Uulbfpel~l5H9A8d3TY;j|K)8M*(;~(CLqP_BL=x&LKB0 z!?iID6>4>=T`||A3VmHrveJT}2jZbzuw!M~L_d7^5Qs^~)FZrv(9K%Y_Z1iCcQj%( zt>*ZKNWzRph%tu!j$^KexzM(l1>q?CUY>E|M}BB!LOL1mTAUZT2bb)C9Z)gh4r^F&Xb<0)Lu0 zo)QGSGRgRk5cLXNcn`bH$dTdk*IQ;5kd-`r?r%5~+4jl{4fQ-bHQ?uMn4PrFD=d7Q z8~+vqf9Iy_Zl$+Ec933!8XXJgWU-9{(WuP}NMOg$iKpX`sEt}I2438w0!{o5%Z(Xp zt*_^UGmCG?H>TzWXN!noq>%9)AG&uUBk2xFO`gkpg<4X~G71ZO?i%lhNZ%|%T_%Kf z*~7dxVHCNUOlEPsk4A)<&l z?REpfn@rGt=AVFfz6dsbun|73zS)_2?0TWe|{`R{bWWAFD8MaNdf{8K9o?cX76&`nevnPE(H3;!4-)MpY$6 z5l7ed9$u(q=XN%QGdTx^q0r50)RDh1R~$sy_d9O;Dm8CKP=EM4%g_I%1t7zJyf}+4 zq!vTlSCl1B(2U^^ghl8+Nk)z-(&#XIF`Gvjk~1rw$4wRZxHztn!6j#&Vd$bu#W!Fx zKINd;-IX47B(dty7eJGFk{qK&z(*+i0~a&ha$)zQiKDRvR2bR7IvEF}4VVhAY2HR~ zR~gPt)(eIDxE^_386cB4olhzJd3v+;o1 z{}lidNK;dZROpYDNQT@r4r^W*2{SV*U+~w9XO+XLZH9BTTC5KizQCxdsSB-pO(F}T@M7x3VL$VFV6i<>I!mnxUxbjiuA9!u$$=* zm0jI1ki4zaEv96>`w}Fya2?7q?REm+^1red;^&*Uke#!Hks**m>;^T-YyGm{p`)fp zOdQBhKe^HSKJT*7=?~0S*4-q+PjgS^Q;BMJ*}B~pxj6=m=&}Td)=Ro5 zbhq0+)k5nov=AlZk7&YViDVNcmZ>0n$#&=Nee2XX{F8tx`vd3q+L^?+#H{&ay&3pX|p*TMqI8}R-0qk=@+-1W7Rq}4$NNX6uw{=6sS{HL%w=j zrG9}17mADLh?wV%BW0(HEK|g2vse(-h~pp2FuE@jTZIu z2g{_wS(|SY$LE)-?9BPZHRB|U5isW9^LW!mGE+f@~F;k%v3Mt9g zbyeef0{?kr2v)Fs72-KRzgiX{j(5?kp@+r|jE=@c#n_pdz5lVwMpY}{kGTk$jHM1F z_yr#o)dVi>^gLt9XWr3_w@IR&@6DtvXvR5}SBym45Q4_+#}pFGtZi4ofu+3qqQ1W7 zqvK%kPiOzgDP)S0HnhF74K__J{0-Thek2DUf5U8Vlx~Ljdtpk#dNIDKGhA&^$Pm6W z?Zo5XNlTCbOhvb#mZT2ib${mzC`>bdo3DPOr6SAueVi?Gz32Bwz)zc zI7`Ppscl8DJA#S7x?LOe~*8M`0B_)K3lLBMTO1} zr}mkODEav)*BI-dwydgS?>Vr8dHZJI-9S(4h|h(Q7m1t5CZjLN2;C#Iv9Y1tBue@x zE=&ss?}!>zo1q+ll*qZ@;q+c-yM&Z_hq$y}G>pm6ncnl-FfAKBzO_2KwN}dRPpd+Y zxWutx<(#(C?LTO3&2BmTPRNKMLEDw79=eBU+Nr;QtBrJdNvO?wGGl|jT9*E<#;7_t zIQWj#w*v-FQcBV#i;98fw(SnyoZ4K#M&8NEiFX|2G0(UhVfK+1DvHY3{G6l6AaZB2 zAJM>2uD?{z=3oLfWIHq4)08m$F}Pj?lH zp8L?i5HEKfF@FuKZ7`(m`sNloggUNF`mf5&yOTkJG&sz?^C%8<2u67?or~Qz4?G^N zT#p(w415@ON)zHIqWjtYYO18nMct$}etum?fg=1qd zk2@BCNl;j6vE)cI76!5gftQrQX^*hvVZ3g*Li^q9-&%j5P9)lK<0kOH{^&ELc3DSC z1E-l~sHbnQS&&GxTk@r`aRnKHGd`Z24HEyN7n_9@40Ui?xrLhYvg;>LPr<1<4&-^2 zno~YJjEsbbR);()nk;OJ)U>HK;Bw0X4L{EUxBH~F+3?j>MSg*IA%zD6a z9Jr>ZPTVPbjJ}w*NIE}-mbNz#Mv-E7d47q|XB#0sF zhf`(0fo`~wOCVsfA6_XypYrlau2~_dvf{Od%`EXcL|WPILp>Fv0O5+VF#+T{Rw>K` z%C;cL1_`(y5+Qnkp6N%L6pw1fie05jT_B;sm_uhC+SZHxcz`Ps^8TY_R4!KLtSBpM z-gmWKUxJ4rtA$H_OTP5+4lIc1c?XWV+RlFK*`H<(6;r6PU0wM)(V}7s!T5imNMst#477}=%HeZ3sPv%@ZjpH87LcQ*&nxp~Q5`VaA;ps||2E}x zg6GnYr`j70b>^aMKBJde-2_awT+D*Np;1F-xdslBW2`d>C@?vzN!OH z2Sl79`O9i*9D&s{QoTR7m<$6X!f!|Z8>b=tLM`sr(;2hr&C!`Iqgt=yf`*APKq*^AIJEJ2}UWThQ&M%Q2>1x-v-Gw@~pBF=dp8DSL zeQ-*~-OlOiePSXtbH{taL8K@!tDUpu>4FiwllWf*OYH*Ms*HL`MoKE$f#a!My?-O?Y3VM4hCUf*CEG! z0a+@L63_y5pO)|LJFCU!&sHp(9Zclfm{smLq(wACX09>YsF~?Corb`DIx$Cdl=wuH zYH|6;ZVodYU8D0eswN+ZDaw*j*8?Ztn|#wKXIoESwt)cy<0HC@aUN8`B!IB+Mzh!2 z?Q9(NgXK|$8Wc%|wG|Hb z2Za$gnGMvYk6k&OE{E?w3o&DTz#2rB<>TWcVPz0VCYIj&Y*JN)%g#qm27XETh8j1rwdwwv)8c~q5l}SF1;gmoo0mGiDjBAzur-1VlvIjw_pEi?) zA|)cf#lXJo4$64!=U8gU7_}pLFa0Jbo2kYGadGiE+}+~7KDpz37vu8H8bnQq)e~8< z_J@iunvR$#^@(hZWGq(FRQhWm<#ylAnIYZj3(%R4jNO2}AX!i2)Y;Jy8oUoP)x@h4L)TVu^j z>T8wkB@J~3SPvadZY^dMyQ&iKlh2>i6f$}HrdknwLExD&t+TJcqvyR{UWtUJ3>ewi zgYw(ktJEtJ!zdlr{bV!=9ODy2!Iit#hYJ;Z_GV5OsR(h=%ehkO;g_{Wb#C+YacZ@=XY9X(Th;7?hAwqi@8XH?%k$?5T$0FIADv|E? zrxewMSkp%iKIZafTVyv@CYEmtj0c7d_-hiCh;7`pZLPOX(f)SWC}dei`ktJ9(f{5$ zpYtKp+a$W%5m_GAY`72@X4X!oA9h=ZU}u{!`kPis+c9Tg;M2Fao%yB){PE?2_NyQ9 zb3mdy0_9Nohh z`<^P8|I!5?@6@u{8Uw1QrEdYg;xkiIo1U_fvW4Y;IO4h|HfWH>Y0v2^6TsgNj1$+6 zENSH&)eZ^~kzAM_YKGZI4v~(HHXa*8IzGNdtx+9kW=^K813~I49!G3HtKA zvOgUn?w|QE>+~q)+qv!9UtIg0#3edr$>WM&Ni!OcepBGLk@CFdO{GixeE7Il63gb| zU^6BX*eJW!GJhn=*O3LP=98kX?!zA(8?=)(8VU+z{|1l|8BZ6c<`m2_(e`w$1zy!! zzvvbiqDIhQ){69!-ziSgLJm(4{`LVDBT{pvd_QX8+Vic@>3#YYmAQpQ zEZCzXjAXO*PJJJgA8)w4bau=HzO&l#AS{WX1qx(rWMs4NGcNvmyYXBAu0^q|EIm8> z)GB{d!j&iRag+sgAoDk=B?dDVby@Xzc|=4UUN^UZG=xJ0mA)Qs2SJHt)b{GdqIfrT zDqT1(uwODB#Ko7n3UBlZu&G4hd6$<=TMHB9IEbe-1A!*--2s_bPNqD$CKzYSuH#p_ zxt|KSECvtg6#1`fH4_ZucrdnM;5d7dLB_S)@L);SGPhqg)p+$`(-}W_S6Q& zX*ShbiNFBlnV2C=?KYy@ZGV9{260296 z3#u!GoK|F1REZ6ilc>)T%B-yF@R$k&G%EEQbYxXAu8|6q;E2<{vQ#w9+N6~bMrhyIP@$xRuKimz1wQ@biJC{s zL@ThEDC|j3$aL=9Ic=V958F;eQH;6r-u%>SdMdhy*4EcplXEQiS)~=rflA+t${>-V zLJ0{D*DHeG;BAUMJ2ya*3~r7mO2~Q!i4h+1@Dkm$_a6D>h5Al)^zK-o!|NM5ZH_jM z8?2KW;eUA`7CXe;_T|V5ID+i;_peH2uqVIgb)jAyWU{IZwhuAeHyn@v zB0jNWRPuec82rF}|83~4cH?5x*~9?ibk$lbF(#(e1DW)DsgT|Z>DQ0OpG&7?MWGXt zM2V5@8-?IwuSqx)P3z|?Tkg<^g%B0UjO!_EQi5V&P>+`^2d+|cT-g`6?1x6c9v;lR zAmJkAjLD?TIPZWjXiZ_zuZ^rfI5C+dW*8_De+@l7`&W__@w__0s)znox0|F|h!3;X zbRosiYtAf!3Ti(e=tZQw&VPpI$r@k&{4oK!e_;D5Detibms~cvZXTl4lC6T&MEbP; ziHIwaJr=5<<2E+&-`#8;FWirt82`AJ_;m@<`JV7Uv{NthVd9?TJXg3t0jIm3aJ8bJ ztJxd*&Qw0e4phFy*B=&dq1IP`S_-lrwDE~%iiHZ9v8};ee zbrN9$Hn3*}(eD!^$Yq2A?^j`9CkJB4d||w(fp$>p4Y!{BUYw1$pAIeb4?7)989X*_ zP4hkyVm`2zgo9fXCBx_vU%0!;2eG@u9F5KK7)9gx70Fx580h{1U-t-?a=72952`7j zsDs2C(f<-D|NAY-x44*nu~7)!((&50d3k~5mgl)G%)%1;Z;*m>(QjXA(h?QHZj7}MojV@qkG8NX!lm->G#5!S z9-fjk23$;RY#fYybeO*toi+%pl&y*9CQ}JFW{FgvMIKD!#HYS$6)r7?9yN- zr8s<-n;mbWuDha+^@;M5QbkY`xi4G5L8oJ2VxnULmBP5#=-3z*2h?IRWMqNXh+@`g zDw5~TQMJr6=W@ZR%mM7_mb>s4U{R$elRW9ADCf5Zd;il0( z6oK>$CLIj6ELakdH3L%U+v6esKVJABlx{vRS72@svR|M%FQ zObmq#VAk2pjE&+Vct}?o7Zzv3#1E-g`CBv%$ss`$^=$E%>W8-{e+D{4UEo_XQ9H>x#N;s@fXM^~L1GSz(c;Q}5W5v2Q|PKYR^Fpn-S5_OqSi4 zYlFw3quO}+O$)v$h6YALYd~1(S)ieFJRB5UMAz10R>nh6Li-{8t;m!46BHTgn5o6g zOHrAbQBh8(UjO@gaI5{nJ8}G1Ohs8h>K44mvrH8tmb*^k(l z+F}Vk&;Y(-pPHglXz>A;-rN1?J$b#XiQ47B#dK^ozsL3VqAFI&-kzzp{`R~t>Jz`& z4Ar-!PSeNnBdYCn3qV}L$K`~YIR3eAGHQnd3J zwE}j>5w`;x%9|4OLTtd=-&JLYpusfWIUi90)e}kVkn92xG(nw&o18CRrT$wB2|b9@ z^C{WcE-#li*Vm+G)2&fazqFtM_$D&;Gpay+Y6_(B$vZh9CuOay4zTrT0lI?a2JRmn zh^QGmJ%HB0XM(=>e}Xam=s?=RU8z$mD=M1jaX0p_499CD#f`Dq-I;n5bk+cRJ%X|e z2+Oy2BTLs@tfHs8M&dl#;sh!F~Z14pc zWoA~Bvf!Jck9Rh&Pku1D1<;4=SBJ!;<>mF{)j>Lijef^Rf92#cj>WJk0pvt!>;BV} z5NirlRuob#n)`bcpuIuyFX_hF8&LRwB+aO;o>Ks&U>Mj{x*tu+N+@cossgj0UXXpN z|8A>EUVG~g7TtEP6ksgfiT4XZelkm_Sy@SGuDJ|$zi@M_m^~nZ3-t=`jno7Xnk5d{ zN(0VV>{&7h4lyw?F%l9CNuS0IT9M|p)?^h3c!E>M#`>CriZimZh~8qFm~@1NNoNVV z(9=cj}!0 zpAv!d&9}yufPOB+lFB6D(bCci<-tDX7o;GN%ls^DAx6$^t0F=-3R2==D;XRt@%#jh zN+N*BC#o3+vfUv}G@D=!R?KZlv#ce=QzqcCmgxrf4x>6NMwjYu!B35sxrrPoMO}Shn--|IK3(}$ z4?=V(TwG30KlalcK-mh|KzZNySWz6M3%2{E+sDM^+~@XJ@T}aKIM@hz_n=Ea3*k`r z{xLza4vL>R|J|?L;dM5e-6-W>bc2g6o8|gx?|p=b?|DdvLu+f44AfGCok5Pw1N8O5 zq}$p^nF{0t8?c4XgLneY1J{mt&Pp3)F!At=emRci`M2%A_3XzTc~O>>wE~o9O_T4W z{_Yw;gw78Z+oqq2Du8CZ$4l6HPUh6v-1jAP>a8&FrPcf541ZZ{ft6lL0Bhau#)x}x zbl~husX<~YjRKIuwelOi&KGI&S0Yf=lf&g^@=>g7ZuOB-2A2r)A;Jw41%bEpCXRRk z)d7WgabN&JcvYZfRImB-qZ@?Ye0kATv%4z}CgwLvv6W7E>n;EhR4vyMbE0TUb`rg; z7drihzq4GLdJo!@w|7ubZh+JIv~f`fwnbOATADZ@XIu2fva5*w2AqAu=9~9pzC$?< z$EE?scQb!bm#bmD`D6X}@5sca=2obr4X7t@wV4XZdw^>ADPz630%@PyB0z}%t4j_E zRDY9GV*b)~aNFFkD#dQG4OP}FNqP3ZS@>y(_ldRKcf(?{i9@<*a{tiU;X_ks&RC$A zGbrD9_V&nScUkjsFe;x44A*NhaRU3v5gByN^B`}e(92+R8vxS`3$zk+OnIX=FZ)9c zebr(nI#3+K5(-E7B3^= zH(c;{d?Ax}<83OA-*tY)o0^ew;>VFL^ybH>iPqU3JtU8)9oz+VKX2y?fv0${@gC;= z_NLHsKDj)&GAiyK`*RJZ)j=v<+F6PFR8yj~{87J9<{8ArgF(*Td`^hd5mH4xI4FhE z|LitKsM*zofr>_Dku_W7&6j!&9Gwnl#J7?R=iKg})-6sh!)6?ywa%|-(QZL(L+}l0 zWR6S!9SFg=^aw01pRPBBmBoLW(a_Xl)&n0g(1J0oNU4K=aBG*E*LBK@~97J`Q5muZ%oJ+L@O&2AXJc)E92#`9(%qVT0HrqY(m8F}C?9eL zg3e#=&Q?wL0C!Y2SE=8}yTAIsw1D@PGYw}>9;AY(agifKV{G=HIBNn}L5?pH4;MFw z&HU-!iYY=@#c`n!|BCFL`4gSz_+Sw2xS{VeI9La;No7Wmx4!T66W&-5C#JYxjX^i+ zP)ov=q>Sc|P+$C-W1_^pQcLhgn3OF+JqwaUC@;l=_dp{Q;A3RWELYUf)Yxdqj!(ND z*$PW-$ZZWK`brB_7&F#ZRv@ZFJ)&fj2tIX%Pms8O7OD(?EeR~$|8QO- zfg+bX2XZ=}QrE9r03Yd}4e5yN1yUyo30C$NNEVomJ1Vx&w|$!O0(bZdc%Smt0QdPj zi<}tyM4%dt-m1)z`;$)4$Fv-zLUz$Vd#r|&LJtN@_3d}(Y|;cvgb*vHZ{;6u4pB+H zIe2-mZ$qTx4QOHr`1u#6JQ^Iwu2UV>B&AYZ1&x38DUEsu)ED>6IhL?o&P5Pug2y7* z&aA0HzqbZ2g1ncKjzeb7XM*lt>NH8?M*DM~%tI9F$#4dl!@AeB!;Sp7$4?n&H~R+v zVbt<)vQ>l;g(0Mj?d`A9%Kn#jUCIG3$Lv@bp4rl0GUYlTTF{7s_#qU;%&=B0$#l}7 zqNT*epU!_w6aG4-$|MtD$r6-VQYK!2eqb?ZY5Me6*O}?(-Wbtx^{QwRmHnx)G$Y!; z=f?Z@d^$RwuVT*szS> z$@B&hk&x{p!7B6tXj9LeV>((ZqFf{rHiIyewKpUQn=$>sZ`E^O*MBQf1m)J5vGc}q z#6WzOX5&8gbJU4|r-rj!)V_%S;Zu;oD|83uA`I8K!urTq25Ly_+y9N6%sbyG3YU`q zM^38ceY^#TrpdDLeu1;gRpUAt3JTY&axNi0ejx5*{n>eJ8~lMmzjCgK&#|a_G>sV+ zfkg*pqNtzvR!nFR>rL6Q{3L?1|bJaan;q)D{2N5 zAv7-!1mFHZqUcdbSZ-Y%03)(`Nef zo>yMJ1S8dFJMtFqXVkXz#EfR^XWV8pNW^a6{nhJn7)y3$c_5UK4R=SS^bS0o7 z52_-`&aBM@$e(o{pijDZFPO=%U30qs2W2;$4DJxI}Aw4xELzd?P zFe?599|Yr$?JCQ3;SBMcPxBWXj#$E_f*zs{z9ytFxIhJyr+AU@0-w^{PT=;_WczR_ z;;ZJMD+)^fT8NbHLc@WGD{_P^j?&}3PI{?zUcT5foNFBnuj4(8G;8kv1$~-dmGd?* z>s`SR2u|-ZncT)AAtMPpUc+cg0!uJM%{tz~Yvrwx*pKfvCsxbjz&RB4PILr`xdU3L z7-d~@jJ$XHP4*mZ6N-=Am1WKgO?T+yn-7VYiLSg23f}JE1XWl!1V|5rk z4)*1q#lGW@Cg4>IQc`^5#S}$+JRJ4$o*pZwAHNb^4x^+2T03e0GQ#%$C31=-Khw<> zx}dn4GZGzhtPE%hWn)wI#=1tiSq@}NKW%`NDr?dIK9eV5Ka075pI2cfZNJPr)X<5D2v}%t z1$;{np>UqyJK~6N&1-rIcvy~T=xABxpW#w=i(T)p!-iK7?N?irJ<@r280Bqk_2(+D zj&~|n;0;@yp?zgFGy?_NUQ3y-vIB5s?erQ7e>a>Z-$>P%U{}uDuWSn2xgPTvy(&{7 zGtXZ7$BYaG%bK|&6X)={^Ijc5i;EzYMQE|;E zIkBo0{>D^)`4O$1NJ1p1u_N#CG-%wXcPVBjS6p5_#OtHrw5Q*BksY(~(Vui0YU&tD z8j+6U-ht6gBJ30pcM&GqsH}t2nd$kU1s88`J=ZgFUeX(GU5Hm7>z>XxG!K9ZExbl; zuqA=`lCTl%bTmQYZ_tlwOUm!f{sFJ_@Q)_HtIQ9YYj4=V!60tciB1PDYAzJrJ+q`m z|3 zI^t+V`gTN$Y&lJ78ZkyoTe^=UjD!+ zsX~K9di@BLxv%0o~X)X zd}FmbHMttX^{%Nd^Nn4E|M5!}AL;uLI8Bapy36LB?#p@OcE8trKMot+<{(F_l?eo4 zGpwb}xLl$2ACF`U6{SY`6$OeBSV@UP@+tB0GRmzb)z!b56aV|inwTsiHqcQ0j_Q$u z;~{vsy?fdJKCvcGC3!0P^V~zXCYXnd9&OnnDVyfuMZjr6Hv}g*8f$N@wvAwyTK+d^ z_RD{u*?a5n8e3CqR-lss+lOr71gWI?FJo4R@9MmW@zA}hO2Kr9EFuL(x8oTzQO1do z=TAA8IMQRjxTvW!MbVB7u6KQkHBZ}uKFP{N@Bo=gDj2JaPq}E{tF~^rvm{5E|FNXw+Wn-mEQ8TeFYlR4!F75o9O>_BAVtkguW6jrO z9Is+kO-*`vPzEqd1L{n^;b3Z5c$|s^ci)}(IDoOaC(Hltkgr@yR)MaCvbX%FQ9|>Z zr=NX_>GdAVa3;$9F0SjKJ)lz=kjRao@2cI2tJOnNQW7+wl>5HMi43Mzi>X^M2hMeX zhJu*RcNNt(rPc6f0v7-yExmzm_kG?uR)LWLr3MVT|Hh(Y=XDeM| zA^~fM?I~*ZR%F|;Bj1$4>NA89njcwSRdHY4QF5)bn{NRyJ+pY-sRo;IQNN$UgV+dF7Tu=Il=J5C=$ri0V$*>w0so{S0P=k_MQS$?-*zWE}*O!zNV!6P~0 za&m(HJq&W1gfntUU-frQ>gsE^`POSH-O^Vp%99?naZ=sQp*4Sgiz;!jh*1I1b}ZkxmN4zDBELj$CN3rV-Os}OwJJEolWzF2zqXjnSC{TGFC4=}?CGCoKrg@sX9h(-Xx@@{(!EI@ z3>QOKJv+=8f@eDQkTOdAv$2`z;LuutUFx*;?lRvR3pR{h{srijL_V8J=|cQAFzkC& zkk+WDh?ZTN{Cgd;pw8O+>|$dkp)EPL3wP6Hf!~UytnDi{&KSvRi8{ZVHEiI2a9?_4 zq$nR%Vt)w#BG5sq!yYjA%Kd$N0d}oo_zTGWx78Y0e#K}00ZL9lD~*XPq)>VI`Ndty z?=~OT9VG~d9nh5nbcMaNi>KlF+Ea5sZ}%ON(Af&NcMJiD8sCIqRoua8ifKCEJ1ZLfdrg`ZAd@af1@6k0 zs3<9;QF-X>eoc*JaF+$&pgX^%+~s66xDJ`$pq7Xk&E<NiWprgqMPmqSDJNHF4|~37$yI^6>wY4o))&0G$C!fm0jjYbR^0q}BTDaj}*J z8~GYpJT44ZbV+?NeKAB*nyG{hr_)k?Hu7)0bD$h;{5KDq0{-^dHSh8Ivg$KS2cw=W zGZ}Gu^zU+2=d3h2U6>`O2!c#MpO5Y9pC%45q&PyZucmgmDo;{y<{Z}kagX(RO^!_? zGc%P*gpK+1aE@i!tNQz+Z?qX}<;j!bSM8YkbvTx5=ipq5xa~nVt@!vyR&sLGzWk$x z)5OsT<($e7`rPv`AU&+x;Cz0ArlP48e2I!&cs=mOzWc5Epx72P($~1$_CQoPDYM7_ zr3H|=bOD6x`(mTrRz?w3P)PP@o6Vjli#!zgQT;F4OgLgIOLcaf>HjjjtPsb0#(W-b z_QM8R>`}%e#xo7t4OuHIr1|je2)9~Wj%#v=U!b$ z%6)lhJZw63zFk2DB_^gFi;Eu?b-9RVIy}4>ziNhf7z*Q6ukA0_5%$`bcTG1rZ_R<+ zL2vKZ;4EKD9?J*Z&V#@4n=GNr_yW#!E^O3TTYYB7`Cq=c;_;*+>FRV)aWS9t$}6+y z+pEiS@GT}@_z9M<2Y+*0EhcuIL~^gDDUPYuZ^=$dWu&1voLR!SW@P@7XI(ml{_fMf zWN#1V8SM(jy)qi9h@$^b0PRyoAO{+;%Octt?@}r6IBg6dHlW%?r4#u>v@}%heMkvC zy(KuOKHrb3!&bw}llj){df0hgzuNkk7u-Wqy%yLXlk?h4DM8gW>~(qE3*tUgQG-)M z*Si-Sd#PirI$nWW=2xBvh$J@NNUU@5lfoLRs*^zlw6bWKHVvl>i@LWbI^V`St=Y}H zKb;PPX1b~DCDLw}od>&5_lbCzM6ck;;*Y1WlUVpTt35r9!KSj|A&yiY80R~~tdeRn zpB4^LUZJBg{u=V)W^Aks3IkcjZBH2K?;aUHqQC8g3EUO*f7$D29uJIl2CDAj$`(Cd zPRi`>`Iy8)Cg-25-+9!UmW&An9LPF|2SEh?uAG@i8)IS@%Q)*-&V$Z#^?n!$S$jhb zXYdJKaNSFcF}j?5BN+x7QRj-VHv91i!IIU`JQfxXzrp%>7uZr0w+{Ul+}Gcnv3&@Z z(;U`$nW&TZK!M16s>vkm&bYlP%{2}_C+tcfGo`;doD4i(XfHuBMW%Nr@36me_bx;K zbnUFbC=m$X?EIWEG!g~-m)ml4XbavQ^!L1%eBbQme$@A&F%_aD*ep4{o3IRd-@YJg zIc1a_AD84}m=BRu#78MYkF&wj{p)h08{YU!vhk!rjq43w-x3s&g`TIfmcxqNcz|-C z_V8GC6i3cT>~7}`?jVBnV17VRND(NugK%iNSJw1 z#rag=aVEddM++_7J91+`d>%I~Rn?o4lOX3nQ>v{@kF^yJx+&2~@B0NSpi09@E8bTV z)NV~;-SNHAb{vr(fysFRu~3F}F{q(6;M6!W4fRmb+&%)1xv@lAyj;<*fhtHblKy>8 z$NAF^xiKC!uEpn7!eV*pR1g_UQ1py09?3#`;RR~>7v$@%sUydtYEh-UO@Ou~3K6a|i)al_7GP=B*1#MV`#YMC<)NLRK z?)*IGz_M>Z4bHXLe`PbCT1X(n+Ek-=cl!I(TM;%qFCO*I`aT{hcD2?NjTg2rmI#WA zh<8_(Lmog$>;)|j>jC>muRkms#wzvr#fKF@xas)mJO+gGb6Om6Zq)`vP&AtJl3p78 z&1tnQQOd{dn-Jz?;O!tv zp$bgf+paF#-M3JcQz=R-s{F!1mJR>uo?%F?2fngg_fHGt^Nh_#WR$6t`_Zu+>o7|4 z1>nWcgnad#=rvHLrUQ^k1&S)w<>?R=3AohM)X09Z#nZD2t`qTlm$#}qsQhViI}`C$ zc?HdmGqW@1=7nM$1|4n=pr8uyqB9N8&h2l8Wa)B)GZYIJDmMH2X#gPJkiytO)j)05Hm~L^W1AtF=q&bDB#?4@$ypFuhh42am|2Y z$_+|ZR*%aO&|miN2@AtF`h{fy*b!%M_&M?m38%BKxQSYC6e0K`6AJj=SUT`a6JGy? z_}_!$GlEGiSKQ6UGXgGGV86xd@-Hoa&`C+rY7+m7d;yyC z{~wN?AQ+sP0Da3}4Qi1<)sdjT zacair&!8dr$Fl(6u`Dp=DpFV+U99l1erGfpNhrqr7sV&P|FQK8G>v;d#DOALX#qWH zAH7Hn3=E*|-tD%f&chom5b>Ahwthbz^NU#VMvjd9l9-TE{K1Ba5k&F-y;d$55#2=4 zcD#l8hyM0k2pF<~>m&m2AJz%HE*U5{O&l&R9E8yDFyJ;67Z>g9;gzz@K}-M7#rUgu zKbA#O4`cDQ9X(a{~z)Ku)36MqQ6RC_uBXDwO@d?6M*R%v(W|NHlldR5}( zVE`|sUpJ71CRXgwXGqLW(i}gZ}S{6D@X{}AkDm2OuBh7d! zyFZpHUE%-v3~HfXTum=uWM}UL;GzKUqixNp=|b-xRsJmEWft&2hWjP_&o~GFW4Z!p zXc&KJ7}_hr7ocweoe`8zPR@GgI{Ea%$7A6a=7cUqe~g4LfEDEZLPw)D^??I!;~w7t zaCr|9SAF!nRHS?q1FnSo>%Ct_1QerO_*cJsPBxaY?^??0L&L+e^3tb|ST=hHJ&_Q)gFxYuE%nMg0{V7MEq;H$ zWMF_qyJ04m#~SeWm(V-6xiTiNgd; z)l2~nd1RvX=;!)}LpMSRJ);Z>@xGel#U@|@x6KXwr1^<$OffPjY;UYgcaA7H1WZV4 zWoXpvDKs^cPlEcvwX*QHwr?Q2yX3RDol%qlP*+j}oS3h}Y3cjH?W8n7pH&UpkdCgn zsOZhj-u> zLcXl)yAfVcStNH1SS|33FiT%+QdXsf`f&{SK<1%)pTj!Kb(5 zP0=@Mu~b{(%PPduZwG8tN7`9f*GIF^7$FfpOzw^L2LLRjyr+&tG-VB*g)EibH^4)2 zQv+Z!73z_43ywZDIZxc}j)1c*R`vOnILu{J(uXKPNn7+ERLV$3lxR|lsc;C0I8z&( zXcBetmDbxv1tNMZUx#hZse7>r5ew35-{LT{Lt_@P1AsQr3)pyIOX0r2W^tx};sBwF zrHSZTlW1oyzz}`a*zi?-l~(eqAXjadfsuPn_^b ztdwc-@gDojepyjt{{EBzSC*m8v%6~+tBv^~lFRPt8z@AaGq{TJDU>2M`LB7giFdSi zY;S}?3aqBn=3gkDx&HR{-a*LE)~gW=$9MPt%LF?7-wAZ53iT=Cwyf9fmbQU`{a@?k zQFL@8Y`G})G4Gz=l5l70O*Y8;|Iq?o)e+3bW=*{chvuQHsM-0U4%9_vy?!B{v?mIE zFl7T-xIF!YcS-!fx|i`<#FEX+F&X{uh}$vxMuA9&JcrYZt9;ceReAj9mn$#eFQCSb z?~@sQYH^ElejA!;Auel;-@}nvV`BBZnf!XL=BL%CD~D!qNp=3WLlBgd-LEf?<*a>m z9lCFd$+FiBCMTK)j>-tyC;QI*Nh6FEGR3UH0m5=%@RHJf9vIJA70Fc$+~r!1*+NLY(mQiRgoPo59p6*wX_TmEHHEXVjTM%`wF4Iu*IolV zL7iu0=(dYRprd8SZ?VoSVw{T466SEPWKj?k%Chx^AYLZ2{!6;ezXt}$zIyO$&x&^f z$ReN$Y+3+7m{eZ6S~8Q_U=&;JJ%+!PhL; z=X%d?MFQnL>dk$7prrNSK;mUT$cBpqW;V730lKnnXI2ziTV!VOJQ*)yV6N{t_b=WFkrdO%|0uQHZ(%I zRkpoy1b3R&oTB<9_RX>DaKN!*Y;7;8%{I0z1PDIog$sEu#Mo{m=(LzGJHFTg^jgaIohYdH@bCw zig{S_!?wK(F45R*;?03eCpo#CEWQ>Sb9T7a)aWDdcwK!PMHi|H%pPAu6=?R-2GGfN z-+rQs9<=KHkMF*ts*!=ABDfDLIuK3>)}T0Kf-cHeE>tkkLR5d=M-qfkO4kDWV_qWb zUj_OuhaRz5GDHl_SeJreW2EC5gZ>B!h0M`Z=6L@R=|j<))84-8$%X4>QYSEK6n+Dg zycXxj-sRp9frt2Qf)c_(0z}n6A=^$z5qkH`V8FLOHvFqO+IF#s1$sZyetDFfkukjl z2Hb$sm|Xo`FgFmsZ>R}<<(3y>9E4f; z>u>!9d*nMUu0Z0*4^Y)-<~EY@^5yw1wU+9J@%(9l#vun_rbh^emAGX3MbXA3a1v-4 zN)9Av?wTsKU%V)x*9i8?Y;nag%nwkBJ}RrOCx17!)O(qujqc=@mfj5M1BP}|6KFt` z5Q`}al2kdTMwVt|R${KoEXr(!Xv$7&x&n;d zOgeyA>hB-W(B>@Xt_+9_TXZq)WRihus?LI;XX`)Y0GcEp(P$E3H-5Y6y{@18qhJSn zZ1B68at&3>=(w1Ka&`O!_0^?Jscb?-MP)O3{<;aESTwi=JP&1or{F1PWNxINzm&D9qu1sE1P=y@YdSKrWx?jnxN76C z#+E&-a+tlVSNI(O*Soa8^DoB0juP!I{C9{c(%j5cSlt9jFhv==D=TY05#a63ynnfy zbiQ8Q;Rqon5vx+C1+6;-5|Bm0+UW~teA7csrMz}STPU9dodzN79cqbE=O$8*Tilb} zbX{5p`iCjMva0Ae-g({L5v6+%W4%i0YOtJpbG-c*^{GO*#KUP&+ORhRoXHo7hQpCA zX?398>9o{;XD5eel%ve}z+NDQum|MmB}X4Dy(T$=zH4+?-rB>azWo?hNIR5?55ZG~Dh}~{` z596j{&;cxwU?hbjnBwK6n(#iQN&h@WUEyf4-Z|#hp1#%aMRs8U`)AL1tZ@QknoQ>y zZJXm!_flY_l;GSJ%CGRSut8oXUS8voUQ2?RxKgFPFUEGq^V}JTPKpOobPYrirQYYVc=DE^BWN9smY36heM%g8Px* zy@S&wyID^yLt4QMJXZ@K@7!1)uOSD3I*Uz?%S#(-O19`lRGf*9^n-tPqo8qR11(D# z)ZZmvpHAXNp%^5{JbSa~D}Wx5c0stk%KG{@M|FmF_rQCs+$OAQKMZ1;uJ&}A(mmk3 z(Xx+gwcLt}f%A2-zX&u>{FSSdt2+0389O{hlJJ)Xn{EIq+xF()kl-MmT1Wq|oPcp) z>rLW+`}RNYk))n2pqhY=6GgfhIgllW@bLV^Y!Ar2FG`3DgQ}0?uLKXb1cu7|ibCF( zfq((HBd#~7-ft9+CJv_#gso{ytw>6Wigwz^ zV;dS8z(6GT+PBhgaclUbPUk|;?$4LQ-ouf@)NwsHzQQkMdDl<<{or(r0Gc`azHNE| zT)3+hBQ=CBWZf}$dsy*J!i)BmhmqA(=6|YU%0QNoEeU^L2A^T)9PO7_rYiA{^zbfdG)AQSlhs`#$2dU=;<&7o>ECeA#hu+ z=jc^P(ww zTF*BAlz3hPUT08Qg)K&TYwL^Tx_j%m)tukeD=WXnK4;of7Y4+t2Mh@9*u8sn5XbW{ zk|h=dp<)b>Q^4;N`E`k`IQIktji*nmARLP=r(#YUM~q<6sQ% z6##iUqB`_E9CS1^ll`e`31d#+(C(z52#iP`W;R!qk+`2`Or1;x5;jO!3Zp%}TC#*w z4waOaUTpL9$tb2JXSw_RD3K}PMTS_PlFUXdVBj5>M>)5DxWW15hO5NW4|D~tDeP@G z1%ue0S>iM!;g!V-P%V{htHHwnZbMJEI=2t7fLi*`zoL7Q@j!o=xtN%E+xgwt)S|4C zaBK4m#J6zd(*-+MQpt5x{24-M$O}6u`0my!2P9*kph0aM)cw`L=9Zq}*LURPpEWd+ z;?gj1Ggm=AYQOFnY-%E87Gp8~qz~|o3*d!3v4Czuf5GC+W9kSiQJ}{JeH=Li?JXkj z8CcyH<4WEkPmPULs@KVLOv@3Nlnf0FfPN}aNY&yAmheBRUlj97B7mGcTAn`t%gWTC zs4%-cAu*BU{;>%-slkZVSyj(FFQr5pK$;0t=Jw3Y>1g}AF8w7wfRW!isD$z|(w2lS zew+0Y>lN^=`1E6yG97>)lhFNy>rNHuSr~Q_-5FYWTSz=Ai1*jMUM8$xg z149EMc{OoysWMGYIwX2+YK|C6ph*i%_t>pW;J$Jxm}qpLCsyR->H|2Gp+O!Qz~pxU z&7{tSu@D)6i0^hcg{f}sNLy=)&FhkQwBvUKD3(SU~_D#%3k_D3WDpKl9?~lNWfcta14-zm| zzy`KdoBLKH=_6ytO4UrebcWruSL}s-Eg2dZxenhBfy?c#wtQKNwPq9KZzPdIiA4D? z%IjP>Nc#KgjMN-u0GiEdy>Phy9DHE5^6N6EffZDeuO@&h-6^Mj6Y%hSP5|F}e}LO3 z3KoGxRRvExaJovXv7Dte|3?c*_wjJWAeaCL1kfTX{+1GO=lTv{hWtcCNG(i?j;Bh* z4dvky3d@Oj6%SyN3Wqh?RVBTf`hKVpJV|sy-CeB;xX-S7elhlK2drR7Oq%q3msmjA03!Q8QZ!v8xG%Y(;$stHNUI@&ygx>LpLxjZF1Ba%`UR5d+ z69b_GA+Ry$>bKd_)Z0Ciq4OZiw51Frt%RTQ=iVGXlXw_>f+Q z3LO($rGVjEDfFVaKQnw`cexl&*ZUDgtj&{k=u(%5EwK*+I6ZN(F}kPa(idAu5^yFLX%PKcrNu2ARv{2sqSIkfV$IgS>)4g%S#j zYa53f5}=(FEId(OslfUX?JeV0cs4QCRKCI>mG)9CX!%aJNt|s22-usO2HaQkb8Nt_ zakmU=A%RImZOi}54tYy1zDWrx$wVe^$KtL^(0r5oBS&BPhXV*(Qizr2^McuuD!F|e zP*n}Gsd=E^mb+Hu8Q=HhWu5eW7~%spM4-J6*@0a@3Le%Ks3C;#viMyn3EtiYAakh9 zE&)CVFwYMsm-=1&41m++2;uvyJ!O zW#RELIh~zzlVGHlS>NV-{#!;^XL)d<)VS^);BP7(QgAu@D zs|b^3bTSk6CN|*gOIOKCpMt38j-b8lxnnw@0m`P10ip>kLKql}BEPV)pKLoR$UPo4 zWh{Zj?rRs`Ff=`nVZn!Xa&_uwpepy%>hJoG?FgsC9qFojZg7wD*y@Z2CKwPw)YH=g zt8#Wy_X0;5z;u7GiY;3G(nhGL05_cZq)|Z3k^QJ0@drhoE0suM{jO6k|YLx zy4gXkI{F`bTy(dnjQY5t5ZBc;my>(Q<&^=%e#$|G=X}gt4JvtajFL!f@)Ja=Eum zCm@f;O3Bd7vfnW}+BM1fc4Xw8JI;(#Ozbjj+2?tng)R*Da?RA6axekb!Krhacd-vuO z4M8M=r0(ICcF6~bs+U@<5JtsIS(`<(U+Dr68KoJGu}=k6{-4(dbM^nb6XcPCx%+?BcA{w-BW(tuVg=4(B!xV@6BF zkL82T^*jw#ji$J`xbHP2ZGH`dU2JYeidUG5VOls_uJjLgB! zRg!p&;z6PQTJKz%5v5bmI~Fnb7%m+J2BmK4m3 zo2o(hD1CbRmiay2-ahk2uAa0J!6<_+im!P1>;eddi8nMAg15a^b{*1Df|iw5p$^+}5vha<$L9$0*L80FdgOX@qX{r#&?&sL z$VV%o_p<=i`5hHcs57zr!778azfG7Z88Ryg0}Tre11oFxxuj8#!{r+ODCCe1-M@GY1X9u@37|(yr zqd;!AEM?&>eSao*qZfzW z>`0rPml+@+gt-XLXBolKCUO}xF963hI86IcN0kR7_pHEGZ$^_MP(a_t3Z;M2P*qjc z5PO_cS5WoO*FGD>%YC{Bqdto(uh^ZD%jX5#&70&wLg%}F0p8RCv^N4)2zK%mV^pB< zootO}l#lv>GjKV-G|zdx{T)SajDXMpU2&@?Nn20P{{HSKPIj6WFWRdTy2))uqsE73 zUH*iG81l6YsPA5Pgp$YW8misL`mcicK)g}Wvt}D*bH1LA6_lOWtn`#K?h6@3+sGbV zcT;|(VZ3=K3e^%*adk=n3SO0B2i~;Lqng_WFc)~z19|hn*H|e&_r`E5Ssj# zGTWNnTdMbKFTsK=8Dh?PEcTQ48V!h@KtfeiQv!onjbBC-Hw{S=hTEH<>w}k@N>fK3 zq$uJeUbii%IH5*K$Y$b>fF9~!Wm+O12?adw#wWK4-2jM^&vlE8oV+x*OguH0_7@)y z;34?t|JWUW;&TCH1kf32V3@Bd6BiWXOL+%)UVf3!;PTFCwUq3K08bY<@5y#&H;UUF7#7OLop~W3<>GMP!?GnIQ zU=+%V(-}gTNGVLy3oM9xs1LL;{&S4#(>E!dcZSoVXaaeaMcv=UWTnCN;_|g8!{zK_ zR0tvhA{`q!S^o;`fz+zGpSm)d4(KZe%=``~@?id1-Bn$DIX}|pS6^iHkX=Nzz}fE- z{s~jcVqb~51YG`T`rp!#zVKqAT%lL6T?{_vd70_qKo{RfaVn$nuLArF4e%6U~o;Cq6Z|Mok! z(k0T%LV1EtMJ|N~{{94gGoUo^x6Qvl6hF|@Kzp==>r{Y4sGbs0V*V5pRr1qfZSjTe zuB7y_oKzE(V^hwZkUfH(Vlca?63*hjv(xvo8WGy}grMhzhNRhlR{N)E8u8_>4AyvV z^jhGFpxs1OR#b()q6EXS31@M%&G+Qc$JySbHywzG`{{VWA}>lTiE{V5h=71s9eOo1 zWc|9?Z<;M2PcTF(vnr!X5?2jkz^_g8MG8bLv0&pV`}aDvH8jGM!L^zeGA^hR4Q~qe zy?#r28`8_Get_G_b03pp&=MRv>~-v@x(n}ohN;xz^qoRD`Bv3ze)8QXG+gg`>Ky}Z z$tW@wmXx~>p!@reQ!p?N+t(7%($V{ii@^r?3pgKmKCfYB?8=1`MB;OdO)Sc4%K-p} zh>he9K+ypieRyOfpFZ5*{{~!K04|{zz&GC0WX7ct;-FvNB;U^=s)OD@XJS1A6DHRi zQgazQWQW@32Vd)zwk`*&1qV_V`o^uv?Z17V&rh4leZ_W(Kn3Dfw$iN2F{hcSzw!V0 zPP<|Be6<$_q)5PRfo3F0LeIXYmUyWV+6T`r5uCs(wT$aJpzhdMSo(*C?lIoD-`hT$LN}nn~t*^(GhADx< z+^b*Hh=~<;*Uq=8yI|7Y>OM~R_3PTi#X5-9M4|fKUB7gF^S&o3`K|$M5y1Q}r6H|6 zF}{o=08oSSfTyu82!MWtg@r&$`fSUBj=r{qawXhB2FU3u&o}|4IgOIue;N%R_h4ut zYADGhEfr-+eaJtP1;K!qIoiuUBuv&}Jpqmqy3di(O3dK|_&l{{D6XJ&OW?gu8-zJR zx-)3WLo|AR?Q=nbS9c_Ea{5?QM0q?_4HHCAnNB!cn-2)b%vEhg)IHtZSC%W1SQ9{{ z143x7z8>i8E@NcmY2X3oKP!y}1Hhme7Ik$xuGV87qK{3Baoz6F_j-OsXDX%jR%Y8# z{!7q&t>IzN>14CO&6E7ypCKF}Qbxwdt(HK_mhkuhJ1rVe6)D`EaDJklAkYcMO$4P*HXC53-{`oHlGot4Uk=RHpHlFFT_A9zg*Q8<=RaD& z>&V;J?%#!MB;Q;bL(G{0c6*gYc+9eZ=U*x)!?_k28e|7Gexfp<5UV^BmMW(jp7n_k z0JseTc1ODbJ|I4}r&RVxa582iWr8mL}18xw-7dcdBpzk{_AM z0>Hdn7^r=|X^=m|OG3_)(7Ql8w#I3q2m&NX_UMA(HIdi)MZiHC;n-WiL-O@N zOw**)(fZNR*}%|%hKqW9RqEQa3(?EXKj4SmLbg72%k{f)V}L3KsMl8KJ*J(o)|N)}Xe+3};IHV6Y4cemW{-?My$KX{#7Zp(Lll(fo<5)$#wd+{1Z;X@KVc;O)h;y8Z9E$s^9cntd=)_Fa2r`f$Zf6E4fgj|@>szvqA))HlTuz5S z9Va;oM93Fg@1yh-%IEw0y(13hYGZ-$1U+p%C;#?MC!hivzyExC`3%TLi1YBue=fji zj(T^-a=AB}cxo6xqDaU3`-{Lme#&~|_IKz<0 zsXK0QnGUEs;`eR?2Cf?TJVZAxl+4yqV`+P~n z;`)N4s8W+#Y0TG$*^Nx&5=D{(&!=)*cqRyy_ItnArE{z!E`v?M%7kdJKVFNitb~K} zlQr0*yy>XKj=`5Y-)`{%zu7a#j@A7TSV}IQFYwG-%hNxPq$atxx;?M|Nd=vNCxp7N zR&+P18Bbje>6q6#dSMWtsnq$-a4@%698=W8!@)s~TXT-X!b7xb`!p9b3V8MeRe$Z< zj}$1#OCcj6u&{G*j7{cyrcPbhAN9w@v0-GLM^(H+29>?Jzsr9E<49I40%GW@F%&|v zma)2`^ZJeptKt8)*1+ZRE+qUS-Wv7zOE=RReC9E#>ya_x3ENbaXdD zSuer@Jy*7`FX81|AjXWQ@t~V6>JCBz2{VS8nJl>kx;9#Xj4YU?01JDwc%>lX-I%03 z2A>m@#}cT`fDeV+-QTM|(CNWCj094zuo(dIu)pHRWpewr`VE~{JE-JlJ31aT@`57g z-N~On{K{&JgR4TSF@nB>(Ng>CMFko43L5#k!I`5NjCE`pCRTQVUtWcPPcs)579uY% z75aF^NPVT{EOr5AU7oE+^p2CohZmRFHvm=R7LyvYCec65vMOsm^Elm(;(9p#kv$jpJH^jIKkd|6%Q$GPs z%nc(bB)FJ#4ggR%j~6pfRtQ!V!ppwiFX4glf&DhlV0f|Nt?v-;;+1+XqkSUZK}M?uHMzs(=rBL_}Z z@LXIxtvZ2hzbfcdBdrB%A%6Q~&)aI^{-A6qU`GT~dP^KL(W*ieJ^7F#0F?5)sO+&b z{zf7~84ciTjVTDhE~gWiPoFfwJ#x;bkdvK*n5FW4{e&lXgtkc9-^kq8)6BM}Gv9g7 z^0&2aepD2K_vWYtw9>n|Zx4dL16)kZAK@2(9YZb+$gXpFDWy8n2W#4knh>`PRCH30 z96b;7Zt(UPn;Nuk%>>|BsqB^|Spu<+i2)otAF9+vc|C26Gl{j6w~(VC!RG#wpw)EW z1Dw%eJal8ZOg8iRJm7J)m4&2yPcu^@&I(6KRXE0KqTA+y%4cPh0kA=AW2(jluQ?a1 z1Ac;nV~2;;ci^c*s7MSk9IY}~8BP(EcR1YSDbjs^bOD0?5Rq@7w?^+2)Wnk;5V00O zqM(+*gr1Im>}}tlFRtKf*ads(*FLklid(TVaays`N&(TYWn{I#W5TGX5c_x!9C|U{ zIWdse%fLo z*{zHbAnsrRH}Qk>_!Ae~q@p?|F0S>;F9%?)KeQ~fEK5ZJj?VGLT|g%wm5K2ou>{fG zVW`Q;2{-#gXl%0|I4D`3SXi5>DXEvolXib&T;@NO8j40_@*Lk@@k^y8WMrhJ&9}la+t`NBp0S}k4ob8bmq{b{+5P9-`cpWBxn7L@mq3+yzFcg z8VEn+S!eQGz0JRxejCL69`a3f6J7?C)YKiEAlK6V$IQ%(cJM6_{$$_qyZ^oz$buBU zV$`X6N6%9*zZ)A9lfLll`vp*3efE7WesRc2pb&8B?}^zmR~;Or1wW5KFiWq90Q(kE z+5&KyYspL&8`|}w5iyp5cX1@0S@W|jA1$S-oEnS;BZz9yHvmU9`7b^lm%DFr@l)O1 zZ@yteZoku(k(4EmKFJ47J-#w5ri+To$|4XM;b{!XU6bR>j`sz%u8s32Q>_5c`hkdP zi)gt?O+me|!B6}1XGlwysVPN4Hw(d}LDB``EzgtUPH5x@Q6djcbWkFQ%wc8@TXfkc zo5JjNw+TQ2K3}0~WEL`w1%?L(xa|)vK=A|@3b2KlPhKtAJ*6TQP%zQi9ynY(H|QS= z8x8mT;G~uQa+|}wTByZl3@dR5cqGD+XS6&Eb6G^JW7Mww zx)LD=YDvHpYljY}gPa`{jDm=cB6~;lMj@E!AoiAl3Y^ZZd~?nLS3BRZh&5kdLq`S( zpK9AsF=eKhcnbu0gqPTXr1mRDDfSOKI?F$|-yaJ&Lqae!qZjdti;IDyzG!FXs7`a^ zm$^NfBjTRs1huQHQ@67NabYDTPfvk2Ih3VCj9jV z2aViD6@YI{A`ab9j+VXZi!d}_Z#RR2YdBsHZK9J&Ft@(-LIUb|$5|}_E9=kiNIRmB z7E((o7a38o#0brYMp#G-2Z*&nrdmuGu3XRn(_Z|zVg7pLgj&0%b_vlYP zcZ-R4{Ib8DXAJop9BOK0jLh?=?|2df1$T_0`v3;d#3T#%4OX+>63%=D!i1c*c5SfK zMo|Bbp*hExXKy3Si`~Uo-6CzMg6dUu-DSa!dLbp6kP>QTpmS8)=F@jO>&UK~5HhEo!T0ZkV zBZb}8jZacP++Jj^^;G?6`&YUFsX)i)NRcO{|Ml+fKDe}>C~)VI1$Of%3^2(BGrE^x z#ml6pQMzs!3O_YPu+fc`?5QbTUnU%OURikpP&UckU|<4L=Gj=yEJ{jq=&7j_;^N*A zp>I7dv$Ass-%~0OFQOpd&Ht|b`P~Q#0-|H5=ww@gn3Ae{sDH3_e@s&@*C($=we$K| z2|e3dhktZrfbKa5x?os`mW<5hd78Zq^_c5QQ)8~daW^_Wz1IBvQwTkEv`v5%`>9Te09 z$x74Ge1j+yqc)6qerRFj_dwW0uaUT%>X0%IL`!}TJiNJ^`r~Y2A8Vb)#KfCKTt4Sb zXgNm9$U;7KgkSpyVCOibBALrIBg|G*FkF;G%bi+vBg z@j8)~m*146qbB=myt0_}RUZZ>{-P$XDCk6elqB)|5pqke3^@${M@g}aq*RBY=(J_nrD=g`NcQN}p` z=AXSD7#We#QA}|^*p{}g;3@FyYD8|Bv0gl;xPj^+0J=tGZ>%9Ozm^F4?Av(^CMI@# zyzt~3PUdUptFg%qJT>jCK@u+aQr{S5qYthY_8@2~o+9ArpzFaZIj2M1(ce7XV~t=>9N-#ha~07`}cgL7;;AdKl}4Ug9zT-k)s zgHIGAJwvnIqq2cBZNLe$JFo_iNuGfI?>EAGba{U}GvDXOr$eb$eNm8>kt?8Rx;Q{& zr;_w<;w+CcQY16Y)4>I0fE;CTDsAy92Ja;GI$;pB{&a+b!;}r0cNIS34 z2(yM4NtVt%ukp>yzmk0o{Afw2RcraDmx@k6fR@R-1m}BrSO?*^ty!O>B3-0=4BW(n zdAC=KEP4Js1X%E5DQs0XhZ8EjA`uj}RPVWVhPD$d(>j8v7|4~QG8H2Jurq2e_8%?aJQ_WF^TT|jJ?w&Vpgh0H+pN}X^d!E4mR!koJ7_uqKQ=XC zYOs%;Aa}QFea;qMx9%v}{+;n9gm{b`_Cv2?(q}%qG!8y*od(yZi|g4pO3dS1@@apx zoF&neBwsmy&}k6#@lHy*nS5Obya{@_6i@=b=s^?XoTaO-LdM>wu-}Fk2fyQ4TNxro zSBAo&pTx0Sk2HpDM;^Pic!-Cz`gZ!_juN+cog;Kw^4RB;AWFvC^`Sf}lR=E6)PWv( z$m{8VNr`~~h)ls-?KXE5tIXu;Gu*VK6MjZ^aY+ryNJekkUx=kXzvT7wMC=XxYif{^ zEF}4og4+MUu+UP{M%`+k{JFN)ecsteZu-K?`*#0#_)q{$K**N{Wu>>rIwcp2nF7rl z#~U7x>$}PU&{$n9iVPbGWS^OWeOWtAHMjXZ!f@DZSM*0S`8q8%EVFVEy}CsGfZ>=Izu=bbT zE8f7yg6Zp7lajse9uIx|D*9Kl3@0;v`^c7OWd1O(eS0CT(J2hE-*Ij3vqVI7Gk56NLDtte36MeLCIh`GV$%^sW0&Bqs4wkZU z1Aj*{f-v-%*v)6dvhD}hMQab zhJXN5Jd8>fs2!5=rCC{$YN5UlzS0G835Ig>c<8-dyO__9G{s8!h$wf1XHC2Kan92h zNOMGyzL0)U!AA7VJ-hgCls>x#=^-K>Sq}^uUV7l*U}q0zi@d=!i;6O@ zJy`S)N&w8QZkxNA-dDrvDI7vaG<_peWG_ER!O7gTZmK!lXS1IpscmzzKWTc=zEJ23)p$7ZhaV{^&L2YrOl+Xvr^0 zcyo)Xh6z4g^ZlJB$3v+`eauyajW(~?xR|df#E_|qF5AN!A;W{iT&`b?L#Geh3t;4V zZrEz80*{eTu07n3sq0cCZb&?_q+rCwJAGGe{C=6+Dxvc%p>0}2e#CUf>p<1f=#Mm_ z%!p#P(#u(2Y!Vai$tuX3)mAH-?>_EwLz4oBgjsT_tZ2F+^Nr{1QdDV2>V0w$I&vYF z-@6B*M~NdHEFHzWcPKbGM;?SaJ@nd44_`V(TEUvkWM)D5=0r(Nj)?E07^$yP-{3Sc zp-t2WRoM$S3nUZ766&G{yVs_(WyeC`q+1Ca5CGfr!N(Jk{MQf7(2odkaO1DHwhZE( z{pZ+c2g#!mTtcz=Fnev4f&p z6(k)F2xoY@g!|m65?*j<>(T`$q$BO_7dvJ~6?v zYg%mYrBhNeO+fNmf-E7)4M$!32KCWL<(ZP5lxd1h5T zTJ`hrRc+O$DsmAKu32Q^CpIvS35sG;l7tCxFqe)1#lu8;S?lU*GdC`gLO-|4XdSoT zlw95J4DIDwPL0hLMKePu#X>inxtN&kd+UelA)mcR7e&wRSe=~!+qhnz zx?2jA6?ldZ1+@_4Vv<^D=}sJ((9MT^7R_iSZ{f%z;4v@Oz@gA_fPg_ z#oaxHJ6vW6Wk^}Z=DS6Ah85PrmH&KhT;avWhC1{6j-R!GtGd zZ(in_pM!^z7OlMP+Iy`gTnrpdjGsI3Q$D#gxMaLvES~RM+2${Tj)MFWNJ~$DartCw zB^7jf;fw%5W6Vi#zm-RVq}sx`P(M4*8F&&(gSyj={bc=X<~FCUubc{j#~kX%Odb`kF{z#qNgO^~lfcGgD876d4b>thDreRyOmSKRd-( z9rQSuc;z`I<>kfj)9mHZCVvXgM$_Gk6CyH@?*}zG$;l`ByGw~?Y7mvszkb2;7dnRM zvX?PtdquF|jjrEtf9z+$!v53#a3c1%RHaO<(>|ona2S$aT+S@T7WK$yrnR<)?%wYw ztnMugQp{R3@Kt}&@jg>@_m!XsKQSX@e=OyFjN*F5DUs-syam*H@qN+<6q?zgj$kB(P|JoZ+*n=vslc}1m2 z(r}Iqf~})$Ro=6%_QytvI*-Cy7esvI>{NJ!mcAk)PUX7a4i`lgRe?XYlrE@T`(WBl z5sERLIo61hh8h$jN>yqr`D8wP;;OA!hQSo^g>pa++uZ!?(Y(yG(cvzhr}N7E>@+1W zW|W_vhWc;_JSvA40t2sFs9L9pJ;{ zYjmREV@P5Mfc4F7u3ezLf{s+g@x^{^W^M}~+#iHi!I`m^Ele6yv_io^xpOh@!EqJw zsqwD*>?|1mGz+_VxfN^>kG!}@?vD@fs&M;neZ4-(KriZ8YV(MY-k66wNRq2QHLSFF za`TWkM+X;|xI$5xs*SPf3f%I0op~<=CnO}eo~;sV1#ZE92*-|(JNMf3Q9`py&b`Ly zISRDj+j*KkhsptveRrSP*GqH@%?kgVR%` zboK9AR$5=O>VE%tPm90aA>-w1HNw54rQB+F2F3uie{SAp7!VK;?8wt>VW5HVn2(>2 zKLZ?Ur{pR(fK}&3Hb8yxUH^a35&jV%(DI@_WmOd?7bKwk!&LyA`U<1ew=;x~zfgEw zVZVJl0~tI#!HJEH*86+s0NB^c4gPN3Q8c zPxa>Kri;qJiHZB)dOG70V8_R%=NDwdXOvPWOn>5W?fM|c2ljPgPk|m||3Fxh*(z>9 z)c*W`yN(L{wO{(Dr2SY@}Fch}b1`8ScnVI;uT z30{W-o&dJgh*n)-TXu(TGD0w{g^a?{%F%3DT|oSyd1N8j{IIB)46j7s;Ro*P%5OcK z`=VQm!&_tut>)%5n>Z@+i}Wx|C%QYkn~OtAQu1o-w<1Zvcl>>ZKv?8`FQ3gsn2Yj6 zb>Ovyc~v(oM(Eus4FOPEECTfv}$%5kjPK6-Z!MV{&2!ccdme zHhwuAvTV&^#j9ByYMJcs4)yo<_IaQpBeoG;f2k`-C2qDorR42)oR zn}kC^=*Y+CWL8)HC?z9zd&PKnd0tpdH$Yg3frIYTY&km%Z6znBvDp_{vr{A)*?0Z3 znx$BmVyxLg3*6+nVZ`A9=_fC5HmQG<)+9Nc0 zOA^V;*u^*khR zoYQR4c$Ep`<42{`p9aX#t5pJS_Mom5SXNNMp^p@?#@?Q6^=Ze`#Z=(Vb%Fbre@a1c z0QL@LltAW#yTxH@YLb>sC?zH<;te9aNx)QtgrJI@44k(F12;2zo_AWaZ+S*X_|UeH zfeoS6@>HYd`E(Z9dYhMmoZQzV3>+N1|4kEd!A1JTTkpPM0%gbGh9}b1P2d)xx?ArUWD%d^CwH}`i9}=CPV4L z>iN!c8S1ePD<=3I!DK2>2pC(HMSNpILYkW)7q=z@omy5B^06>+k6CS?$GvR0v!Z}T zwT3$}RzGkVYAmENNvHOQ-4&Ja9U~*u+GZX!85w#^ixJLrl(i|th_+l!jRVsIxBP#! zfOK9*Obi?&es*SYB5kM}NlD4*!i3axm>fCP&mx+dFwIr)rz>PEjO@w(e3lsCvz%{) z1*w+cQ`;}Uzz}X`G&2h!Phwtl1c6*iOM)Z}T6PG+LgY~bBkGNeIj^E5DP7i{>-8N~ z5lLlGlGc0;jGfAg4-M+k*P$R5Au=Bxm+jpSHdZvG|Hj&TM#B|&f4}L1h(wJ}45A0o z%S1PN7e?LSt^4YF;RWN&Ea#kk z_Wta>zh4S6CMKo~L3dh4mh1op;{O}0yaUO(Z{0AwrEQPjn9D2p`5ll*Dew2Ecuj=d zQt^vAS{xki4_FxGv0b0b3;BZJ%aXQ~jQKLa2Xyh%7F+$e0DNkK_e^tt$-}?4G{YCS zKxZWLxcSX$7Kp0ONDTI8(TTzqM5{kc1tucyBOp;7@;KsuQ|wwY*RarH$oHhI#KuD4 z@yyoYVm-m#1rIACFArL6kB?J!6s;zUvVBaU=t+hwGQd)m1G2WHk@O!Cp>Jc%6Q_)+ zYMsC?lj@$QeaIpCnX_g;Do)8dHC;FaE0iiEY|IrZ9YZ68Efa9m%pIBcEUkn(J z_L4@# z(}!Z-xITNM2c%DJZW|)-X>l?DG>E|lD-pa7lab2sv5&a-67uTf8n#t`4{Va`4aK%D zs<`sye}snzN=Li{(Q>~fqKtXgM zf%r#DUt1m9U|T{Z(eG;AUUAFnOFYu#4t-5P;$%DIMR^!?_-!2L^qa}nwF0WgaeAdP zUPqOdxyJRpz4i$RhJK>Iw%ARwn!=jx-^OE$AI;=8P$7 zeQWF6M-XH8?#V_DAdGRU@hy{Nd!qhmd1Y&QbSC~kH^?qIFp~%Z<*hgjmj$CNstD!e z+wz}U3vSQsj2NFZ4P^#FUJ1hiB%*w_utN^>zkDh*|31JRzQX!(&{M?s_~J}9 z@+#nw_I>-~x2ZA_3{36>$JhazPVvQwr7RnH^Dw zd?sQK!zH@%(ZAMAOuq~ zJ;6M`t&TPB{p`No#|caP7I5b*DzBJprn_1C<2|)OEI=QamOchFXA^v?TABC8r|e&o zdc?*BdfLt7KDoE^@8yz==;NHRxcl3f`!#P{&99#vO+UR^yeRTAwQ#~I{y7*MIRi|? z{8fCE`~r4C!AD-)ksLulz!t&E%&dgQaU6jc76q!wODid9D~ro$YeRI2SD${DuWm}C zL^Kh9O6}h>l78Gx7q*y_c|-j7y!T93DmeJlyijk2ik4_SlW*^5i=^`Br5Fugxgok? z3B^xx&qc<7$VsG5Op6aJBl$Pq-7V-(l~wbdzRJ|R@b?J}b`t;mSy`Ebnd|-X6)?Zr z#KZHcB`|cn&VbkwFXMAkiOZhyPkyfERd)_buMgPo~8Ts*= z$&Ca_rh6-CM$oPwxs3TWIImxkTI8)?vsG4w3Xv87`xU{eTm!G<7z-P3f7VTcp%#YBp{(d=NVZ_4REQT#Fx(yE;mfKtYD$EX{ zs;a3BQD)=RrH^Ag=4WJyCEG#$6a4{lgujZJ_;CRJCMP7$*VK)NjnnLW_~atwU2yk9 zgdM|hC!dT@_=mq?iE(i)F5}ik1i5*j7P z*#PdFrG!2K4o2XDBIN@67I8YXoC@yU9T%6_OHDQ|RlGNRiOjK;vm|V46-J0e+uA~6 zLbO@GiK+x`j3*ek)_-_&z-nQS;xFSvx8SriHaLs(S^M)?qxKsef5T8~+P9CosXmWF zR!vMQxw&aA0Jpe~S}Amf=GzeoO(`iu!{^767r9sKKfB`%x2C6^@;6s;?FL1QdW;D#(btYj`^NZ<iecKs{K@qsysw(FxX-dXifCY`p=^ycyg zzVw3EyC`V(yQz51M?|$RJvB@uO`yW>5NtE&vL&mXbRmou^!V7Vm7KJ)%ZM1{6q zvbA*u)w6Z{MLP6uKNE88ae3IZS&~v`Z?iS3uC4sL`HO~zI?y?7uU@Et9;p+?JoviY zctJ)Bx{K?2e%f)?#q<25_UP^_>SRgWf_%Qqx7pc!p$tni^$uK)qS0BX_J3ZsJj7j7 zqUqk}8sno+lBI=CAGaDhjE}2#{GD+)mb=mQ*8?n-i58R>P`}#!W4Sy4`0l72#+z!U zbCzGbu72@?+$egWM_M`T|K*c^xRqL*|H!E6?mhc7X ze#)E5lzDY1WaXovu8%q|zA2-pkaOFKYc%;c7}g?CPxG_#RGCp&tO~5n;8It!k}99* zFY>YS0F3APPfDVuBQQa&=@pyIZq=ka23B|=*H!(Sl zHI`Leg!AYrwG_}C-ZnNj8SSTi_3v|y#{sfPDI`7~ByDE)>Ju$26WlP8CiS2+WUzkG z<5(`*UvO48Or8aBN2j&4HxQJCQvOpfGZa|FD%FR2?5`)AcH5bd1sq@CTKwXHh&8|z z6l8VO)%#0qMzrk=fZi$t2n3{D{^%DI1X}FCIOWIXKrsqYCohq&5PEt?T>^6CgJ^S) z@!-oBQ%yBEre%eN&nG&f|5@#TizYO#wwSbnREoL*i5Mb6!tVsdANQ?FWHlpdWE}FC`_t zPDCtD1F)9cuWg<;$1g=+zASgK#ZKVAIzl!i7LATha9hp@u=8%j(QNrBWcd{zP=!&Dorn2^o z7d(%A!hups-mKUpCjJeEol#y~4O@{BX?#NR%KtI=`g)x34>_$-#~PiRGtndXU(rX zTG@$v^KO5oCqJiv6K_OOn*$8yZ(k0Pkl!=7su`$^AcR}(5Eq{XPCP#*`4Ju}$;!op zFm1Llvo<-+UFnKp^;EaI%C!!>3-G~qni}t8Nl$$0hRl@xkHb1p7+lYfw)mTwnVz1W z{@%@to|6?fG?bEhV@sTn`5P;9f+pub7mV&zHL!n9dqL=Q`4fKzgNhPo93UnoMeKgN z%DsOu=_e$o^zA>BL~Zz@ezHNLcv4Tt7wCC$`>e;19T{zua^F>URn#Ye*e+17_Xw!; zo;bZ*|2%nH@NQ_A<<{vKf__+pc8yMX^xq{RtlD3gH+ksNXZWQ5!vZ$oyWdobw6BK> z0`J8BkKv{NfW9EC|37{N*N@klxOfra?BcxI*3<19mACug5uU4SwcB}I904$dl%L0_ z(MuyGuh$q8dd*~X)ZDBOY-<7gRui5vre-!rKvK4oMkuAE2|N9e*d&`Wp9g^c%AM)M$Q1< z-!_m%9a;VxEe`mPESFyOk>Vsi3nq8pHYG!>vTU`g1hX6osEi&j072zLxx+{#RT>`N zIiNZA=MNybQgfp>reu)z4_AmJ5i2Tq}IY zCb6%t56Pv<&}q@zE{2;}>UVrarX@`>m@Gp?p#E_3tNNs*EYxPC_5u)M+J1A!$aqXP zQ8&HN#cJ4g4VM8_sN1ZD)B#x#q3(&9H)4PqC+DZe&AAd`BK0J34+{JbHLfd1Xy~-q zwWo&L!>7__s&arfhpL?gfT^R~I)F(t;snjuxS}s|AMbI1g&@FyrM9Lv=opaGx3eo| z$3RGB#2_mFa>~DP2feL5@Hir`;CrCT&lG1D(8v=U-{;;M10{%1r!?+>O6Wf z0)ah(%}AZ-IHMNZR)7DGfCt&GQ31IM%R2#EfDwy$;O#5}1FTd}{?KRFqa+d!m-^M^ zfWdEIMFm52oR^hV4k3(t*wWOQ11@(_NNSaQE06!-!{~Co7xuf{iRx-#=L#z%XmgA7 zgT3hl0%}peNgTe_in>>&p&kXl2m?_+4==A|pt~2=l6?h0-8O(37e?Q66h`lo=%u8n z9+{h(+s{<4-EHhq<2z_?7IJllM3di4Tn_*WP;X;YQzcrwEm7KqoJ=Zjc+8QmMb1EB zz-jb>l*RnGl8m1_!1@<`2bR%N@T8W4E)Mo1U;??|-mT~)_hXHS*Xl4;+3!;GP7)~K zvYjDvwxT==2rYEu>GI`LdE*}lsv^VJPA{NFtv&`Vwhu*?{Y0DW=4w;_0;0iE`ufdT zS;m98WR4OyAVV=fKr3~>qdN;hGhiXGY}XD2+$npK!a0)$(1#ozm_3H1CjB&l+BHKiKI5XD z7XC5uLe!Es2Ih`6HDC<_y{auY8rlEClada6>E8JsZQZ8NMlBBw4aduF3`7LxoHdoT z?XIuJ3fUzVBzd^FXee(+1m3#K_s5`w&AKV!FLZUG2}C5OOZ9$-=h)IaJA3KmZLgui zO-6USMrPSLE$BMTbyTp~+b^p!jG*hQn^|EYzNzV?1R}t#vXYjw=c}lKju<&1Y1=AK@{=QxqvY{BuQ#Zxlk2Cdy_=>~c||MT{Xc1eTavp?elvWxQtQ8a?( zTdbX8B3_P1z!mv(8a|IX$??6rGfR)a!$W@aKHct!&6aqI>RFiO@x!FTl0s2pdbbX3 z_a%KfyRT@hCe1kw8DNGj8TV%x6u$0kL%+Y0A{i@clD7tFOfdp>Up=3qYRYB&AZXT{ zRA3=(w()W5@)URE`}g4Lni}*O>~3?-wwuF8^cRdKFdBE0xroVkiQbpDf$RwBaA&cLpQJlOQJi%WPVGPZR1<#kod z!DgR)4nfbLLG{9)KN53R*oLPP|6<0R!^x75HyWc%^H0p>1fXZ6I2;?DALw{m|U?C%%COWj@0o?}PFr&b~MzAYMET$oSt zzfAx^f+`>GHtlV1zh|SRVEgwG!!d_oWnB~%WvGaFLk7EQKO_vn|5dEyK2be;R$N?+ zVCjdZq{g>?mzH9OUi?a^scE(}Fi=v_@%X4J=V*DgUD0>cdJjvNp?Lo)B_yX{Ym@ry z@&ekhX|i10R^1 z&r@CF%NJjRlIEepUjhv!nDao}oHURu$nC~9Ir<=JsJzPM$Ir+FsFdblKBrj1wH^D= zDRxC|&Dr^REU0LT{Fa6m?0t{SJ?RVc!{`7Km|s2nm^8HOVJMv~Whxy-&id_a!d0cK2jPEi{jz%R-rQXD?JirzFN*ZkJ(i+HZ7XCM(kdP)NrK6+k{I z#c1lJEH$|0INRhNk4fIXp#MJZYDTe90AuhSBoVGH=Hx^-a_WY$o{?}S9fRgwj8X12 zbW!0n>6qNicJhk;j5?^C{FGKZCM|GA*n#s=9=o$qaob%ds6ZpH+x)8T04ov~(5c!HaoSaS) z_$QY5-Q{=~@)M;I84UGt(b8UBU~bDc^JT7i1VBDrDNF^5nRe#(tzQPZ6}CnSQ-ypl zeX#S#w+8uxa*uo8@B-Gotvi2aQ!y9uu}eIh&6HHa@{xWJwQrQ1vz@!`cA>$H-c5BU z%<$M~*IU@p%TTFCw1ZiKh}CW`oX27a%9hN`$)wSt8i#JaKp2dOoLKs|m3^pY8u1aW zbi9sznwZ##*@k1wG&;n0AmAk@r{~8f$ii1a--8MXe|LyK)|~`ncFXc^^Rvpg@f}{S zt}pyJ9_>2Y>ic^VXK`b_L-QPUD|c}TNOC#k(I}nFFQYtHQ{#)*r@ZgO^1^d}f(Sz* zGgNOFv0S^5-(l!8aFSK1N2c$6UI12d1NTpZhImE;7HbMNOxCGOB?Axhjl-R_MRPv7 zsZL?7W#=p^B0xIo{6{Ya0*eU3-zZf~=F-Vvg_~?8;sqOKAd-e1FzQKGx$N=9Uz(dW z>8DyziRKanOp%nDgt5_jz1QQ7*#Qj=*TZ(H6UoS9g&q@6UAPY`-b-waXDW@=j7sTr zgdvxQBHp{d?oe`dS_bKrtix#{jN{{5DUrmJ3 z7&kT*^ZFla5~p^7fq}tceTJ+y2L;%@TJdhJ4TH+E2647srOhGRZf-K;u@-zq)fqwh z920F}paGsOju*QP>W4S81K`+DisWR9I?K%R%WGMO<$A|eBs>sv<XEI6C#u@&)jC7Ya%5ZXaR)40Fg3O9m zO&0JxkM5I9<}cmx4ky}i<;gJ8)<#ZDj85YW4A?gvtLNO)sQcQL(77z6mC^jLE5qDy ze?sEDGkb&mf#8D@wUD1>n=1y=q9m`{edgl!Jt9N6RQHj7_XX?C>4+UJf>h1b(OElK zS#jZALsFeF@;lS5winX{?%!0~R424bAv%~*vWQ``wq_@`G_Z51Bmq3GOau1&+Sd2X zwR+ER+UnS$zZ^4?DQa~Zz2Ash_PO}eFphH=^|QDbFaz!VyHBQp$J5dx5=Y=hQ(z~I z`sEsl-)~`LYdZ}i$6O!5u9IN*>gs>qT@UklOr0-dHkTWP97<}B9GqBol)W}a{MZQR zJq`t3OKH+ER*g3n~AydydH+1i;}}R5A91~H=UTPuilW= z>j9ule>@9vajA;V%9?pShC}Vx>7}R+Q9D{%$OsEV`nMY=38!OrHV)Rd*H_n$j{Y5P ztgo*6?XiR-53*lmRE4L;d*)J2&Vi)m^)n2`O6?E3d4zA#)-#Kfi{9ocG!MH5_w8$S zm#P;OT8dEMovEqKuv2atBQQTd3b|S)EAhgaEhZUeT;9^s0yB1yYQ5qw?ju+pxz^qY}o82mhav~R$mC_6IqlpJd;CAbz6#T5HmAfuh7)Awi z5(PXykrk(Z@H1jlg^XUF!|q0o?k`Cj_dfFRF8%i2KJvQ``_O{izTbnPwaI>hy-z|; zIo1`15ip;X0lA`EkKCV-`ZQsvPWl||_(vb@-aUlR>*!)xS}MrR-TnR!gYLYbAoFFv zHp1K%g@=bHg?OueY~LkTSd;C(KdHl9j2qnz9kv8g`1yY}y9&;YymTL$l0Mk2tf@NM z3l;D9e3mEz8oHcD?CwYJ2DAjm%`Vn1U*0H_t+~K|)>MDkFMajh{aX9$f?EiHZhu3mC-f~OiBn_NJj9WaPYwA8(pJbw7x`EatJ!B~VqgWvV8+s2aZ zOtaE1jY_GffZ5%z(P&yLF_m;t%#=3`--m_WE%tZ2TRVhIKMg8X`3r$y-^$Y-x1x!i zvuZx{>n-8!OG;`@1#sHpG`-nzKM)Rg7RFuGOc}1Pa zJ67i5zTtNqy(2@zs-06Kn9Iz;!9(Yd>T#{YgZWW!ObepOhlYmw9kUPL+E5(W)z*w3 zbZ>4p?Qr5hf0@h+b5c=Jk-3=+t3>V(x?Tibu8bbbX80(R$&1DYnWE;l@f)$->guXr zDB(adM0n|}(p)zUo4@8aHlB7*vhL0lPwZ4NDJTDaVTiec3qg3Dl z5^j$Xh~U{HwL+#stS8?Kr`g{7^$ssBjSoQU6n7T&-}8t$r7ajK3Rl_8+cDXH(oMeC z_uu~@jp)wL7y-ZH)k<*x)?a*N+9o?YyS=uBqJ`8RYQxv$1Z?P?w)-~l`NC2Q zB9f#Z@OT^SKiu0vng)k_?+;2U*s{UgX10(G%^rlyeA=!|(6f4llaGKt)u9NBZj`T{75 zM!;ob*w--EjX+f{ zUwL~=)l?fi->@J%C|LGVPaBmfQYGwb>w4RkCtZi>Nj}8%jhmxqM=*?L{jN_@dM)jf@#OE~U?UB(uOH{3k1tQt;<=Z`Iy&An3A{f}W}-&_t5OlU-)323$oy)$ zF#}p`NZk9$A@L3~YMSr$bj$nvG|I1VyEI_xda)_s%vVUA1v^QDapxY-ez~S+T`%63 zD*eZCdDN1Zl9C+el&0<4XN_@4r??b;adIjDlji!09uZ66ARGu15OBsz_Df2NWv0L1OAJbRH-76bovMz*Zsm| z7hXSdxEd_Nf2I7n*@H;x1y)~}8kZALGw`1`b#+A<*6X8a`m4v8ZUvJLpmb1g30UbA zP$Zf;6s}d|W+w{y4hx`%1uKs@5VO`~oKCit=Vfr0TrVch7=ft|fRCGLEgwHrSFc3> zEZ$2Z+txp*_Al3(7pw^>LP9&ynwCu(R_l=$0v~F8BzU> zGQG$tl1Js|kLVirx)_SJo{@la8I8ZV)wnqy?Qd>6->Ui&Hlktc{)&pJyhaikpD_yO zNutJPb_NEX{Mf{Sm1a$);ikLmq4Zzebn<8FFA(CQ26JtJ!u&0$ZbVa^-|v?UBo44+ zh?ZM~;vL!ub2p>|J39_DQxUr?XFEf|&Tx};Kj~MxFUoY1{|8`T&Rh6veNM)rGMWTi zZ&x=EW1-9`{8p~SXe%3TJ9U|qG;VQpLxr8N$KtJ4LCEi0r(8{IGRU6|47$U$(EBJS zXWK7>Z!@RPNCQS=KGGVPN1TAXwem?7MDIzSbrdv)L+0k^TQHl5vgW(&#`dU8*yb7j za_pa9BIn)EBd6W&$97llb#87RRHF43-3#Aek5y9>Bh*ZlJ<*@cvWG2&={H#(OAW1j2q&fPR%@&HVe9^=RRmPMwBT%A37^^)nRb!mFk zmafHCxYmamo0-n)t~ZElm$+^+GPn5WIZ!PycaH23%IfPc#&t6dEXk$w73AmlFOF-x z4Ht2BJW`Hhg}gMW>A{!n>Gt%xF7~^dtwfrz+EA#da9(V57vz$2GGp9ks=f@Y5=Y5R zd_rIG)bLIs$IR_NSNM*To{_Ng)3pDyw6R&NKU~wY$w>4=Y{5=Rfe&DCj=6~0QQ8yR z5w$)z+@G(wsIV|RKRJUP_JHFuxMv++Mn)bS*q!!q!M(M#;wQCrASQ7P0~=prG7Ik6 zLc1dyYcN2WCSrD@-+7r?=(Bf=6owhqT2o`+!&~I0&x1ED?HYv$y zBH}WR7hnP6`tGL>oxzdu+4xDj2~B_o?bvO~W{T`qC@;d4VfP%sU=uE@Kgm!*trv%~ z|9;aU5;ahOKl@_)^Dss6@$&tAldwXXB@D~WE!>_vS)$Z&{N=S*z`-9rgW+Rb94T8zL4t0HesEc{Kz_(-n);yNp@O)Oc z{2CPH;9nErrfUV6+gT%^RFa6Tci%A4@u<_R(l=PNJ=i}zs~pY{iAhbTqw6#6Yke8= zBnGv7*K*a0LS;%R5QF>N^Oht`edwH7?pWQ+0vZ0Pmkq}74kimjhUj{?;vDA zyDa9{yG+FkF9qL*2Fyj<;^xM|_~dMIx+i*ltn>SI1I}Sv_9`;Y0?DX6ik_RREqmsx z`{!{;)Zrq`a{t#~PCi?%>ZVmdA((YaWcMAkaJM zQHIw$;k>*xG-YUs2B>0|1o=5J>u{GnKKtR}KCNSa9^6nW#0#EX&II7Oe}B}54t%uY-TwZO zUI|0I&M4{i(8=Yg=6R0A1o*a16GwKJg0C zI?%&6GL3+L!cu?iTNJ<4;v`V5_R~7$wm$Umb$ze-9CDQ}C?Lcbk!fjXm-C>-)z!7P zC68F?=szz7VD$g?Qa1gTyM&|cT&F%2F_gNo<90&06>w(qSZNFzts@kP);G@E)?GMT z2!y%CXy09(es{rf6z1V^fl{O%W@OaXx<5r_0!PftGt+Ph|II*cj86{yM;xbRu_V9C z6WDv*d{2U%AYc(>WMvB$lL-mVM!IUH4_XQ@uqkXPTwLz=T$lTlYsaQt=jXAgTqo!m z1p5GJ+TlwptnFUrtn=T)Ft=LmiFwU0b|M;!Bp!P0?C#pyIMh|ty1O|6yHi?@;6CNV zKTUZSf@OVK1 zY-3#vLu2l}`+v^TeU8ZhdXUPLg4GU5js8{PHpu$;=wnCSN<M+=hX+n2F>wz+FOL-+-MRcstfp zmnx3D^pet2P13J-v!v+9f%dHnVY0*x%>54c7e`G^4jJnIR#xIahzWjp+uu2kXsSZw z*9r;K12=MD%9g%>fRM6c`fExO4hP+v37j*RD9V{}c-bIDTTTuZidwjO!I>;;rH5<(jrh0tW19^*IeZf?_)lTD7f!6{X7IVB~B+Y?ihI|Fj2ISxbR zhxX8NS2KMd6IpL>D~OuSz)>(;w}ptRoJ?ZI z$n^K#_XIn^NmDIFl?#)T^tA7!?0fJ5t3Bho&s=>+12ldTdiu%sR`x|KoF2|j5IJ(r zI#J=;{B$w&K4{)Yva@+RBaePM5s9{MCI%8v^ylHDVwMA*k< z$8`Kb=8(7XP*cS;+mAV8b(GTlgQI>!sef$KO3(32iaT5l)Yph=3$QSrg+Q*BZ8EO7_x$sypFIlc62z&SV#zrNJ_p+A!T%}`Yt)a({+c)uv^GEHg=SL`TFk?is_3Q z2@jPr-7}JbkfXVTaBmM=D=YiNGO^#U$AH{6Q^3qiQZoJbBQCQ|eTZDi&=7#vRrNKq zhA9&SWF(-w)w-l3>D;y>KRv@ibbW;Q2lI<_b8IdF5`O^R%;t&IgxAQ?ty9;{8V_ED z-n!d~!er{c1L)d?ls%j(p?))&6tLr%_Pf%CDuicq#zKhBaG#UECWWDQ87}^d^n*0D z)!B~n;1%NF5!((V@u|Cd!H6Md=k^peTtY#NZnwiWl*K<#Xmjp6Zsg;u#TUJ+2jyn} zxuZ&*LUb{;`L{QOC*EG&utRIQLFm5>paddfpOZdsAgemvx{9CJaUtmq?i*M<(XTxr zWCT=){q9eic3tSRW#x2P-wS-;@H?MW*qSs0^(mzb>M(KumuI=REEI~^Us~@QXH-d@ zoSVyD5og3ux3yYkB5%0p@yeKy^TMng>s}*~3fRhbrt4SCv=S z)~feB8sI2KASTm)nNK{!ziQ?ir)QAune0lSck?i9)9p(#XwZei4Qwlyt@o_w=YB}Ydx@zOEh5U$kiNUB(={cCZk61Ue5PKhR3Onzy1O5~Xh`h{+)g=0gA zNH>jIeEbIM(|nj_oJ{I{T~Rq4=^33f_rSH)}qoBGNmmwPytEBzuwy1qo#c8Gb8koX? zAtUT`ertM~xzP_%hNVWbv2`$0X?PlPVsgr>GUn@B;Rqn>8)8C!`NRLPVD9&YrTI5C z7_>*0_Vnz{gBnbD7@KE(?8R`{p%lg7$@?#wOZDr?Q8tm!OsW`3P zgM+SXan^f92t=NmgPqOZ{(i226RBxt-*jkXWaQ>1NniTK1sm29OS<4qESaS1;dGX0^<{@>4cA_@H z^n{<{7j-5CywuqRrF!h&R3i1e5X0v!BqTH$!%^Lc`mRA6hPx|Zn538z8Egh}>#R^`2;WMCbD);1R$Pn~2+Q};# z^8;d$*%CPZ;Qn7Sgg^1l$VQ=x`^C&2t7(hNFL`GIx}Bzu>WhSDk{H&^M&`LC@6Yb@ z7+=v_`+4KY303l4AaOo1{+>&XrhPMy4`2~dcAFKw6t^KC8=C<{+kKKSN3-LOJVXvj zmFRciZ00!|v8OYUQ7N10wFCk&H?k@xQOH~#(KaND&T39&bM9D8Vy8CXK z8zrmbw|66m^nM)V$9TFi`@c z1Lm)Nj;Cl|9?d5tI2kC(Aya3Ttn z(NAxjItUq+xjcKjCVgj%db$;V75crK3t9rx5&kf7!orj@&KlX1jt=ky@UTCxa&XMwz=wy5m)YN>e;NFK8yBbLcTiEK)hs z(y|bBdTG$GNhYb(J2z)Ob~;H<7#qu^bg<*yyfPMe3lus8J<7lMY+8p(O35H{Ks`uI zCG4!Z`l-f5AF46FG-YpQRb#x<4?QSNK5u0=xG4O-VK-D>(jwWvZbitbLX{xUJu2aS zd(*?Pt!%;CJJ5i#Yn3Iwaany7D2Z3lqc9a3NyY1O_-6?hVKMl0+3-W7;~^05ORB>6 zI-|gQehAIAwLQ!zy^5Z$u0n`G;Jr_y!{8DXlo+j*V?Jn*d)d^Nk(Be^ZK`=`8WQ^$ zJ>GURInLQ^YvE7^1odFL>;((+dMupaWUPHG`@Aii&N+OY5>Fuz+a1vJ;y`l($aG1p z6=|&SV6Jv2d^2CHEZj){SKF6?r2phJ@2$cXfcg>i;`#~@<>m;Us&+%`xpD0X%mem} z0cHrmOcc;7+_l~lX=z~?*VK;R*fPfo38pA{f3yH!QxAw0;Pv?D%0UiqiU}U*i+g)<@@)9a0G(QNZ0TZ7;%YrNR%4!6|Ngf ztFzQU&CRXo)6!}j$OndI2IgIzobYk5c?|{L3d!7T0(A&za*S z3%}7M=A~XxQ&UJtfd|Ctv(smB^P3ui92>B8qw|Trr>>I;GRS}B6~6~6adR`R`25dZ zvrQ7`6omm~`?RY%WzISjxAne}<|dk;t7d@o@@R>p`u@&A&bG=IP2ewZ@C`jET1Nl`%Datk=(HYXKnfT;yFM!?1Df5!od3p zdE|d2fUAHQJ$}yVuncsL{sicEs<1!YrlG@bFF!-Fwz)bsAM`wgLII_7ihlVpP9w#E zf$LTy@`;6o)h*bq3inCR^1a0uNnZ?ZPo#WWi*abl!4QqU*8xAK)Tf}K$y*E+r?Z}Z zf4PhSKdt8n-WUG?R9Lvd^Q&hM!_VP?zNPB>xZ1?TCg>z!%@W&PkOua4MqLi|qfPDX z&bHd_ypyjMVVD5}hXX)4@KU$hrzSaB*UnB!S;k9RTG!h<^^vjhbI5~Wcp0BBof|zm zH#s~twV=Smb-(wu(+S<@e=6veo}<=lYm1&b#~~D!f~qBusqYqr)fwHEJTi{1{{`~@ zS5{D(FT}cbqmw!fyBrf{XCEp(q^{az*LGw|Ow`Ku&+nMo12VrL+|LM8eT)%rl2>*P76E*u`3tt%`z@?e zJr3~D|6yY`M6ARO`S@I>Dv9D6g*q(r)T)@d3ZS4dPM=4sU_VIS2X~r zQTyCI0?K3-c?I0lN)>8h*B-95UB?e_@25{fe*UC6SffzYRl7N9awv>?dH3LAbAPo6 z^Ki(~1HY_vxU{ix_Z*R=LM_VndchPT_yM?Ho!rhG9i6SMtYZUXodEEHYsIJ_@3H#} zoA7afgpUu}JDz%0I(7{YY-eBj=OMMti~n9yzXs0{NLnDUDzN(P&d_zfbco5Zl>bHh?Eeo7NEHQS@b$Qr!qtX?Wul{_BPkhJkfdYkTD;$hX9NCv4&O2x;^j>^C`qiO zStp?+zaJAWV}1Mz>@^q!(P(OF>Q_*(v9XC4r_NfsdmI2HU2{{){9Y~pg)7RdNek-@ z>S-VDOAbRd%yX49*$I)!P%T}1i!ItCIs3|ae%}-LXD)B7o}Nr}%nc#r6ta7GnD}&^ zM40>JENVHXq(H1`}%1J4Qvk|Gmczf>%#ABKL8@EgNUOy zZE6t*b4d*dWaWf9noD$-ktYI{ew2Z!g%5U@clRiukshVz8&k+-H`TlvaEF)aJLAnY zi$9yppPK;w+x6=zH+6au@5Rf6fNxS*I|Ukqv5lfY2-P#xW?>-P!QRExJgbKj2y_=HCWZ!j zd&t#l+P0Qce3aQ40F3{l^O@)=P-wv!Ti(8I6Ca&Vc$14_zCaOd0X z+(ZpEL$3?dNkL zNXA#pkPg`MXej%x+0W2&C6z@@vFIh>XtL#oy;Dmn9XYWGg>%{fEOO?G!UQVC5KBJ(?ul}F-PTt@r^;E zwNQz<#ihC9gAxgDJHe=(ZspSd1Lz`jAwnR%=D7PlUh%YC0lQnoW6nf1THL{hUvY&f3V+vO=|zw;ZAY%n4_$ei>^(GJN| zovfcCDJomvmL@rY_CPz9rWyoZPG8L?<$Ya%)A7hT@%>|yv)7-ee|%{r3sUH_?pnvL3Az0Izrd5mQxyOK5kVcw%KDAu;curM1)z->3dc(f_pXX^LqrjkBwB z-E800x*RP$1DM3qWt-<{&+6ES_vP-(r5}PQ2^KqFV31j=`TKIUjr3^ueJcnvFudI2 z@@ww)W0fw;GAw_Q2b4mt8cwO;!n<4gm_qZ9mR4QxZw!OXo54|;M=eBC!jeRE_N#`h2Wp|Z|@p$CKo=H9B5cHiN zU8-3>+Z0*6sQuoK(2W{L=wSMC;I%;MXE~%RT;)H*nM{sHI2-BGLQLdh<6&au?$hyc zF%cuZlN=0i0Ax}Y7BZQ?88kUy+k-CwNyLv;O-+*YL`6IHz*X!9M6MT;552JnruO)NsP&{` zYJU_DJf$^--HNG`EgmJtcg6F2pAOH-Tj4#JD3O3dshpGNhFMH;%#S_ZxYTbjiY2~v zYu9+Pj%`TPyj8b2SGq$dOi@lDiMMQV@Wpa2tI?|L!x-TuC6B{{cBk+~io!2>B|Mhx zrIqh{c@{WI%WBDkEFMDfkC2ZOCIx@pp=RKwX5M>bQ1--xmm5TE%$Eat6uUbS-FHZ> zD?k7tIJz*d{vf6OBR2#BA%yL#I+=d^R%;@#iW$u8js?oVK8DTDNJ9&{HJm~@#L;nV zZ-R;#C%#Q~Jlw|##!qc6&B{u&9QhM!VQ-vnW-rNIa1TC?<_y zOD&)r%%xpf$egU?P|D$LZi~p`?;r95+W))J{@K9&!^?jHnyJh93q7>?rCv#3Rt>x< zl$|o&6Z{p`wM$qbXD4V(SGo?A zfw(N77$o~0E-HoW{uUp!wFil=SJ>lItFTts7gM1Hzz9lxKe6b0%!BoeJei(eVjlP$ zY-3G?XeQSl9vP?t+&u#uHF=Dv=gNC|%q6ytN^h@`(NTF4g*}96+plH9J(Th3^$Rzd zW|=bENnwr2Vq#)lT}sfhfe~_ny|r;?5F+9zuw%2f&WyQ7Dz95qT<+}T9+SxhRL0|~ zh$DALfzyc~u)}XJ<~}5Hw6){jljTk5!^!;$1@n;X**wUY(z?qI(rgi#Q> zvVkO)1#eotMchk-zkdc01@AJY+eDsz?pl^$XJh9#=H_IAn1zh5+^1Syxo;tcnQT-dES8_an7^$bsK{Jq7%ADMw_W6Z99o?fP=D}XjB=cnMM(`udS^S%My@T0V>3>%C)W}tq;V8CMUm5e#^-(l`DVt zhtgyL+uM%|nVHMQo>m{{n6UK``sPoKQP0#_j04`wXhz56)cU687T2U_f9;x(vh_v> z$HgJFBBNRt?59fWic-2QtO@3H%{{np1l5|r#=r)ikOO`G5ASWn|Kz7`rPm?bh1XZL zfeX%*eB|`})i9t5+THbaEjqU)4udNXdKZ;xbOJKKgL4kDozn%(Qvof>FsD;QAkNON zy+eUyoQL(Cqo4pY+JAlqfa9wR7me|Hz=ol$KY{|rt=BvPc5(td;tmJ|qfFD&*8W&; zvW4@3IQQh4iw~ANtDM|afOUp{hqU9-KxV^t2D2EDt%do-7?R$am{l`WC z=M$48>in2(7M$A6hit7xb+ggMa9%H`s>O~io7bzh{`5rL$W7>;B zz>w!;bR?oB^5Tb2AQb_hn_UL4@vyFmiMG1W>56=p6XZWLiT#*<`oh1r@3rDq;L0?A z4sX`^UgR$?XOQ*>n3Q3?m;5)l*);#_nWpYZ)6Rp)@^Wn+p6x>jHL#N5d&Yl!WJ8HlMUtL|cHaBMrfyo+FD+bCwYx&*;@Z5=si2{y=MH=QVdwb|W>|EsM z=`R6zVViQJiE%L9%g5JRG|?e00rAejAYM$gmI2z-#AICSIw?4KaP`juPrN^T<1bm+ z#ke@zYrH^{2QbK+r{9JOjj&a_l4eb5DoU|}()xByo%uy6lPyCMg1m;>u~FfZwvl6> z+T6gNs(r6@tNE67dn7q|bPr%h zh}OcEm+e+pspfvP2FpF>3x#nNrOgr3U+p~*>^3Sj)Ml>k9`8)eM7K9}DPa&RAJ>xB z8jcNT1;l|3EdLb&f5gt7m)Bm9pMUblTl!{CPjARW0b}Qe^qd{sS_0;J+}{s%~_Qv?aXGk6v`eUAvw@;K;L zzhSiO^79Kg6D2B+^16Vj!>vJ4!q-#tKr6wCm@!e%>xW08X}H=DrwM+eKw@uaM{bO< zDHaSb=Wy)t;fz6H4$CurGMm2uTEnP>EV4Ud+zrCaaq4e=;LWhiU>K`Et|?Ac?5*em zM-lxSb;yAzcrzA2HOyxRZzaz!TIM-gG$%-_8^l$=Is{Ji+VY8&WoAb%@TtS7YxFq7 z*(2xre=XSAl^L0g7~<@omO)9m9;B2ND^VNTVBKx8BC0e#ZfF*I2;>>JRq9ASLmV3{k{!B6nY-> zlaWY=pZCngvI1v!~Syq+caT}MmaP^%}eK8yp_ zAsfIC@6gsqnPT8imf4$2tnW9Mu{p0V(>xeU>%MmLdiYoO*-^`pmslF!M>+g6P5y`K z`+)i?-2p!tAN_@q*K|kj9nUQ0{%Yh#pnl3QD7fkE&xqJc5)on3wNSZ_V)n_Bd9}&s z)P6*|;Q?QL)!kvrV%(c~IUFBh(e)X=;hV%JujW=qmDwZV+oPHuerX5f_Oe^LWBUW? z`4nXI_Itr!Q+ExNsdyzTTm7eO&P)zZ2@h&nhuYG^!NVeb9AXx6H2p=c@%YPM6Qw&= zaW#Xx9i)Wv4||8A=eAvd%5<&E%F0TO?q{U9uCBg(a++c*@%(nCL;d$3bXWHhdiVR3 zhTOAqKVIM3TN!30Bqu_Ed~}Vk(ooPna$>t!uxW@MhX^E43G$J&T|_V?3A+t%9DaiX z-jXb{U%TsbL54J1=aX?eLnxcqH>e(ra zUQ}tNdNSM#A9uVDCQN$>dM?sHM0N6msW}Mb)9nwT z3=#fHNvO=yA0L<_4&6ns$Kh=A2-l|=uJu^>W{Gzw_^C?tMCAsJFIre?M#hl$#2kA~ zGK*!WH)^g~?z_3UlJz*++E%*GB>2AZfOZ3$Jl#OUEFvT^QJCo&%_oq}WR+zXqz44! z^y3L?{<|JGi+LPlJ9B=l%Lr76yGvWReoDV5zg_IlNO)hO)TCVYZ4Qu&gk^s!14_7s za9u#JIL)ZO&jFT{@tT$IF~}mWz}pajWa1kktdw=FxJVXCue-ArZsXXOK?AYN8?%m= zk2iI67}Dnv0w+CN-F9vJi2FP;upB{!`(3>U704Cdt|N( zv!Ai#m7mZr!I>mNocve@-{`wBn=EfC)vk=`h)6_=!!y}L=q6f*I3GP!=(>l|grs-0 z%T<(>#GvvvJ}|dEQLp%mU?9r0U(q~2W5o5VhIwDtn_;lKv8~bQkT6y24Ldq%wJ;SC zxhgGS*4FE>@I3VG6>RJF)?UC`WK zb)>D9w7aL9f`BhU$2jzaxR>(qx=_x5it+-s4dJhLu3cuCycfd?h=)mR-yrEkD zfb8bB=zO_bc9jOUhp}KD;1%GjJ6gyqmIo^$IqydmV9Cs23$E34J(T@KmVw1cF@f8N z-A1lV${3YiDMw*t#BTi!@%hIFu`J=0KmFw_CDF~fd2CVNO8V;WgxOTp%c zuM{t(41ANBuq6_+EQyb!xKBlOfb-#Rmq|2 z)~n>@FfGk!8d7or?wt}e%4tGb>;t2;(mRkIyet(6Zp2fP+f>|kr)D-V24l_0D1~n_ zCwrV_(Z51$++w)lNr09VGN7X9@YmG~r?ev-wk_F|Z`EWA@(Z%BoncYhoBlhCt5%4S6#Ces#J1colROYaTf8K7C1K`ctwlsPIU1 zS6AH`a&IJ$Sao-I*Lm!EE{1CI^YedP3x>XHJO1+Fg{7P&R>VXmEdDvBzbzT82?2zc z2{O!F@|$Tb99~PNIu&CStWv>tj{1LbL8VNFe*~sX2L#|h8pNQ(A0o#gVex)XKJVy~ z%rCOIODpNzQR8AXUY(|vrirj>lH%FJkm#LjtoUY?g76(Wfn^yml^2@42DYWKTc)Y+Q-{#b z7(NKGFQ;_q&xYgtPp%_dfyo}qwfb+8Mh@gPz+RL~oMB+3NvX=ZjE@gvZSgmuQ-o3U znuRkgI6s>TkK<}mG8=PAXDnTR8;@DbNs zbv%;Atqr&6k>bUUF{U%QtP_iRskt*N5}Y(9hmUrtKfr!|S^MKTk=r7>F)C@B^GHu! z2M7Rw8@?VuV2-#TnhkI`s{52oo@TqVJ<(D34D`l4yl~1=BCwwyO847;gs;T{yVS63 z0So`Kv1oGYsbLPYw=V!nz|OKfTcv#;X_t~f{mJ^NZ3l7Bshs2(&_Qn4)KF650DYNg zWSGHSwH4NC5stf(#e$Q2bUh)rf6miMZ%gAUo(9g@>u>HK0#GSAw zG+^(>qB5wDQZM0@C+IrIhYl*n=&vD<-QtVJS8nE<$?I5ktV)w!dj*IKuz;|K9eZ^e zjg^?YI4Ec0$LtYsJbtwt=vw=e$BB0n{&*)jfNK67zp^9f5q3IwqUYq)5WDGndXWR= z&=i!oF7uBTAbnYne5g-3*=H%7>F&+@zqlhHvN^~yT)S}L$tBwVna_9rc`@~1uN1Ba zoPyQ^df@VdyhZuoJtSa)+nbxqQ|gq-YrH)>p+Te$ z$N=8t5E&#RP`A6LPTWB>#bg)ZJKo`P(MRGA5F$i?ROmc4I0_C@#r1(kpz(r#-6PYv zO=}a7AX3k=UtRG9ajK|mEN91{{7bEuu+DQWBU!$1?%+M!!*v?=EIx*KRhVxhYg}r`Qmc5w3bS=r=Xxv882VkT6?AM?v_8VG&Wqe@w}(ZQ^5!WddkGw zi(?2@4%X-~*1!Nw6i-0`7?7})DfVS9Pg+u)eJ*14#5 zqWn#|C=$!9Wak`u&!Yn<6bkIuwoZb+X8FdgfiUT3VJ{pUavig`H@2b;bf4{bJJyVj z_Ye1!Xp7=4fIg=P@*05LleYk86;ejU?u^K;_iO8rb7E<3KPrgv&#=_8tjY`V2JrVd z6;&d^>V!>=?$6=}<9W>kz5{-vpW z)-%$(bDNBcf|{I&dc-@CIIB}GQQV-yLN;*aPZ5#8)+ODlHp=mxrY!FIf{d!l$5W$& z-FPzdba{+e-c|tVr-$78GoAm!n0nrxqzyG;LDc-3%pir4ol^F z@9n3Xh-_rI)MUl9>DECN}hZlh)$Vcjc@)_2}(;0QETp+bQ2{Xv^sX0F0AbtFU#Hs zT_ettTg_V2KAKy@^4U$A$;$z;VH~hz5SJ1_M80^oQ`6J|`a33ns9H1MRZ>jkxF)Z^ zWFIfC(-*7x48)>%ndx~ww@S?e_gJPPmxjX&3JQ|_jvXA_qQ74T2*Px_ z)Y_o7(EvYIr*8WkHAOoj0S>;L7=)O1McqpiQ3pxH7v2VK@)e73a z`W7F-G1J-KxnejIG-8n4E~s?m-~t$eV_2^1}y;-ky^5Jjvc$OWmr(h*X-(W&g-|UA+1v3yVt)Z|e9E<+ewe zJsI2&$eF#q%QbRGWOXC7aUdEcZ-ju~g+)AqvDs>wVoH-HA{J^T7_JKvASck z4t$xlH_6Sl3XpV~x3bQKajDzD|G=Dg2^!d9`U?dFf%{z*!@(0IZp(^Dd?2Qp6?z|d z$b7~IYEP3Q#pY;dQH^o9_T?eh`!0ZPav!I@X6$@6uy6|qt_ZO2VpB(`78)v)lz!2q zA>n3EOy_pmT6%gOywcdOus38n%q-1TtunZOf0c3wX6T()xVIBThs7H=W#4fMumr@v zsMFkZ_iFr28yUIx2y1y6Fih!Oas0BZ7{M;`Weg5~CW#RQD$zd_7DEQHXGcKKoJUir zf~)(!=3}yR97hyeXk&}ES9P-~LWQ`#a*d38YSLpnV3NqqE2?l^E&z#%p=zY!@ z7>8J?$`DuE!gv z#+>N}oo#J;SRLJGkr5@qR6p`S!51~!O|K%6cIFN)**U!*sxZ^yQIwE>v#KqveWJa_ zcOcz>l?fu5{?lt&mkqD#?Qw!>9~i{93NP#_l7%8dJ2t< zAhC)1QlItX;(1LP6#O10!FT2Cr5gIqgHJWFNRFFAa?gGciitZNe6IIZ>~Y~d@sxr| z**HCQP`2__?iP?JEl;gcEEpuypv%;30(+PAzvcjwyVR!=q~TQH}hPs!OxWGgCr3D=D1XG=07M`2zZ94>WiNzNDZpGb`*R&&#%Vx2|Gqruz zobX98EWf>t4Qp#hM_2ojSf%%uIBy!e6RI0G`tE6{SJt>=hj+I&o!p#UoZa>|b_VTp zn;LtN(gTrZl>gLIA{#o6F&m{iF#0{_tD_ z%lLyfDymkb+|})-!-qUj%9ToZ&$d@OVzmGfwR5xXU%XZH!ejbJqG0R;BLr~^VWPO3 z?%|cPii*7?mLmCw;X7#~BV!PyE@g@9!|8&i56YNlB^cT}{}!y&(zC&2_&c?=_KX|u zPlFo42JpkoWz{u@8cPO#8y@&lgFZ_vYPo4lT0~0o(`dhl@$(_yEXd(Bs32AgS7=G zKbv?42BHK|#%d}C5nf@Yf@%`_JL?R8185gpJK7@SU2j~$nmN4Ed|8u~H3XhHznwjr z4u#;TBdZxq)Rs-SL;j9k3>)aNGptVyXa)JMQ+0-Gf2LU|;Z&FlRt0hW zj`ZCmQ+sL%Byq^|`cJp@ea9Qx&>7F@eT zAIkBkncvW>P=O*%St&e8JOaepF!m}A<*xh8crOqF zN>WVUVZF={N?u4n!u_SZH|Dd~e1~cX8!MCz{bt#!xn#?Q+fqeXP&n*Euz;TaN1yHJ z{KpAJVE-=!($%vX8{h@@f=)*o)mIl)XBi|u7T^KpkgEf@rIi=8u*lkX?;M7t_O@OWkR;YbeT@^*uBi9(N*)+vvrJBnE`#R4m6mTAqEPX$TWB^w2V{p&P zfP)xkvnPG%89>tR<%`#;KX0K}U0H`G5UfuDP>aEcJxuJ#2Xhbkr5tjo%#o(jIz zWR<1)dWU9tS(!pE1Sz_@@a2W~Q4^sU6&V$4yw}gAr;TPz1j_)9HCyFR1?&T79$-Iq)*;D`NKc|hOz zm664vO(C7B|CL*OLG8Pjd+*ycWEn!aYD^qW{6>mCp6Xvvn4;gy5eqZD)7w5hFxW5W zml~BZ@HT_Zv9=Vs6L}tTd#@bfpK+wvYl6=^(;xjjI1&TuoanE2po~G5PA6@fgA_!k zxoKHEG5ypWXfZk0r&pWW|Iq>}E*>O}o(x1YC7q~&;@@*T2ag_Y4)Bs?vbHAGvB`3G zoa#SHC=_Ak=$tB=hXmarW>g9{0ICqLx47@A`V(6lhf%a|0b18uXAxj%G5H=AhFfz* z#EhV<2eSHoq7Q<`(I?#JMQge~bNxh5G<_T-@VyDR$WLHM4PY^7hV)v_NQNVNsQ<*o^WYM{W*%CP;i{O+shmRW}u+ILMM8 zw;pgI-j9!qo;&job4sUf0EA zYh1EIAuwh2Ca}()FQflUK{g(UQ);HC_x+|Bj+&uC8VKt2mxHP%XH87&ESDH-y+JL3 z@t2ocpn*b8H#S{N#nG|tVR4SSZ-h$ZW`iC%Hiu^cY?o_y+D#yEG0zp%^@!uE)!lV+ z71)3>8kGLFtDNq^Hs@IlNSOe(ALq0c0Enl4D*d0E;gNr-E6~zfXMVv|L}vSbH^hQwI-Y2XD(SbHC;1r zK03S#AUzUN5(`U16%p80ifqzjE9(cA~Ww-yY1exv!5D35oC+eWW2O2aW1DJ6n`7T2(XF`%p4&ljIY?3H3EJ_`Ev* z42mt@bbi9)XxP(*rhTKxKDukZuM^KOCmr%3LdV_JIb3q|v)Sf+unk|?0MU`p$veOq zfPxAj<9+elcf$^F>lLGm%{oZ!7TG=JgkLcFYPvri8 zKcAy6T-Zolm|lwI^#vV!AzMas^RptXwDM}5cW?6D(BbsEeBnZEx)TfN@tOTP{e_LR zFLGuzL&sML*4+RoFz|Mt#`vsd=$OeiU;Xp4N!=^uLx;_cEnoa$Oq#iDTs+%hmC*Ho zyA$>o>PS;%J{i{Gi`qXHyPKRP{!yD{;xRJT;u*^OO(*e!5eA7Jd31EfUrDiWEG| zuh;9=EhN>UZcqe#jrd#>l&;&9*vItXmTjjFCJMpjg;2+@EU!;ZP8u8QBi!&FKqFlL zcl4|Tr00HT&rry>HSx1Nzv}Eg6%zM$who&LPqi3;><#WncsjHvSnozA`Jdo=ai zUQTLnX7v6aET8GEVwzMlvk9@<{6_^86u9d*wg}fJShW6(I2r8MJ;R@!>_?K9NHshJ zYh$o)2YXu7Bqc~oaN@6C$?1dWh~~B`srhaf`b|wtSn4)|07dz$@2wt$Duw9LI0T{r zBs+!%HTQkj{}q5kplCdY0MlSx2hU^{3$Tnv`S3Dw_zvwUA+b74plOKUhP#_nRIO%g zGFxCuNtzV4@t>rjC1I-)W8J~dy97|X&{P9EIg(JsU7-@I+#gPX1t9<3MHFi5@Dd^5 zfjveZC%nvX1kE_2;J{&A#*MK$L+dSgaPaaCi4%WCIX~16E|+KC9-!XWt`Wwhf%-2k z9i2oV=C!2-hPa15dJJGpkmK818|H`Zjlcd161`!7DiIJ6(KxHrJ6__N3FiXAXg30a zt-{X_IQMrp8$p&mfG?Y7NM-6QVntx$ z#56y9*7RQbnZ54O8+qlp-%&X3-pN5@BRwoIC+t7*t^(5mY zdg_-~XPNqxLP8L53&&P=dR|GdaIdUrAVmN~5M)YOZ0&6ZeC+VrH7(#cg3)IENh563$SUnAFfmoY-fz^2?~5rvwpHBG#k=vP?{Ee$X-K23UhYYe^(tr@GDp>c<i<3sVT(Wb#tn3}BXuxI zm^h1w1|t}lDR9ewyp;q6Ju(c8Fc7gV8_+tb`6hB&{n(8(aKZa6{Lklt#YF>Auj)o? zPDkf&fF`spn$1Iqw%jbQ%jwUGvyJ+ICVDw}$b%bH<0Z2o%8Z%T`(0fhvj4BxodO5& zY6be=j6tD%++tttW5wNPs(6?{sEwIivYi#^M!@W4*art`AQlviWQ>i7f_QBZ31C=Z zjUuygpZzZ)RaskSyJ8IdE(JA9)6LzW;)c)gAA^J1py3;SUN(bR-z0i%@o;uj3)=mw zhX@oKuMgMIY9uF6QQc=!NsJP7Yrrx2ZmikWM@`;qPOu--%^}5(+Z7+3#$_UEq^JwOuISb zN=v~FSt5+^_iqA08HVeMfN$lOzy4f-#-gx29AQatUZ#`_F(MNG-KEsO^2s#<@#)Qq zUr31_sJamYdA7DZacd5Y16%G+FY1^o zmCs$J=4Q9Wa;0;X&j1fH1gr5wkU;-xAG*CQwU}_nZFNcbwL_fWUO$)3wYw(=H?fR@ zY3ue#)Osh{4uG7Ie0f^;sYdryFMhT)`a;td=&Yu`76Hvn6 zg}`T5I<0;j2i*#-N9v1m$oA3Eh32vjL_|L(Tp^dwnRA}FY(Dxc{d@?J5uh}65uSPF z^aYu7L`E~;2iV1J^4qLBn&lb?RU|3?3UW}t2Evf=d-}q+Egy0_zc(ef>D~vJoAFJx`Vk|OlpI#@fuFr=!Gg>_#40HA0i0>6O06 zl)!`SfVPC|Cy(g_D&i?0O!$FgZ7_b;>YBIJFGPTpWc+qhuJQYbgsmQ zLV5^5irlY(IT{x$!#eCy{0UiNq<^j_7H>sQ`xq z45dx<4jt}!hIkTp&uGuI_lL-Ba-QWE$rq6q(~NRqJ_X=3hI6F zZ+wW-1(bSq>^?2VL`9K>K{Vt^99JM;on6fS0q0PCvav1=>Y&F3RFYD^m*yyCy6EfgjM)tIl!V@&6oKvif#rxi&5w@G zd|Oj9p8si5zEnV-2_#-o%ven^kQ40eB_TD3YUM!|>+94r0_%Es8KC&{!X`V_i1X6? z&CYIu5DT}>apb{!F3cJJ9nD#OIa+~L{kOt-5|&jL>_@tf{o!*J*l42JFIS-^^JDr3 zyfpR$6_G?wBafPu>z%7AZroh6BR^CwOnMg`?hE}Hi3N?^Xe64e#+RW<8qw%V5_cK$ zRC+W*Pg8xOmE_ql$}oH@V!Wl!LynTKqc{K2lIprn5c}kf^^PPo{35 zzSH3()og+#^+(hv*TEOz)KIz8tB$pdEk;#W5%13-YXJfGp0Ds9)9{U0LF_o?^7HlQ zm6Gp+98ad2+^_wDaQY(-Gw=_M^ce|(;Ogz=xg5>HuC*2qqN6>A2l&HVuRQrk0EGGH zpMk7sSE$PdJpCb?ot@1e^R=zX0w@zM(TrS49rZ2h4Tw*KO!M-Uot4pYCoqYEtv|n^ z*0fd%vCL4hfqAssJ8iY5$I9G zNNQ?pli>^QO1saHm(ZSM>>MX3VmV!2xl-RDb=-pcOe9xW_QYy%q@oJyc~f^P53l~o&&LNU*T}`BNn;ywkyZMM1w^y&wvw7dcsH>M!0+k40YXy>NJDWD* zcJMQfA2h$duDkotwUZpJKC2#@c+s{_#i3zHmKJVD2<(&EcJ8DFD-8|cMju-XRQM`; zQ9QEI4#NsOKgEzZZOR9v2x08_LG~2GWF}ax6crCmOG}#=;{4jz!PN6&8gh=Dg;7Q^ z@1~EBaYpH#CsI9sCsGr>*~*Y%@)ifI4S^rdCr39Xggee zI}o_8ssmtrxUUXYc8@)Az!D6&J-fP0lO-YFH5b<(2g2vzeV$8X45eoBGgc6>D}DmP zr-*l!Z@^NPE1gOx6a+)5k?=@S8{4p6>58L=_dU0A;6^wvyH7DYnC`fG-CpayT!q!o zJlTGvOEl+C@>dWi`}q@>#4GN(FfN_bx6t3OS>^4euZN4nfSLme6RyJC)bjz2A|50! zOSaV8s69`PAGJN;pB^?PwH6q84dSj{CdaCl(#VVqFh0trReqVCo*dIpOG-*g$nSh{ zQf6IT;y~8Z)6=HibFD|N-fD{o(^%}>)pzmDw=l62Ndp5rEouMYyx_>fxs;NuP|HbQ zt*=kRPw4n^-={mNAK9!g9n4J(DRt|tPu1Nwpz&UirjhU)$-p$xU6mAmonGn&dJgh6 z$c2fBHLN=~H+Q|UQT3>tTw!3edj(7zv2k>YxZ@5$?+WQ7BOy>cHR6Hg+} z_{?^Q@6P_L;sFoHjcZ{52Wek|-nCG1&^?;TH1Jc+Zdo_LC7Fqi^)5af9nzP}vX zk#^}zl)b$A8=_+t#1egLW7~ayE4MJG$_p#0X1aD> z93vr?vQ)@VPb=@fb+)R*)85t&htu!UN90Md;1}G$N}J&mIVB14;tY0mepW+IEeX(I z{mE-wY=#OVe|L0`u6cPMk)x=EZj;Pgg0m?^aW=$g(;v;(eAeY%`R@NH9X! zy!>t|%A~ihvdUufKWI1S6@`yC7=*1eO?ayAd74<{iT^DSDkIG4PvQZ=8*G^@;erdT z9}@Wr9?9h2s?~)H6`-K#!iCRofW7iR@%gP`pu^8j06kQPL|2fK%wg#3@i2oP(wu!3l4xVS{r*21*3GXC%(1QYAD zxBb6#E3zJdUqv4!8r0V~Zzh;#(x*$DfR=1;ke}DSSa%hOSQ{{F1pIwQ6bhQn%*ltG z8X1t6Y}gO{eTxH-U;_NNMq``=z^YHnV2+g2h@@`h{`Vo0nCP(NSRCo?x#{VHWxrE{ zT{Q?>9+>&l{&x{+9)4;fY-8BIav5?iUV{D_r?v>$PoMTTc5?FySU_yl?S-F_Qd!#; zD9TK0Q3e4_aDW6b`omG#4K)ca*2(}1%DItk?x2_i)>zpsQI(HRpIV|q$}Yij22-Me!#Nm0;7D7tEifK#=xFO> z21Zg$TntPog*J>%|}Ln6{X0t;fOE|6eQJpihIl&Qo%UuYx(MMxV&)Z}T5=|*D$ zM(43L?84e%=M7GXp7c*SaID?t761=HrbkY!t#TmwJkK}w?>t{`@{+hGF8_NGG3cp! z=MD5OAj{L06194UlFM>Rr<3l36!-SF(mtK)uo{O`uo3ZmV`lqgY)h4nUt!J7N-6! zG;o^q{|W`-QQaKwId?q|vpYb5O(`zdJ4njgJxL6zSpKY+kP=brzA(pyOcHlbahAB{ zqtlUun8+B@p{WNa+<|(7^JDO`<8R%R0@GL{1Wea|2e6P+y{P4Va2^~#GC4lNMpRW^ zPA6vEq}n;BrnB_A^Xw=|6=BE+^|fdCbow>29u{^E%^gc3J3C5f_lNLn&YYXssht+D zU3%Kg1Lw|C&3;CD!xNn*4tmO?qw!u7pKZ!o6wWv1(LijJ7jbErt7;)!T?egPvEUrY z>~R6`6R2O-?1yRjj`=eKe!Yh>!}Pgs%C8NpKh=M31wpn7Iv!S4h1IF<4kd^XvQ1%l z#EN&Sr$LI+FRQsWzMzT{v2heIvWGx|O~*#ZpysZip>TfkvG}O2n-w~>@QSn@cb|@dzRw9w_U}R+smmFD0L63Wl)n3SSC~C!pg?<-SDvxC*Y#m4A>T9D<(fhg)N;1-?`MNFTcZ zHf)_)R+S42GV^uh2PlU=&YY@3AY_16Br`=IU|CxDAja4Ky-)en8m)}Fh)T(o+)pE) z^!06rX=j|Vgnj<;Ws)$*+zIUQM)lXtkp$kQD2EE$VY&c~Ac<3o<(2LYsZkb)8!7O9aw_1u<>CT_T2Racx(a_E-9(=SWZscN#$(S&QMztnj9d_YqNo_UYlQ7*wQ30Mn&Gk`$nvdC9H zP|j^_nGOjYYE%&=y-nq8SN>l!CFIvLn*6sUK}eL11}3~RXk!RE*a*e8{?~TQuV3&* zVxC3Og$)IXuY2`ve&C%o_20VVd#|VaKDd2o1~7@8 zhBuD?gAYmZ10KIpUQm*gpTB!XnVMqe9ft5tZ%>zE-?^bDUjRHJ6u1lhl)yyssIAW= z{~uTo+Hb2oH+!w_S>S%4XV0E(IyigZk0U=``G$(70>`|8$4Y+McS<$x>GQ8&H>)%k z{W>Ce)7A6w=3RfV%>BFJC@&>ALJs5AMyCbbJ5BF89EJ@~^-%^y`1Dl;5>$ zm+hY;n|Z&M%FdO2_imo-+qc%+>vvZCJbdi+7k(3VZEpq!&i9@!jv-uO>@VGqAMu>N znyJPc*sN)r4&7>S#TC5OU?yy2ltebp4FBrI(c`a;W_en16R^GdsvDIZc=gyuCso(7@ z6!iXn-tP6%1|MQ$!^3|+oF6AW-AL2M=-A!En-?zxpP@eY*|TNLt2SL)pPqj2!-p?c z>;6ZI0;7cg4saqhV*yp$vD9i0kD4Br1aQLM84)#gugfg%i^u6{1-oD!M<=||cl From f68c34f98920c04e43d687eae0e420713020ffc1 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 15:14:28 +0000 Subject: [PATCH 03/28] Share the PATCH handler of per-user game fields Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- server/routes.ts | 87 ++++++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/server/routes.ts b/server/routes.ts index 73dae6408..d7bb26d3d 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -533,6 +533,34 @@ function respondWithZodError(res: Response, error: z.ZodError, message: string): return res.status(400).json({ error: message, details: error.issues }); } +/** + * Builds a handler for a PATCH that sets one per-user field on a game: parses the body with + * `schema`, applies it through `update` (scoped to the authenticated user) and returns the + * updated game, or 404 when the game isn't the user's. + */ +function patchOwnGameField( + schema: z.ZodType, + update: (id: string, userId: string, body: T) => Promise, + labels: { invalid: string; log: string; failure: string } +) { + return async (req: Request, res: Response) => { + try { + const { id } = req.params as { id: string }; + const updatedGame = await update(id, req.user!.id, schema.parse(req.body)); + if (!updatedGame) { + return res.status(404).json({ error: "Game not found" }); + } + return res.json(updatedGame); + } catch (error) { + if (error instanceof z.ZodError) { + return respondWithZodError(res, error, labels.invalid); + } + routesLogger.error({ error }, labels.log); + return res.status(500).json({ error: labels.failure }); + } + }; +} + // Helper to parse category query param which might be string, array, or comma-separated export function parseCategories(input: unknown): string[] | undefined { if (!input) return undefined; @@ -1841,26 +1869,15 @@ export async function registerRoutes(app: Express): Promise { sensitiveEndpointLimiter, sanitizeGameId, validateRequest, - async (req: Request, res: Response) => { - try { - const { id } = req.params as { id: string }; - const userId = req.user!.id; - const { userRating } = updateGameUserRatingSchema.parse(req.body); - - const updatedGame = await storage.updateGameUserRating(id, userId, userRating); - if (!updatedGame) { - return res.status(404).json({ error: "Game not found" }); - } - - return res.json(updatedGame); - } catch (error) { - if (error instanceof z.ZodError) { - return respondWithZodError(res, error, "Invalid user rating data"); - } - routesLogger.error({ error }, "error updating game user rating"); - return res.status(500).json({ error: "Failed to update user rating" }); - } - } + patchOwnGameField( + updateGameUserRatingSchema, + (id, userId, { userRating }) => storage.updateGameUserRating(id, userId, userRating), + { + invalid: "Invalid user rating data", + log: "error updating game user rating", + failure: "Failed to update user rating", + } + ) ); // Set the version of the game the user has installed (free text), or null to clear it. @@ -1870,26 +1887,16 @@ export async function registerRoutes(app: Express): Promise { sensitiveEndpointLimiter, sanitizeGameId, validateRequest, - async (req: Request, res: Response) => { - try { - const { id } = req.params as { id: string }; - const userId = req.user!.id; - const { installedVersion } = updateGameInstalledVersionSchema.parse(req.body); - - const updatedGame = await storage.updateGameInstalledVersion(id, userId, installedVersion); - if (!updatedGame) { - return res.status(404).json({ error: "Game not found" }); - } - - return res.json(updatedGame); - } catch (error) { - if (error instanceof z.ZodError) { - return respondWithZodError(res, error, "Invalid installed version data"); - } - routesLogger.error({ error }, "error updating game installed version"); - return res.status(500).json({ error: "Failed to update installed version" }); - } - } + patchOwnGameField( + updateGameInstalledVersionSchema, + (id, userId, { installedVersion }) => + storage.updateGameInstalledVersion(id, userId, installedVersion), + { + invalid: "Invalid installed version data", + log: "error updating game installed version", + failure: "Failed to update installed version", + } + ) ); // Update the per-game download target, or clear it to use the account default. From 6553acbae634ddf13f1abae0043456be0c5bc15d Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 15:16:28 +0000 Subject: [PATCH 04/28] Address SonarCloud findings on the version helpers Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- .../src/components/InstalledVersionField.tsx | 32 +++++++++++-------- shared/schema.ts | 2 +- shared/version-utils.ts | 14 ++++---- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/client/src/components/InstalledVersionField.tsx b/client/src/components/InstalledVersionField.tsx index e7967a105..004ab27f5 100644 --- a/client/src/components/InstalledVersionField.tsx +++ b/client/src/components/InstalledVersionField.tsx @@ -8,26 +8,32 @@ import { apiRequest } from "@/lib/queryClient"; import { compareVersions, extractVersionFromReleaseName } from "@shared/version-utils"; interface InstalledVersionFieldProps { - gameId: string; - installedVersion: string | null; + readonly gameId: string; + readonly installedVersion: string | null; /** Release names of the game's downloads, mined for version suggestions. */ - releaseNames: string[]; + readonly releaseNames: readonly string[]; } const MAX_SUGGESTIONS = 6; /** Distinct versions found in release names, newest first when they can be compared. */ -export function getVersionSuggestions(releaseNames: string[], current: string | null): string[] { +export function getVersionSuggestions( + releaseNames: readonly string[], + current: string | null +): string[] { const seen = new Map(); for (const name of releaseNames) { const version = extractVersionFromReleaseName(name); if (version && !seen.has(version.toLowerCase())) seen.set(version.toLowerCase(), version); } const currentKey = current?.trim().toLowerCase(); - return Array.from(seen.values()) - .filter((version) => version.toLowerCase() !== currentKey) - .sort((a, b) => compareVersions(b, a) ?? 0) - .slice(0, MAX_SUGGESTIONS); + return ( + Array.from(seen.values()) + .filter((version) => version.toLowerCase() !== currentKey) + // Newest first: compare the right-hand version against the left-hand one. + .sort((left, right) => compareVersions(right, left) ?? 0) + .slice(0, MAX_SUGGESTIONS) + ); } export default function InstalledVersionField({ @@ -72,6 +78,9 @@ export default function InstalledVersionField({ mutation.mutate(next); }; + const showSaved = + !mutation.isPending && mutation.isSuccess && !!draft && draft === (installedVersion ?? ""); + return (

{suggestions.length > 0 && ( diff --git a/shared/schema.ts b/shared/schema.ts index 969b6d202..40bdff14e 100644 --- a/shared/schema.ts +++ b/shared/schema.ts @@ -591,7 +591,7 @@ export const updateGameInstalledVersionSchema = z.object({ .trim() .max(64, "installedVersion must be at most 64 characters") .nullable() - .transform((v) => (v ? v : null)), + .transform((v) => v || null), }); export const insertGameJournalEntrySchema = createInsertSchema(gameJournalEntries, { diff --git a/shared/version-utils.ts b/shared/version-utils.ts index 47deff821..c7d3dc78c 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -20,18 +20,18 @@ const NOT_FOLLOWED_BY_ALNUM = "(?![a-z0-9])"; // "v1.2.3", "v123456", "v1.0.2.34567", "v 1.05" const V_VERSION = new RegExp( - `${NOT_PRECEDED_BY_ALNUM}v\\s?(\\d+(?:\\.\\d+)*)${NOT_FOLLOWED_BY_ALNUM}`, + String.raw`${NOT_PRECEDED_BY_ALNUM}v\s?(\d+(?:\.\d+)*)${NOT_FOLLOWED_BY_ALNUM}`, "i" ); // "Build 12345", "Build.12345", "build_12345" const BUILD_VERSION = new RegExp( - `${NOT_PRECEDED_BY_ALNUM}build[\\s._-]?(\\d+)${NOT_FOLLOWED_BY_ALNUM}`, + String.raw`${NOT_PRECEDED_BY_ALNUM}build[\s._-]?(\d+)${NOT_FOLLOWED_BY_ALNUM}`, "i" ); // "Update.1.05", "Update 2.1.3" -- a dotted number right after "Update" (one dot minimum, so // "Update 2" -- the second update pack -- isn't read as version 2). const UPDATE_VERSION = new RegExp( - `${NOT_PRECEDED_BY_ALNUM}update[\\s._-]v?(\\d+(?:\\.\\d+)+)${NOT_FOLLOWED_BY_ALNUM}`, + String.raw`${NOT_PRECEDED_BY_ALNUM}update[\s._-]v?(\d+(?:\.\d+)+)${NOT_FOLLOWED_BY_ALNUM}`, "i" ); @@ -40,9 +40,9 @@ const UPDATE_VERSION = new RegExp( * "Build 12345"), or null when the name carries none. */ export function extractVersionFromReleaseName(releaseName: string): string | null { - const v = releaseName.match(V_VERSION) ?? releaseName.match(UPDATE_VERSION); + const v = V_VERSION.exec(releaseName) ?? UPDATE_VERSION.exec(releaseName); if (v?.[1]) return `v${v[1]}`; - const build = releaseName.match(BUILD_VERSION); + const build = BUILD_VERSION.exec(releaseName); if (build?.[1]) return `Build ${build[1]}`; return null; } @@ -54,9 +54,9 @@ export function extractVersionFromReleaseName(releaseName: string): string | nul export function parseVersion(input: string | null | undefined): ParsedVersion | null { const trimmed = input?.trim(); if (!trimmed) return null; - const build = trimmed.match(/^build[\s._-]?(\d+)$/i); + const build = /^build[\s._-]?(\d+)$/i.exec(trimmed); if (build?.[1]) return { kind: "build", parts: [Number(build[1])] }; - const version = trimmed.match(/^v?\s?(\d+(?:\.\d+)*)$/i); + const version = /^v?\s?(\d+(?:\.\d+)*)$/i.exec(trimmed); if (version?.[1]) return { kind: "version", parts: version[1].split(".").map(Number) }; return null; } From a62337d9d58fac84f84d000bef258d7c33fd7d71 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 15:23:26 +0000 Subject: [PATCH 05/28] Record the installed version once the files are really in place With post-processing on, the version is now recorded when the import is finalized instead of when the download client reports completion, so a quarantined or failed import doesn't hide later updates. An update's target version wins over the base version also named in the release, and an open game details modal refreshes when a version is recorded. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- client/src/components/GameDetailsModal.tsx | 8 ++ server/__tests__/cron_autosearch.test.ts | 50 +----------- server/__tests__/cron_download_status.test.ts | 42 ++++++++++ server/__tests__/game-version.test.ts | 78 +++++++++++++++++++ server/__tests__/import_manager.test.ts | 36 +++++++++ server/cron.ts | 51 ++---------- server/game-version.ts | 49 ++++++++++++ server/services/ImportManager.ts | 17 ++++ shared/__tests__/version-utils.test.ts | 4 + shared/version-utils.ts | 20 +++-- 10 files changed, 256 insertions(+), 99 deletions(-) create mode 100644 server/__tests__/game-version.test.ts create mode 100644 server/game-version.ts diff --git a/client/src/components/GameDetailsModal.tsx b/client/src/components/GameDetailsModal.tsx index 6e6152be4..99f9c6dec 100644 --- a/client/src/components/GameDetailsModal.tsx +++ b/client/src/components/GameDetailsModal.tsx @@ -595,9 +595,17 @@ export default function GameDetailsModal({ game, open, onOpenChange }: GameDetai queryClient.invalidateQueries({ queryKey: [`/api/games/${game.id}/downloads`] }); } }; + // A finished download can record a newer installed version on the game itself. + const gameHandler = (gameId: string) => { + if (gameId === game.id) { + queryClient.invalidateQueries({ queryKey: ["/api/games"] }); + } + }; socket.on("downloadUpdate", handler); + socket.on("gameUpdated", gameHandler); return () => { socket.off("downloadUpdate", handler); + socket.off("gameUpdated", gameHandler); }; }, [open, game?.id, queryClient]); diff --git a/server/__tests__/cron_autosearch.test.ts b/server/__tests__/cron_autosearch.test.ts index 1e00cfc18..04a122c51 100644 --- a/server/__tests__/cron_autosearch.test.ts +++ b/server/__tests__/cron_autosearch.test.ts @@ -124,8 +124,7 @@ vi.mock("../xrel.js", () => ({ // Import the function under test // We need to use dynamic import or require because of the hoisting of vi.mock -const { checkAutoSearch, categorizeSearchItems, recordVersionFromCompletedDownload } = - await import("../cron.js"); +const { checkAutoSearch, categorizeSearchItems } = await import("../cron.js"); const { igdbLogger } = await import("../logger.js"); describe("Cron - checkAutoSearch", () => { @@ -2375,50 +2374,3 @@ describe("Cron - checkAutoSearch", () => { }); }); }); - -describe("Cron - recordVersionFromCompletedDownload", () => { - beforeEach(() => { - vi.clearAllMocks(); - }); - - it("records the version of a finished full-game download when none is known", async () => { - const recorded = await recordVersionFromCompletedDownload( - { id: "g1", installedVersion: null }, - "Test.Game.v1.2.3-RUNE" - ); - expect(recorded).toBe("v1.2.3"); - expect(mockUpdateGame).toHaveBeenCalledWith("g1", { installedVersion: "v1.2.3" }); - }); - - it("moves the version forward on a newer update", async () => { - await recordVersionFromCompletedDownload( - { id: "g1", installedVersion: "v1.2" }, - "Test.Game.Update.v1.3-RUNE" - ); - expect(mockUpdateGame).toHaveBeenCalledWith("g1", { installedVersion: "v1.3" }); - }); - - it("never moves the version backwards or across numbering schemes", async () => { - await recordVersionFromCompletedDownload( - { id: "g1", installedVersion: "v1.5" }, - "Test.Game.Update.v1.3-RUNE" - ); - await recordVersionFromCompletedDownload( - { id: "g1", installedVersion: "Build 1234" }, - "Test.Game.v1.3-RUNE" - ); - expect(mockUpdateGame).not.toHaveBeenCalled(); - }); - - it("ignores DLC releases and releases without a version", async () => { - await recordVersionFromCompletedDownload( - { id: "g1", installedVersion: null }, - "Test.Game.Season.Pass.DLC.v2.0-RUNE" - ); - await recordVersionFromCompletedDownload( - { id: "g1", installedVersion: null }, - "Test.Game-RUNE" - ); - expect(mockUpdateGame).not.toHaveBeenCalled(); - }); -}); diff --git a/server/__tests__/cron_download_status.test.ts b/server/__tests__/cron_download_status.test.ts index 855da989d..4d85b1692 100644 --- a/server/__tests__/cron_download_status.test.ts +++ b/server/__tests__/cron_download_status.test.ts @@ -32,6 +32,7 @@ const mockAddNotification = vi.fn(); const mockGetUserSettings = vi.fn(); const mockGetImportConfig = vi.fn(); const mockGetDownloadsByGameId = vi.fn(); +const mockUpdateGame = vi.fn(); vi.mock("../storage.js", () => ({ storage: { @@ -44,6 +45,7 @@ vi.mock("../storage.js", () => ({ getUserSettings: mockGetUserSettings, getImportConfig: mockGetImportConfig, getDownloadsByGameId: mockGetDownloadsByGameId, + updateGame: mockUpdateGame, }, })); @@ -471,6 +473,46 @@ describe("Cron - checkDownloadStatus", () => { expect(mockProcessImport).not.toHaveBeenCalled(); }); + it("records the release's version when a download completes with post-processing disabled", async () => { + const versioned = { ...baseDownload, downloadTitle: "Test.Game.v1.4.2-RUNE" }; + mockGetDownloadingGameDownloads.mockResolvedValue([versioned]); + mockGetDownloader.mockResolvedValue(baseDownloader); + mockGetImportConfig.mockResolvedValue({ enablePostProcessing: false }); + mockGetAllDownloads.mockResolvedValue([ + { + id: "SABnzbd_nzo_abc123", + name: versioned.downloadTitle, + status: "completed", + progress: 100, + downloadType: "usenet", + }, + ]); + + await checkDownloadStatus(); + + expect(mockUpdateGame).toHaveBeenCalledWith(versioned.gameId, { installedVersion: "v1.4.2" }); + }); + + it("leaves the version to the import when post-processing is enabled", async () => { + const versioned = { ...baseDownload, downloadTitle: "Test.Game.v1.4.2-RUNE" }; + mockGetDownloadingGameDownloads.mockResolvedValue([versioned]); + mockGetDownloader.mockResolvedValue(baseDownloader); + mockGetImportConfig.mockResolvedValue({ enablePostProcessing: true }); + mockGetAllDownloads.mockResolvedValue([ + { + id: "SABnzbd_nzo_abc123", + name: versioned.downloadTitle, + status: "completed", + progress: 100, + downloadType: "usenet", + }, + ]); + + await checkDownloadStatus(); + + expect(mockUpdateGame).not.toHaveBeenCalled(); + }); + it("should keep a playing game's status when its update download completes", async () => { mockGetGame.mockResolvedValue({ id: "game-1", diff --git a/server/__tests__/game-version.test.ts b/server/__tests__/game-version.test.ts new file mode 100644 index 000000000..19eaf7abc --- /dev/null +++ b/server/__tests__/game-version.test.ts @@ -0,0 +1,78 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; + +vi.mock("../logger.js", () => ({ + logger: { info: vi.fn(), warn: vi.fn() }, +})); +const notifyUser = vi.fn(); +vi.mock("../socket.js", () => ({ notifyUser })); + +const { recordVersionFromCompletedDownload } = await import("../game-version.js"); + +describe("recordVersionFromCompletedDownload", () => { + const updateGame = vi.fn(); + const store = { updateGame }; + + beforeEach(() => { + vi.clearAllMocks(); + updateGame.mockResolvedValue(undefined); + }); + + it("records the version of a finished full-game download when none is known", async () => { + const recorded = await recordVersionFromCompletedDownload( + store, + { id: "g1", installedVersion: null }, + "Test.Game.v1.2.3-RUNE" + ); + expect(recorded).toBe("v1.2.3"); + expect(updateGame).toHaveBeenCalledWith("g1", { installedVersion: "v1.2.3" }); + expect(notifyUser).toHaveBeenCalledWith("gameUpdated", "g1"); + }); + + it("moves the version forward on a newer update", async () => { + await recordVersionFromCompletedDownload( + store, + { id: "g1", installedVersion: "v1.2" }, + "Test.Game.v1.2.Update.v1.3-RUNE" + ); + expect(updateGame).toHaveBeenCalledWith("g1", { installedVersion: "v1.3" }); + }); + + it("never moves the version backwards or across numbering schemes", async () => { + await recordVersionFromCompletedDownload( + store, + { id: "g1", installedVersion: "v1.5" }, + "Test.Game.Update.v1.3-RUNE" + ); + await recordVersionFromCompletedDownload( + store, + { id: "g1", installedVersion: "Build 1234" }, + "Test.Game.v1.3-RUNE" + ); + expect(updateGame).not.toHaveBeenCalled(); + }); + + it("ignores DLC releases and releases without a version", async () => { + await recordVersionFromCompletedDownload( + store, + { id: "g1", installedVersion: null }, + "Test.Game.Season.Pass.DLC.v2.0-RUNE" + ); + await recordVersionFromCompletedDownload( + store, + { id: "g1", installedVersion: null }, + "Test.Game-RUNE" + ); + expect(updateGame).not.toHaveBeenCalled(); + }); + + it("swallows storage failures", async () => { + updateGame.mockRejectedValue(new Error("db down")); + await expect( + recordVersionFromCompletedDownload( + store, + { id: "g1", installedVersion: null }, + "Test.Game.v1.0-RUNE" + ) + ).resolves.toBeNull(); + }); +}); diff --git a/server/__tests__/import_manager.test.ts b/server/__tests__/import_manager.test.ts index 1505e581b..7a2d650e4 100644 --- a/server/__tests__/import_manager.test.ts +++ b/server/__tests__/import_manager.test.ts @@ -324,6 +324,42 @@ describe("ImportManager", () => { ); }); + it("records the release's version on the game once the import is finalized", async () => { + storage.getGameDownload.mockResolvedValue({ + id: "dl-1", + gameId: "g1", + downloaderId: "d1", + downloadTitle: "My.Game.Update.v1.2-RUNE", + }); + storage.getGame.mockResolvedValue({ + id: "g1", + title: "My Game", + userId: "u1", + status: "owned", + platforms: [6], + installedVersion: "v1.1", + }); + storage.getImportConfig.mockResolvedValue({ ...baseConfig, libraryRoot: "/safe/root" }); + + const manager = new ImportManager( + storage as never, // NOSONAR + pathService as never, // NOSONAR + platformService as never, // NOSONAR + archiveService as never // NOSONAR + ); + + await manager.confirmImport("dl-1", { + strategy: "pc", + originalPath: "/downloads/source-folder", + proposedPath: "/safe/root/PC/My Game", + needsReview: false, + transferMode: "move", + }); + + expect(storage.updateGameDownloadStatus).toHaveBeenCalledWith("dl-1", "imported"); + expect(storage.updateGame).toHaveBeenCalledWith("g1", { installedVersion: "v1.2" }); + }); + it.each(["playing", "shelved", "completed"])( "keeps a %s game's status when an import finishes for it", async (status) => { diff --git a/server/cron.ts b/server/cron.ts index 6d9017fee..9480796f0 100644 --- a/server/cron.ts +++ b/server/cron.ts @@ -30,11 +30,8 @@ import { type NotificationPreferences, } from "../shared/schema.js"; import { categorizeDownload } from "../shared/download-categorizer.js"; -import { - compareVersions, - extractVersionFromReleaseName, - isReleasePossiblyNewer, -} from "../shared/version-utils.js"; +import { isReleasePossiblyNewer } from "../shared/version-utils.js"; +import { recordVersionFromCompletedDownload } from "./game-version.js"; import { releaseMatchesGame, normalizeTitle, @@ -150,35 +147,6 @@ export async function getAiAutoDownloadHoldReason( return null; } -/** - * Records the version carried by a finished download's release name (e.g. "v1.2.3") as the - * game's installed version. Only the full game or an update counts (a DLC's version says nothing - * about the base game), and a known version is only ever moved forward: an older or - * incomparable release never overwrites what the user has. Returns the version recorded, if any. - */ -export async function recordVersionFromCompletedDownload( - game: Pick, - downloadTitle: string -): Promise { - const { category } = categorizeDownload(downloadTitle); - if (category !== "main" && category !== "update") return null; - - const detected = extractVersionFromReleaseName(downloadTitle); - if (!detected) return null; - - if (game.installedVersion?.trim()) { - const cmp = compareVersions(detected, game.installedVersion); - if (cmp === null || cmp <= 0) return null; - } - - await storage.updateGame(game.id, { installedVersion: detected }); - igdbLogger.info( - { gameId: game.id, previous: game.installedVersion, installedVersion: detected }, - "Recorded game version from completed download" - ); - return detected; -} - function getAutoSearchRules(downloadRules: string | null): AutoSearchRules { let minSeeders = 0; let sortBy: DownloadSortBy = "seeders"; @@ -945,17 +913,6 @@ export async function checkDownloadStatus() { const gameTitle = game ? game.title : download.downloadTitle; const importConfig = await storage.getImportConfig(game?.userId ?? undefined); - if (game) { - try { - await recordVersionFromCompletedDownload(game, download.downloadTitle); - } catch (error) { - igdbLogger.warn( - { error, gameId: game.id, item: download.downloadTitle }, - "Failed to record game version from completed download" - ); - } - } - let shouldSendCompletionNotification = true; if (importConfig.enablePostProcessing) { @@ -1002,6 +959,10 @@ export async function checkDownloadStatus() { } else { // Update DB - mark as completed await storage.updateGameDownloadStatus(download.id, "completed"); + // With post-processing on, the import records it once the files are in place. + if (game) { + await recordVersionFromCompletedDownload(storage, game, download.downloadTitle); + } // Update Game status to 'owned' (which means we have the files), unless // the user already moved it past that (e.g. an update for a game they're playing). diff --git a/server/game-version.ts b/server/game-version.ts new file mode 100644 index 000000000..1ab69a385 --- /dev/null +++ b/server/game-version.ts @@ -0,0 +1,49 @@ +import type { Game } from "../shared/schema.js"; +import { categorizeDownload } from "../shared/download-categorizer.js"; +import { compareVersions, extractVersionFromReleaseName } from "../shared/version-utils.js"; +import type { IStorage } from "./storage.js"; +import { logger } from "./logger.js"; +import { notifyUser } from "./socket.js"; + +/** + * Records the version carried by an installed download's release name (e.g. "v1.2.3") as the + * game's installed version. Call it once the files are really in place: when the download + * finishes with post-processing off, or when the import is finalized. Only the full game or an + * update counts (a DLC's version says nothing about the base game), and a known version is only + * ever moved forward: an older or incomparable release never overwrites what the user has. + * Never throws, so a failure here can't break the download or import flow. Returns the version + * recorded, if any. + */ +export async function recordVersionFromCompletedDownload( + store: Pick, + game: Pick, + downloadTitle: string +): Promise { + try { + const { category } = categorizeDownload(downloadTitle); + if (category !== "main" && category !== "update") return null; + + const detected = extractVersionFromReleaseName(downloadTitle); + if (!detected) return null; + + if (game.installedVersion?.trim()) { + const cmp = compareVersions(detected, game.installedVersion); + if (cmp === null || cmp <= 0) return null; + } + + await store.updateGame(game.id, { installedVersion: detected }); + logger.info( + { gameId: game.id, previous: game.installedVersion, installedVersion: detected }, + "Recorded game version from completed download" + ); + // Lets an open game details modal refresh the games query, which is otherwise never stale. + notifyUser("gameUpdated", game.id); + return detected; + } catch (error) { + logger.warn( + { error, gameId: game.id, item: downloadTitle }, + "Failed to record game version from completed download" + ); + return null; + } +} diff --git a/server/services/ImportManager.ts b/server/services/ImportManager.ts index cbbe857d3..f8f0ebbaa 100644 --- a/server/services/ImportManager.ts +++ b/server/services/ImportManager.ts @@ -26,6 +26,7 @@ import { logger } from "../logger.js"; import { extractHostnameFromUrl } from "../url-utils.js"; import { isSensitivePath, assertWithinRoots } from "../path-security.js"; import { notifyUser } from "../socket.js"; +import { recordVersionFromCompletedDownload } from "../game-version.js"; import { resolvePrefs } from "../notification-prefs.js"; import { appriseClient } from "../apprise.js"; import { type SecurityScanService, type ScanResult } from "../security-scan.js"; @@ -539,11 +540,27 @@ export class ImportManager { ): Promise { await this.storage.updateGameDownloadStatus(downloadId, "imported"); await this.storage.updateGame(game.id, { libraryPath }); + await this.recordInstalledVersion(downloadId, game); if (game.status !== "owned" && !isUserCuratedGameStatus(game.status)) { await this.storage.updateGameStatus(game.id, { status: "owned" }, { preserveCurated: true }); } } + /** Best-effort: a version that can't be recorded must not fail an import that succeeded. */ + private async recordInstalledVersion( + downloadId: string, + game: NonNullable>> + ): Promise { + try { + const download = await this.storage.getGameDownload(downloadId); + if (download) { + await recordVersionFromCompletedDownload(this.storage, game, download.downloadTitle); + } + } catch (error) { + logger.warn({ error, downloadId }, "[ImportManager] Could not record the installed version"); + } + } + private async verifyLocalPath( downloadId: string, localPath: string, diff --git a/shared/__tests__/version-utils.test.ts b/shared/__tests__/version-utils.test.ts index acb1ff0f8..633eff1e3 100644 --- a/shared/__tests__/version-utils.test.ts +++ b/shared/__tests__/version-utils.test.ts @@ -16,6 +16,10 @@ describe("extractVersionFromReleaseName", () => { ["Starfield.Update.v1.7.29-RUNE", "v1.7.29"], ["Valheim.Build.12345678-P2P", "Build 12345678"], ["Game build_998 Linux", "Build 998"], + ["Game.v1.0.Update.v1.1-RUNE", "v1.1"], // the update's target wins + ["Game.v1.0.Update.v2-RUNE", "v2"], + ["Game.v1.0.to.v1.1.Patch-RUNE", "v1.1"], // highest of several + ["Game.v1.4.Update.Build.5000-RUNE", "v1.4"], ])("finds the version in %s", (name, expected) => { expect(extractVersionFromReleaseName(name)).toBe(expected); }); diff --git a/shared/version-utils.ts b/shared/version-utils.ts index c7d3dc78c..59ec0e9f3 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -23,15 +23,16 @@ const V_VERSION = new RegExp( String.raw`${NOT_PRECEDED_BY_ALNUM}v\s?(\d+(?:\.\d+)*)${NOT_FOLLOWED_BY_ALNUM}`, "i" ); +const V_VERSION_ALL = new RegExp(V_VERSION.source, "gi"); // "Build 12345", "Build.12345", "build_12345" const BUILD_VERSION = new RegExp( String.raw`${NOT_PRECEDED_BY_ALNUM}build[\s._-]?(\d+)${NOT_FOLLOWED_BY_ALNUM}`, "i" ); -// "Update.1.05", "Update 2.1.3" -- a dotted number right after "Update" (one dot minimum, so -// "Update 2" -- the second update pack -- isn't read as version 2). +// "Update.v2", "Update.1.05", "Update 2.1.3" -- a version right after "Update". Without a "v" it +// needs a dot, so "Update 2" (the second update pack) isn't read as version 2. const UPDATE_VERSION = new RegExp( - String.raw`${NOT_PRECEDED_BY_ALNUM}update[\s._-]v?(\d+(?:\.\d+)+)${NOT_FOLLOWED_BY_ALNUM}`, + String.raw`${NOT_PRECEDED_BY_ALNUM}update[\s._-](?:v\s?(\d+(?:\.\d+)*)|(\d+(?:\.\d+)+))${NOT_FOLLOWED_BY_ALNUM}`, "i" ); @@ -40,8 +41,17 @@ const UPDATE_VERSION = new RegExp( * "Build 12345"), or null when the name carries none. */ export function extractVersionFromReleaseName(releaseName: string): string | null { - const v = V_VERSION.exec(releaseName) ?? UPDATE_VERSION.exec(releaseName); - if (v?.[1]) return `v${v[1]}`; + // An update names the version it brings the game to ("Game.v1.0.Update.v1.1"), so that one wins. + const update = UPDATE_VERSION.exec(releaseName); + const updateVersion = update?.[1] ?? update?.[2]; + if (updateVersion) return `v${updateVersion}`; + // Otherwise the highest of the versions named ("Game.v1.0.to.v1.1" brings the game to v1.1). + let best: string | null = null; + for (const match of releaseName.matchAll(V_VERSION_ALL)) { + const candidate = `v${match[1]}`; + if (best === null || (compareVersions(candidate, best) ?? 0) > 0) best = candidate; + } + if (best) return best; const build = BUILD_VERSION.exec(releaseName); if (build?.[1]) return `Build ${build[1]}`; return null; From 88e1c2c8923bf01266aaf5b9dfb31022057bbe3f Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 15:33:09 +0000 Subject: [PATCH 06/28] Re-read the game before recording its version, refresh games app-wide The recorded version is compared against the current row rather than the snapshot loaded when the import started, so a version edited meanwhile is never moved backwards. The games query is refreshed from an app-wide socket listener, so an event received while no details modal is open still lands. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- client/src/App.tsx | 2 + client/src/components/GameDetailsModal.tsx | 8 --- client/src/hooks/use-game-updated-socket.ts | 24 +++++++++ server/__tests__/game-version.test.ts | 58 +++++++-------------- server/cron.ts | 8 +-- server/game-version.ts | 11 ++-- server/services/ImportManager.ts | 2 +- 7 files changed, 59 insertions(+), 54 deletions(-) create mode 100644 client/src/hooks/use-game-updated-socket.ts diff --git a/client/src/App.tsx b/client/src/App.tsx index 35a601971..e986392ff 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -9,6 +9,7 @@ import Header from "@/components/Header"; import MobileBottomNav from "@/components/MobileBottomNav"; import { getPageTitle } from "@/components/navigation-items"; import { useBackgroundNotifications } from "@/hooks/use-background-notifications"; +import { useGameUpdatedSocket } from "@/hooks/use-game-updated-socket"; import { AuthProvider } from "@/lib/auth"; import { Suspense, lazy, useEffect, useLayoutEffect, useRef } from "react"; import LoadingFallback from "@/components/LoadingFallback"; @@ -145,6 +146,7 @@ function Router() { function AppContent() { // Enable background notifications for downloads useBackgroundNotifications(); + useGameUpdatedSocket(); return ; } diff --git a/client/src/components/GameDetailsModal.tsx b/client/src/components/GameDetailsModal.tsx index 99f9c6dec..6e6152be4 100644 --- a/client/src/components/GameDetailsModal.tsx +++ b/client/src/components/GameDetailsModal.tsx @@ -595,17 +595,9 @@ export default function GameDetailsModal({ game, open, onOpenChange }: GameDetai queryClient.invalidateQueries({ queryKey: [`/api/games/${game.id}/downloads`] }); } }; - // A finished download can record a newer installed version on the game itself. - const gameHandler = (gameId: string) => { - if (gameId === game.id) { - queryClient.invalidateQueries({ queryKey: ["/api/games"] }); - } - }; socket.on("downloadUpdate", handler); - socket.on("gameUpdated", gameHandler); return () => { socket.off("downloadUpdate", handler); - socket.off("gameUpdated", gameHandler); }; }, [open, game?.id, queryClient]); diff --git a/client/src/hooks/use-game-updated-socket.ts b/client/src/hooks/use-game-updated-socket.ts new file mode 100644 index 000000000..f93adb338 --- /dev/null +++ b/client/src/hooks/use-game-updated-socket.ts @@ -0,0 +1,24 @@ +import { useEffect } from "react"; +import { useQueryClient } from "@tanstack/react-query"; +import { getSocket } from "@/lib/socket"; + +/** + * Refreshes the games query when the server changes a game in the background (e.g. a finished + * download recording a newer installed version). Mounted app-wide: the games query never goes + * stale on its own, so an event missed while no details modal is open would otherwise leave the + * library showing old data until a reload. + */ +export function useGameUpdatedSocket(): void { + const queryClient = useQueryClient(); + + useEffect(() => { + const socket = getSocket(); + const handler = () => { + queryClient.invalidateQueries({ queryKey: ["/api/games"] }); + }; + socket.on("gameUpdated", handler); + return () => { + socket.off("gameUpdated", handler); + }; + }, [queryClient]); +} diff --git a/server/__tests__/game-version.test.ts b/server/__tests__/game-version.test.ts index 19eaf7abc..6d27a55f7 100644 --- a/server/__tests__/game-version.test.ts +++ b/server/__tests__/game-version.test.ts @@ -10,7 +10,12 @@ const { recordVersionFromCompletedDownload } = await import("../game-version.js" describe("recordVersionFromCompletedDownload", () => { const updateGame = vi.fn(); - const store = { updateGame }; + const getGame = vi.fn(); + const store = { getGame, updateGame }; + const record = (installedVersion: string | null, title: string) => { + getGame.mockResolvedValue({ id: "g1", installedVersion }); + return recordVersionFromCompletedDownload(store, "g1", title); + }; beforeEach(() => { vi.clearAllMocks(); @@ -18,61 +23,38 @@ describe("recordVersionFromCompletedDownload", () => { }); it("records the version of a finished full-game download when none is known", async () => { - const recorded = await recordVersionFromCompletedDownload( - store, - { id: "g1", installedVersion: null }, - "Test.Game.v1.2.3-RUNE" - ); + const recorded = await record(null, "Test.Game.v1.2.3-RUNE"); expect(recorded).toBe("v1.2.3"); expect(updateGame).toHaveBeenCalledWith("g1", { installedVersion: "v1.2.3" }); expect(notifyUser).toHaveBeenCalledWith("gameUpdated", "g1"); }); it("moves the version forward on a newer update", async () => { - await recordVersionFromCompletedDownload( - store, - { id: "g1", installedVersion: "v1.2" }, - "Test.Game.v1.2.Update.v1.3-RUNE" - ); + await record("v1.2", "Test.Game.v1.2.Update.v1.3-RUNE"); expect(updateGame).toHaveBeenCalledWith("g1", { installedVersion: "v1.3" }); }); it("never moves the version backwards or across numbering schemes", async () => { - await recordVersionFromCompletedDownload( - store, - { id: "g1", installedVersion: "v1.5" }, - "Test.Game.Update.v1.3-RUNE" - ); - await recordVersionFromCompletedDownload( - store, - { id: "g1", installedVersion: "Build 1234" }, - "Test.Game.v1.3-RUNE" - ); + await record("v1.5", "Test.Game.Update.v1.3-RUNE"); + await record("Build 1234", "Test.Game.v1.3-RUNE"); expect(updateGame).not.toHaveBeenCalled(); }); it("ignores DLC releases and releases without a version", async () => { - await recordVersionFromCompletedDownload( - store, - { id: "g1", installedVersion: null }, - "Test.Game.Season.Pass.DLC.v2.0-RUNE" - ); - await recordVersionFromCompletedDownload( - store, - { id: "g1", installedVersion: null }, - "Test.Game-RUNE" - ); + await record(null, "Test.Game.Season.Pass.DLC.v2.0-RUNE"); + await record(null, "Test.Game-RUNE"); + expect(updateGame).not.toHaveBeenCalled(); + }); + + it("compares against the current row, not the caller's snapshot", async () => { + // The user moved to v2.0 while the v1.5 import was running. + expect(await record("v2.0", "Test.Game.v1.5-RUNE")).toBeNull(); + expect(getGame).toHaveBeenCalledWith("g1"); expect(updateGame).not.toHaveBeenCalled(); }); it("swallows storage failures", async () => { updateGame.mockRejectedValue(new Error("db down")); - await expect( - recordVersionFromCompletedDownload( - store, - { id: "g1", installedVersion: null }, - "Test.Game.v1.0-RUNE" - ) - ).resolves.toBeNull(); + await expect(record(null, "Test.Game.v1.0-RUNE")).resolves.toBeNull(); }); }); diff --git a/server/cron.ts b/server/cron.ts index 9480796f0..dc4a9b734 100644 --- a/server/cron.ts +++ b/server/cron.ts @@ -960,9 +960,11 @@ export async function checkDownloadStatus() { // Update DB - mark as completed await storage.updateGameDownloadStatus(download.id, "completed"); // With post-processing on, the import records it once the files are in place. - if (game) { - await recordVersionFromCompletedDownload(storage, game, download.downloadTitle); - } + await recordVersionFromCompletedDownload( + storage, + download.gameId, + download.downloadTitle + ); // Update Game status to 'owned' (which means we have the files), unless // the user already moved it past that (e.g. an update for a game they're playing). diff --git a/server/game-version.ts b/server/game-version.ts index 1ab69a385..511b697cc 100644 --- a/server/game-version.ts +++ b/server/game-version.ts @@ -1,4 +1,3 @@ -import type { Game } from "../shared/schema.js"; import { categorizeDownload } from "../shared/download-categorizer.js"; import { compareVersions, extractVersionFromReleaseName } from "../shared/version-utils.js"; import type { IStorage } from "./storage.js"; @@ -15,8 +14,8 @@ import { notifyUser } from "./socket.js"; * recorded, if any. */ export async function recordVersionFromCompletedDownload( - store: Pick, - game: Pick, + store: Pick, + gameId: string, downloadTitle: string ): Promise { try { @@ -26,6 +25,10 @@ export async function recordVersionFromCompletedDownload( const detected = extractVersionFromReleaseName(downloadTitle); if (!detected) return null; + // Read the current row: an import can run for minutes, during which the user may have + // edited the version or another import may have advanced it. + const game = await store.getGame(gameId); + if (!game) return null; if (game.installedVersion?.trim()) { const cmp = compareVersions(detected, game.installedVersion); if (cmp === null || cmp <= 0) return null; @@ -41,7 +44,7 @@ export async function recordVersionFromCompletedDownload( return detected; } catch (error) { logger.warn( - { error, gameId: game.id, item: downloadTitle }, + { error, gameId, item: downloadTitle }, "Failed to record game version from completed download" ); return null; diff --git a/server/services/ImportManager.ts b/server/services/ImportManager.ts index f8f0ebbaa..214bad325 100644 --- a/server/services/ImportManager.ts +++ b/server/services/ImportManager.ts @@ -554,7 +554,7 @@ export class ImportManager { try { const download = await this.storage.getGameDownload(downloadId); if (download) { - await recordVersionFromCompletedDownload(this.storage, game, download.downloadTitle); + await recordVersionFromCompletedDownload(this.storage, game.id, download.downloadTitle); } } catch (error) { logger.warn({ error, downloadId }, "[ImportManager] Could not record the installed version"); From ae48e18fe40304cd94837388fad73af2a2e84df9 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 15:36:23 +0000 Subject: [PATCH 07/28] Take an update's target version, including build targets Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- shared/__tests__/version-utils.test.ts | 3 ++- shared/version-utils.ts | 30 ++++++++++++++++++++------ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/shared/__tests__/version-utils.test.ts b/shared/__tests__/version-utils.test.ts index 633eff1e3..c0905f50b 100644 --- a/shared/__tests__/version-utils.test.ts +++ b/shared/__tests__/version-utils.test.ts @@ -19,7 +19,8 @@ describe("extractVersionFromReleaseName", () => { ["Game.v1.0.Update.v1.1-RUNE", "v1.1"], // the update's target wins ["Game.v1.0.Update.v2-RUNE", "v2"], ["Game.v1.0.to.v1.1.Patch-RUNE", "v1.1"], // highest of several - ["Game.v1.4.Update.Build.5000-RUNE", "v1.4"], + ["Game.v1.4.Update.Build.5000-RUNE", "Build 5000"], // the update's build target wins + ["Game.Update.v1.0.to.v1.1-RUNE", "v1.1"], // an update's target, not its start ])("finds the version in %s", (name, expected) => { expect(extractVersionFromReleaseName(name)).toBe(expected); }); diff --git a/shared/version-utils.ts b/shared/version-utils.ts index 59ec0e9f3..b2af2de35 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -35,28 +35,44 @@ const UPDATE_VERSION = new RegExp( String.raw`${NOT_PRECEDED_BY_ALNUM}update[\s._-](?:v\s?(\d+(?:\.\d+)*)|(\d+(?:\.\d+)+))${NOT_FOLLOWED_BY_ALNUM}`, "i" ); +// "Update.Build.5000" -- an update whose target is a build number. +const UPDATE_BUILD_VERSION = new RegExp( + String.raw`${NOT_PRECEDED_BY_ALNUM}update[\s._-]build[\s._-]?(\d+)${NOT_FOLLOWED_BY_ALNUM}`, + "i" +); /** * Finds a version in a release name and returns it in display form ("v1.2.3" or * "Build 12345"), or null when the name carries none. */ export function extractVersionFromReleaseName(releaseName: string): string | null { - // An update names the version it brings the game to ("Game.v1.0.Update.v1.1"), so that one wins. + // An update names the version it brings the game to, so what follows "Update" wins over the + // base version before it ("Game.v1.0.Update.v1.1"), and its highest version wins over its + // starting one ("Game.Update.v1.0.to.v1.1"). const update = UPDATE_VERSION.exec(releaseName); const updateVersion = update?.[1] ?? update?.[2]; - if (updateVersion) return `v${updateVersion}`; - // Otherwise the highest of the versions named ("Game.v1.0.to.v1.1" brings the game to v1.1). - let best: string | null = null; - for (const match of releaseName.matchAll(V_VERSION_ALL)) { - const candidate = `v${match[1]}`; - if (best === null || (compareVersions(candidate, best) ?? 0) > 0) best = candidate; + if (update && updateVersion) { + return highestVVersion(releaseName.slice(update.index), `v${updateVersion}`); } + const updateBuild = UPDATE_BUILD_VERSION.exec(releaseName); + if (updateBuild?.[1]) return `Build ${updateBuild[1]}`; + // Otherwise the highest of the versions named ("Game.v1.0.to.v1.1" brings the game to v1.1). + const best = highestVVersion(releaseName, null); if (best) return best; const build = BUILD_VERSION.exec(releaseName); if (build?.[1]) return `Build ${build[1]}`; return null; } +function highestVVersion(text: string, initial: string | null): string | null { + let best = initial; + for (const match of text.matchAll(V_VERSION_ALL)) { + const candidate = `v${match[1]}`; + if (best === null || (compareVersions(candidate, best) ?? 0) > 0) best = candidate; + } + return best; +} + /** * Parses a version as typed by a user or produced by extractVersionFromReleaseName: * "1.2.3", "v1.2.3", "V 1.05", "Build 12345". Anything else returns null. From 6e975c2ddfe69dc793a3afc0f97fdcb345991568 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 15:49:57 +0000 Subject: [PATCH 08/28] Record edition releases' versions, keep suggestion clicks, write versions atomically Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- .../__tests__/InstalledVersionField.test.tsx | 7 ++++ .../src/components/InstalledVersionField.tsx | 3 ++ server/__tests__/cron_download_status.test.ts | 8 ++--- .../database_storage_extended.test.ts | 3 ++ server/__tests__/dialect-parity.test.ts | 10 ++++++ server/__tests__/game-version.test.ts | 30 +++++++++++----- server/__tests__/import_manager.test.ts | 3 +- server/game-version.ts | 34 +++++++++++++++---- server/storage.ts | 34 +++++++++++++++++++ 9 files changed, 111 insertions(+), 21 deletions(-) diff --git a/client/__tests__/InstalledVersionField.test.tsx b/client/__tests__/InstalledVersionField.test.tsx index ff3a33583..83bbe3b8e 100644 --- a/client/__tests__/InstalledVersionField.test.tsx +++ b/client/__tests__/InstalledVersionField.test.tsx @@ -102,6 +102,13 @@ describe("InstalledVersionField", () => { ); }); + it("keeps focus in the input when a suggestion is pressed", () => { + renderField(null, ["Game.Update.v1.4-RUNE"]); + const button = screen.getByRole("button", { name: "Set installed version to v1.4" }); + // A cancelled mousedown means the input never blurs (and never saves its draft) first. + expect(fireEvent.mouseDown(button)).toBe(false); + }); + it("restores the stored value and warns when saving fails", async () => { apiRequest.mockRejectedValue(new Error("boom")); const input = renderField("v1.0"); diff --git a/client/src/components/InstalledVersionField.tsx b/client/src/components/InstalledVersionField.tsx index 004ab27f5..ebe33de2e 100644 --- a/client/src/components/InstalledVersionField.tsx +++ b/client/src/components/InstalledVersionField.tsx @@ -128,6 +128,9 @@ export default function InstalledVersionField({ className="h-8 px-2.5 text-xs" aria-label={`Set installed version to ${version}`} disabled={mutation.isPending} + // Keep focus in the input: its blur would otherwise save the typed draft and + // disable these buttons before the click lands. + onMouseDown={(e) => e.preventDefault()} onClick={() => { setDraft(version); save(version); diff --git a/server/__tests__/cron_download_status.test.ts b/server/__tests__/cron_download_status.test.ts index 4d85b1692..6515d1b59 100644 --- a/server/__tests__/cron_download_status.test.ts +++ b/server/__tests__/cron_download_status.test.ts @@ -32,7 +32,7 @@ const mockAddNotification = vi.fn(); const mockGetUserSettings = vi.fn(); const mockGetImportConfig = vi.fn(); const mockGetDownloadsByGameId = vi.fn(); -const mockUpdateGame = vi.fn(); +const mockReplaceGameInstalledVersion = vi.fn(); vi.mock("../storage.js", () => ({ storage: { @@ -45,7 +45,7 @@ vi.mock("../storage.js", () => ({ getUserSettings: mockGetUserSettings, getImportConfig: mockGetImportConfig, getDownloadsByGameId: mockGetDownloadsByGameId, - updateGame: mockUpdateGame, + replaceGameInstalledVersion: mockReplaceGameInstalledVersion, }, })); @@ -490,7 +490,7 @@ describe("Cron - checkDownloadStatus", () => { await checkDownloadStatus(); - expect(mockUpdateGame).toHaveBeenCalledWith(versioned.gameId, { installedVersion: "v1.4.2" }); + expect(mockReplaceGameInstalledVersion).toHaveBeenCalledWith(versioned.gameId, null, "v1.4.2"); }); it("leaves the version to the import when post-processing is enabled", async () => { @@ -510,7 +510,7 @@ describe("Cron - checkDownloadStatus", () => { await checkDownloadStatus(); - expect(mockUpdateGame).not.toHaveBeenCalled(); + expect(mockReplaceGameInstalledVersion).not.toHaveBeenCalled(); }); it("should keep a playing game's status when its update download completes", async () => { diff --git a/server/__tests__/database_storage_extended.test.ts b/server/__tests__/database_storage_extended.test.ts index 75744b7f5..df4bdf0a2 100644 --- a/server/__tests__/database_storage_extended.test.ts +++ b/server/__tests__/database_storage_extended.test.ts @@ -187,6 +187,9 @@ describe("DatabaseStorage Extended Coverage", () => { const versionUpdated = await storage.updateGameInstalledVersion(game.id, userId, "v1.2.3"); expect(versionUpdated?.installedVersion).toBe("v1.2.3"); expect(await storage.updateGameInstalledVersion(game.id, "other-user", "v9")).toBeUndefined(); + expect(await storage.replaceGameInstalledVersion(game.id, "v1.0", "v1.3")).toBe(false); + expect(await storage.replaceGameInstalledVersion(game.id, "v1.2.3", "v1.3")).toBe(true); + expect((await storage.getGame(game.id))?.installedVersion).toBe("v1.3"); await storage.updateGameSearchResultsAvailable(game.id, true); const refetched = await storage.getGame(game.id); diff --git a/server/__tests__/dialect-parity.test.ts b/server/__tests__/dialect-parity.test.ts index 1b0067e3d..6167cdea2 100644 --- a/server/__tests__/dialect-parity.test.ts +++ b/server/__tests__/dialect-parity.test.ts @@ -114,6 +114,16 @@ describe.each(activeTestDialects())("storage behaviour on %s", (dialect) => { expect(after.every((g) => g.status === "downloaded")).toBe(true); }); + it("replaceGameInstalledVersion writes only over the expected value", async () => { + const [user] = await storage().getAllUsers(); + const [game] = await storage().getUserGames(user.id); + expect(await storage().replaceGameInstalledVersion(game.id, "v9", "v1.0")).toBe(false); + expect(await storage().replaceGameInstalledVersion(game.id, null, "v1.0")).toBe(true); + expect(await storage().replaceGameInstalledVersion(game.id, null, "v2.0")).toBe(false); + expect(await storage().replaceGameInstalledVersion(game.id, "v1.0", "v1.1")).toBe(true); + expect((await storage().getGame(game.id))?.installedVersion).toBe("v1.1"); + }); + it("aggregates come back as numbers, not strings", async () => { const [user] = await storage().getAllUsers(); const status = await storage().getDashboardStatus(user.id); diff --git a/server/__tests__/game-version.test.ts b/server/__tests__/game-version.test.ts index 6d27a55f7..9a32c2e7b 100644 --- a/server/__tests__/game-version.test.ts +++ b/server/__tests__/game-version.test.ts @@ -9,9 +9,9 @@ vi.mock("../socket.js", () => ({ notifyUser })); const { recordVersionFromCompletedDownload } = await import("../game-version.js"); describe("recordVersionFromCompletedDownload", () => { - const updateGame = vi.fn(); + const replaceGameInstalledVersion = vi.fn(); const getGame = vi.fn(); - const store = { getGame, updateGame }; + const store = { getGame, replaceGameInstalledVersion }; const record = (installedVersion: string | null, title: string) => { getGame.mockResolvedValue({ id: "g1", installedVersion }); return recordVersionFromCompletedDownload(store, "g1", title); @@ -19,42 +19,54 @@ describe("recordVersionFromCompletedDownload", () => { beforeEach(() => { vi.clearAllMocks(); - updateGame.mockResolvedValue(undefined); + replaceGameInstalledVersion.mockResolvedValue(true); }); it("records the version of a finished full-game download when none is known", async () => { const recorded = await record(null, "Test.Game.v1.2.3-RUNE"); expect(recorded).toBe("v1.2.3"); - expect(updateGame).toHaveBeenCalledWith("g1", { installedVersion: "v1.2.3" }); + expect(replaceGameInstalledVersion).toHaveBeenCalledWith("g1", null, "v1.2.3"); expect(notifyUser).toHaveBeenCalledWith("gameUpdated", "g1"); }); it("moves the version forward on a newer update", async () => { await record("v1.2", "Test.Game.v1.2.Update.v1.3-RUNE"); - expect(updateGame).toHaveBeenCalledWith("g1", { installedVersion: "v1.3" }); + expect(replaceGameInstalledVersion).toHaveBeenCalledWith("g1", "v1.2", "v1.3"); }); it("never moves the version backwards or across numbering schemes", async () => { await record("v1.5", "Test.Game.Update.v1.3-RUNE"); await record("Build 1234", "Test.Game.v1.3-RUNE"); - expect(updateGame).not.toHaveBeenCalled(); + expect(replaceGameInstalledVersion).not.toHaveBeenCalled(); }); it("ignores DLC releases and releases without a version", async () => { await record(null, "Test.Game.Season.Pass.DLC.v2.0-RUNE"); await record(null, "Test.Game-RUNE"); - expect(updateGame).not.toHaveBeenCalled(); + expect(replaceGameInstalledVersion).not.toHaveBeenCalled(); + }); + + it("takes the version from full-game editions, even those bundling DLC", async () => { + expect(await record(null, "Test.Game.Deluxe.Edition.v1.4-RUNE")).toBe("v1.4"); + expect(await record(null, "Test.Game.GOTY.v2.0.incl.DLC-GOG")).toBe("v2.0"); + expect(await record(null, "Test.Game.Complete.Edition.v3.1-RUNE")).toBe("v3.1"); + }); + + it("does not notify when the version changed before the write", async () => { + replaceGameInstalledVersion.mockResolvedValue(false); + expect(await record("v1.0", "Test.Game.Update.v1.1-RUNE")).toBeNull(); + expect(notifyUser).not.toHaveBeenCalled(); }); it("compares against the current row, not the caller's snapshot", async () => { // The user moved to v2.0 while the v1.5 import was running. expect(await record("v2.0", "Test.Game.v1.5-RUNE")).toBeNull(); expect(getGame).toHaveBeenCalledWith("g1"); - expect(updateGame).not.toHaveBeenCalled(); + expect(replaceGameInstalledVersion).not.toHaveBeenCalled(); }); it("swallows storage failures", async () => { - updateGame.mockRejectedValue(new Error("db down")); + replaceGameInstalledVersion.mockRejectedValue(new Error("db down")); await expect(record(null, "Test.Game.v1.0-RUNE")).resolves.toBeNull(); }); }); diff --git a/server/__tests__/import_manager.test.ts b/server/__tests__/import_manager.test.ts index 7a2d650e4..fa95d12f9 100644 --- a/server/__tests__/import_manager.test.ts +++ b/server/__tests__/import_manager.test.ts @@ -36,6 +36,7 @@ describe("ImportManager", () => { updateGameDownloadStatus: vi.fn(), updateGameStatus: vi.fn(), updateGame: vi.fn(), + replaceGameInstalledVersion: vi.fn(), addNotification: vi.fn().mockResolvedValue(undefined), getUserSettings: vi.fn().mockResolvedValue(undefined), }; @@ -357,7 +358,7 @@ describe("ImportManager", () => { }); expect(storage.updateGameDownloadStatus).toHaveBeenCalledWith("dl-1", "imported"); - expect(storage.updateGame).toHaveBeenCalledWith("g1", { installedVersion: "v1.2" }); + expect(storage.replaceGameInstalledVersion).toHaveBeenCalledWith("g1", "v1.1", "v1.2"); }); it.each(["playing", "shelved", "completed"])( diff --git a/server/game-version.ts b/server/game-version.ts index 511b697cc..fa7aa6b9b 100644 --- a/server/game-version.ts +++ b/server/game-version.ts @@ -4,23 +4,36 @@ import type { IStorage } from "./storage.js"; import { logger } from "./logger.js"; import { notifyUser } from "./socket.js"; +// The categorizer files edition names ("Deluxe", "GOTY", "Complete") under DLC because those +// releases bundle DLC, but they are full games and their version is the base game's. Only these +// words mark a release that is DLC alone, once bundle mentions ("incl.DLC", "+ all DLCs") are +// set aside. +const DLC_ONLY = /\b(?:dlc|downloadable content|expansion|season pass)\b/i; +const BUNDLED_DLC = /(?:\bincl(?:uding)?|\bwith|\+)[\s._-]*(?:all[\s._-]*)?dlcs?\b/gi; + +function carriesBaseGameVersion(downloadTitle: string): boolean { + const { category } = categorizeDownload(downloadTitle); + if (category === "main" || category === "update") return true; + return category === "dlc" && !DLC_ONLY.test(downloadTitle.replace(BUNDLED_DLC, "")); +} + /** * Records the version carried by an installed download's release name (e.g. "v1.2.3") as the * game's installed version. Call it once the files are really in place: when the download - * finishes with post-processing off, or when the import is finalized. Only the full game or an - * update counts (a DLC's version says nothing about the base game), and a known version is only - * ever moved forward: an older or incomparable release never overwrites what the user has. + * finishes with post-processing off, or when the import is finalized. Only the full game + * (editions included) or an update counts (a DLC's version says nothing about the base game), + * and a known version is only ever moved forward: an older or incomparable release never + * overwrites what the user has. * Never throws, so a failure here can't break the download or import flow. Returns the version * recorded, if any. */ export async function recordVersionFromCompletedDownload( - store: Pick, + store: Pick, gameId: string, downloadTitle: string ): Promise { try { - const { category } = categorizeDownload(downloadTitle); - if (category !== "main" && category !== "update") return null; + if (!carriesBaseGameVersion(downloadTitle)) return null; const detected = extractVersionFromReleaseName(downloadTitle); if (!detected) return null; @@ -34,7 +47,14 @@ export async function recordVersionFromCompletedDownload( if (cmp === null || cmp <= 0) return null; } - await store.updateGame(game.id, { installedVersion: detected }); + // Written only if the version is still the one just compared against, so a value the user + // saved in between is never overwritten. + const written = await store.replaceGameInstalledVersion( + game.id, + game.installedVersion ?? null, + detected + ); + if (!written) return null; logger.info( { gameId: game.id, previous: game.installedVersion, installedVersion: detected }, "Recorded game version from completed download" diff --git a/server/storage.ts b/server/storage.ts index 0dead2bf3..a0b85f0ec 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -248,6 +248,15 @@ export interface IStorage { userId: string, installedVersion: string | null ): Promise; + /** + * Sets a game's installed version only if it still equals `expected` (null = not set), so a + * detected version can't overwrite one written in between. Returns whether it was written. + */ + replaceGameInstalledVersion( + id: string, + expected: string | null, + installedVersion: string + ): Promise; updateGameSearchResultsAvailable(gameId: string, available: boolean): Promise; updateGameSearchResultsByCategory( gameId: string, @@ -755,6 +764,17 @@ export class MemStorage implements IStorage { return updatedGame; } + async replaceGameInstalledVersion( + id: string, + expected: string | null, + installedVersion: string + ): Promise { + const game = this.games.get(id); + if (!game || (game.installedVersion ?? null) !== expected) return false; + this.games.set(id, { ...game, installedVersion }); + return true; + } + async getGameJournalEntries(gameId: string, userId: string): Promise { return Array.from(this.gameJournalEntries.values()) .filter((entry) => entry.gameId === gameId && entry.userId === userId) @@ -2354,6 +2374,20 @@ export class DatabaseStorage implements IStorage { return updatedGame || undefined; } + async replaceGameInstalledVersion( + id: string, + expected: string | null, + installedVersion: string + ): Promise { + const current = + expected === null ? isNull(games.installedVersion) : eq(games.installedVersion, expected); + const result = await db + .update(games) + .set({ installedVersion }) + .where(and(eq(games.id, id), current)); + return affectedRows(result) > 0; + } + async getGameJournalEntries(gameId: string, userId: string): Promise { return db .select() From 710b6ae483e2b2a9b5e99e2c9f7902300d515659 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 15:55:09 +0000 Subject: [PATCH 09/28] Add a 1.5.1-rc1 changelog entry for the installed version Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- docs/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index ba4f829e1..e8b1902f0 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. +## [1.5.1-rc1] - 2026-10-xx + +### Added + +- **Installed version**: each game records the version you have installed, editable in the game details modal with suggestions from your downloads' release names. It is filled in automatically when a full-game or update download finishes, and update releases that are not newer than it no longer raise "Game Updates Available" (#1142). + ## [1.5.0] - 2026-09-xx ### Added From 499fc90cead280bb8eeb831a5b96d16ed2434e43 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 16:04:55 +0000 Subject: [PATCH 10/28] Skip pre-release versions, take build-range targets, serialize version saves Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- .../__tests__/InstalledVersionField.test.tsx | 18 ++++++++++++++++++ .../src/components/InstalledVersionField.tsx | 18 +++++++++++++++--- shared/__tests__/version-utils.test.ts | 5 +++++ shared/version-utils.ts | 18 +++++++++++++++++- 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/client/__tests__/InstalledVersionField.test.tsx b/client/__tests__/InstalledVersionField.test.tsx index 83bbe3b8e..6f0a39a61 100644 --- a/client/__tests__/InstalledVersionField.test.tsx +++ b/client/__tests__/InstalledVersionField.test.tsx @@ -109,6 +109,24 @@ describe("InstalledVersionField", () => { expect(fireEvent.mouseDown(button)).toBe(false); }); + it("sends a value typed during a save only after that save settles", async () => { + let finishFirst: (value: unknown) => void = () => {}; + apiRequest.mockReturnValueOnce(new Promise((resolve) => (finishFirst = resolve))); + const input = renderField(null); + fireEvent.change(input, { target: { value: "v2" } }); + fireEvent.keyDown(input, { key: "Enter" }); + await waitFor(() => expect(apiRequest).toHaveBeenCalledTimes(1)); + fireEvent.change(input, { target: { value: "v3" } }); + fireEvent.blur(input); + expect(apiRequest).toHaveBeenCalledTimes(1); + + finishFirst({ ok: true, json: async () => ({}) }); + await waitFor(() => expect(apiRequest).toHaveBeenCalledTimes(2)); + expect(apiRequest).toHaveBeenLastCalledWith("PATCH", `/api/games/${gameId}/installed-version`, { + installedVersion: "v3", + }); + }); + it("restores the stored value and warns when saving fails", async () => { apiRequest.mockRejectedValue(new Error("boom")); const input = renderField("v1.0"); diff --git a/client/src/components/InstalledVersionField.tsx b/client/src/components/InstalledVersionField.tsx index ebe33de2e..d94aea83e 100644 --- a/client/src/components/InstalledVersionField.tsx +++ b/client/src/components/InstalledVersionField.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { Check, Loader2, Tag } from "lucide-react"; import { Input } from "@/components/ui/input"; @@ -44,6 +44,9 @@ export default function InstalledVersionField({ const { toast } = useToast(); const queryClient = useQueryClient(); const [draft, setDraft] = useState(installedVersion ?? ""); + // A value entered while a save is in flight; sent once that save settles, so saves never + // race and the latest value always lands last. + const queued = useRef<{ value: string | null } | null>(null); // Follow the server value (another tab, a finished download detecting a newer version). useEffect(() => { @@ -60,9 +63,15 @@ export default function InstalledVersionField({ queryClient.invalidateQueries({ queryKey: ["/api/games"] }); }, onError: () => { + if (queued.current) return; // a newer value is about to be sent setDraft(installedVersion ?? ""); toast({ description: "Failed to save the installed version", variant: "destructive" }); }, + onSettled: (_data, _error, sent) => { + const next = queued.current; + queued.current = null; + if (next && next.value !== sent) mutation.mutate(next.value); + }, }); const suggestions = useMemo( @@ -73,8 +82,11 @@ export default function InstalledVersionField({ const save = (value: string) => { const next = value.trim() || null; if (next === (installedVersion ?? null)) return; - // Enter then blur would otherwise send the same value twice before the refetch lands. - if (mutation.isPending && mutation.variables === next) return; + if (mutation.isPending) { + // Enter then blur would otherwise send the same value twice before the refetch lands. + queued.current = mutation.variables === next ? null : { value: next }; + return; + } mutation.mutate(next); }; diff --git a/shared/__tests__/version-utils.test.ts b/shared/__tests__/version-utils.test.ts index c0905f50b..3e8ee4087 100644 --- a/shared/__tests__/version-utils.test.ts +++ b/shared/__tests__/version-utils.test.ts @@ -21,6 +21,8 @@ describe("extractVersionFromReleaseName", () => { ["Game.v1.0.to.v1.1.Patch-RUNE", "v1.1"], // highest of several ["Game.v1.4.Update.Build.5000-RUNE", "Build 5000"], // the update's build target wins ["Game.Update.v1.0.to.v1.1-RUNE", "v1.1"], // an update's target, not its start + ["Game.Update.Build.1000.to.Build.1200-RUNE", "Build 1200"], // same for build ranges + ["Game.v1.2.Repack-PREDATOR", "v1.2"], // a group name is not a pre-release tag ])("finds the version in %s", (name, expected) => { expect(extractVersionFromReleaseName(name)).toBe(expected); }); @@ -30,6 +32,9 @@ describe("extractVersionFromReleaseName", () => { "Some.Game.Update.2-CODEX", // second update pack, not a version "Game.x64v2.Edition", // "v2" glued to a word "Game.dev1.2.Repack", + "Game.Update.v1.2-beta-RUNE", // pre-releases: a stable v1.2 would supersede it + "Game.v2.0.RC1-GOG", + "Game v1.3 Preview", ])("finds nothing in %s", (name) => { expect(extractVersionFromReleaseName(name)).toBeNull(); }); diff --git a/shared/version-utils.ts b/shared/version-utils.ts index b2af2de35..56d16e820 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -41,11 +41,17 @@ const UPDATE_BUILD_VERSION = new RegExp( "i" ); +// "v1.2-beta", "1.2.RC1", "v2.0 Preview": a pre-release, which a later stable release of the +// same number supersedes. Names carrying one are treated as having no readable version. +const PRERELEASE_VERSION = /\d[\s._-]?(?:alpha|beta|rc|pre|preview|dev)(?![a-z])/i; +const BUILD_VERSION_ALL = new RegExp(BUILD_VERSION.source, "gi"); + /** * Finds a version in a release name and returns it in display form ("v1.2.3" or * "Build 12345"), or null when the name carries none. */ export function extractVersionFromReleaseName(releaseName: string): string | null { + if (PRERELEASE_VERSION.test(releaseName)) return null; // An update names the version it brings the game to, so what follows "Update" wins over the // base version before it ("Game.v1.0.Update.v1.1"), and its highest version wins over its // starting one ("Game.Update.v1.0.to.v1.1"). @@ -54,8 +60,9 @@ export function extractVersionFromReleaseName(releaseName: string): string | nul if (update && updateVersion) { return highestVVersion(releaseName.slice(update.index), `v${updateVersion}`); } + // Likewise for builds: "Update.Build.1000.to.Build.1200" brings the game to Build 1200. const updateBuild = UPDATE_BUILD_VERSION.exec(releaseName); - if (updateBuild?.[1]) return `Build ${updateBuild[1]}`; + if (updateBuild) return highestBuild(releaseName.slice(updateBuild.index)); // Otherwise the highest of the versions named ("Game.v1.0.to.v1.1" brings the game to v1.1). const best = highestVVersion(releaseName, null); if (best) return best; @@ -73,6 +80,15 @@ function highestVVersion(text: string, initial: string | null): string | null { return best; } +function highestBuild(text: string): string | null { + let best: number | null = null; + for (const match of text.matchAll(BUILD_VERSION_ALL)) { + const build = Number(match[1]); + if (best === null || build > best) best = build; + } + return best === null ? null : `Build ${best}`; +} + /** * Parses a version as typed by a user or produced by extractVersionFromReleaseName: * "1.2.3", "v1.2.3", "V 1.05", "Build 12345". Anything else returns null. From 7ab41300d0e101f8159c64f5e58cd6a835ab605d Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 16:11:28 +0000 Subject: [PATCH 11/28] Queue a typed-back value during a save, and file the changelog entry under 1.5.0 Pre-release tags such as v1.5.0-rc1 now take the release notes of the version they lead to. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- client/__tests__/InstalledVersionField.test.tsx | 17 +++++++++++++++++ client/src/components/InstalledVersionField.tsx | 4 +++- docs/CHANGELOG.md | 7 +------ scripts/extract-changelog.mjs | 11 +++++++++-- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/client/__tests__/InstalledVersionField.test.tsx b/client/__tests__/InstalledVersionField.test.tsx index 6f0a39a61..5483b8566 100644 --- a/client/__tests__/InstalledVersionField.test.tsx +++ b/client/__tests__/InstalledVersionField.test.tsx @@ -127,6 +127,23 @@ describe("InstalledVersionField", () => { }); }); + it("undoes an in-flight save when the stored value is typed back", async () => { + let finishFirst: (value: unknown) => void = () => {}; + apiRequest.mockReturnValueOnce(new Promise((resolve) => (finishFirst = resolve))); + const input = renderField("v1"); + fireEvent.change(input, { target: { value: "v2" } }); + fireEvent.keyDown(input, { key: "Enter" }); + await waitFor(() => expect(apiRequest).toHaveBeenCalledTimes(1)); + fireEvent.change(input, { target: { value: "v1" } }); + fireEvent.blur(input); + + finishFirst({ ok: true, json: async () => ({}) }); + await waitFor(() => expect(apiRequest).toHaveBeenCalledTimes(2)); + expect(apiRequest).toHaveBeenLastCalledWith("PATCH", `/api/games/${gameId}/installed-version`, { + installedVersion: "v1", + }); + }); + it("restores the stored value and warns when saving fails", async () => { apiRequest.mockRejectedValue(new Error("boom")); const input = renderField("v1.0"); diff --git a/client/src/components/InstalledVersionField.tsx b/client/src/components/InstalledVersionField.tsx index d94aea83e..eb960fac1 100644 --- a/client/src/components/InstalledVersionField.tsx +++ b/client/src/components/InstalledVersionField.tsx @@ -81,12 +81,14 @@ export default function InstalledVersionField({ const save = (value: string) => { const next = value.trim() || null; - if (next === (installedVersion ?? null)) return; + // Checked before comparing with the stored value, which is stale while a save is in + // flight: going back to it then still needs a save to undo the in-flight one. if (mutation.isPending) { // Enter then blur would otherwise send the same value twice before the refetch lands. queued.current = mutation.variables === next ? null : { value: next }; return; } + if (next === (installedVersion ?? null)) return; mutation.mutate(next); }; diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index e8b1902f0..663b5c884 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,12 +2,6 @@ All notable changes to this project will be documented in this file. -## [1.5.1-rc1] - 2026-10-xx - -### Added - -- **Installed version**: each game records the version you have installed, editable in the game details modal with suggestions from your downloads' release names. It is filled in automatically when a full-game or update download finishes, and update releases that are not newer than it no longer raise "Game Updates Available" (#1142). - ## [1.5.0] - 2026-09-xx ### Added @@ -24,6 +18,7 @@ All notable changes to this project will be documented in this file. - **Time to Beat** via IGDB's official endpoint (#1063). - **Sort menu** on the Library page, plus an indexer-priority sort option for downloads (#980, #963). - **DLC & expansions**: games now persist their IGDB expansions and show them in a new DLC tab on the game detail page, with cover art, release year, and a category badge (#1105). +- **Installed version**: each game records the version you have installed, editable in the game details modal with suggestions from your downloads' release names. It is filled in automatically when a full-game or update download finishes, and update releases that are not newer than it no longer raise "Game Updates Available" (#1142). - **xREL**: surfaces a release's nuke reason with a "Nuked" badge (#948). - **Screenshot lightbox**: carousel navigation with arrow-key and swipe support, plus an image counter (#804). - **Wishlist**: configurable grid column count (#871). diff --git a/scripts/extract-changelog.mjs b/scripts/extract-changelog.mjs index 20dfb1ea9..56b6016ff 100644 --- a/scripts/extract-changelog.mjs +++ b/scripts/extract-changelog.mjs @@ -16,8 +16,15 @@ if (!version) { const changelogPath = path.join(repoRoot, "docs", "CHANGELOG.md"); const lines = fs.readFileSync(changelogPath, "utf8").split("\n"); -const headingPattern = new RegExp(`^## \\[${version.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\]`); -const startIndex = lines.findIndex((line) => headingPattern.test(line)); +const findHeading = (v) => { + const pattern = new RegExp(`^## \\[${v.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\]`); + return lines.findIndex((line) => pattern.test(line)); +}; + +// A pre-release ("1.5.0-rc1") without its own entry uses the notes of the version it leads to. +let startIndex = findHeading(version); +const baseVersion = version.replace(/-.*$/, ""); +if (startIndex === -1 && baseVersion !== version) startIndex = findHeading(baseVersion); if (startIndex === -1) { console.error(`No CHANGELOG.md entry found for version ${version}`); From 17779cd4ef048a683feb6fd564edbd59040ad98c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 16:21:13 +0000 Subject: [PATCH 12/28] Keep the category picked when claiming a download, and trust it for the installed version Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- migrations-pg/0009_spicy_black_bolt.sql | 1 + migrations-pg/meta/0009_snapshot.json | 2313 +++++++++++++++++++++ migrations-pg/meta/_journal.json | 7 + migrations/0044_faulty_blazing_skull.sql | 1 + migrations/meta/0044_snapshot.json | 2344 ++++++++++++++++++++++ migrations/meta/_journal.json | 7 + server/__tests__/api_routes.test.ts | 20 + server/__tests__/game-version.test.ts | 12 + server/cron.ts | 3 +- server/game-version.ts | 12 +- server/routes.ts | 2 + server/services/ImportManager.ts | 7 +- server/storage.ts | 2 + shared/schema.pg.ts | 1 + shared/schema.ts | 3 + 15 files changed, 4729 insertions(+), 6 deletions(-) create mode 100644 migrations-pg/0009_spicy_black_bolt.sql create mode 100644 migrations-pg/meta/0009_snapshot.json create mode 100644 migrations/0044_faulty_blazing_skull.sql create mode 100644 migrations/meta/0044_snapshot.json diff --git a/migrations-pg/0009_spicy_black_bolt.sql b/migrations-pg/0009_spicy_black_bolt.sql new file mode 100644 index 000000000..39ebdc259 --- /dev/null +++ b/migrations-pg/0009_spicy_black_bolt.sql @@ -0,0 +1 @@ +ALTER TABLE "game_downloads" ADD COLUMN "category" text; \ No newline at end of file diff --git a/migrations-pg/meta/0009_snapshot.json b/migrations-pg/meta/0009_snapshot.json new file mode 100644 index 000000000..1b5a0a0ec --- /dev/null +++ b/migrations-pg/meta/0009_snapshot.json @@ -0,0 +1,2313 @@ +{ + "id": "a0938e4a-d81e-4240-afa2-5ef321e792cd", + "prevId": "ea184a7e-1f5f-46c6-b1f3-33072994a55b", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.ai_auto_download_holds": { + "name": "ai_auto_download_holds", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "release_title": { + "name": "release_title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": { + "ai_auto_download_holds_game_title_idx": { + "name": "ai_auto_download_holds_game_title_idx", + "columns": [ + { + "expression": "game_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "release_title", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "ai_auto_download_holds_game_id_games_id_fk": { + "name": "ai_auto_download_holds_game_id_games_id_fk", + "tableFrom": "ai_auto_download_holds", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.api_keys": { + "name": "api_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key_hash": { + "name": "key_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + }, + "last_used_at": { + "name": "last_used_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "api_keys_key_hash_idx": { + "name": "api_keys_key_hash_idx", + "columns": [ + { + "expression": "key_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "api_keys_user_id_idx": { + "name": "api_keys_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.downloaders": { + "name": "downloaders", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "use_ssl": { + "name": "use_ssl", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "url_path": { + "name": "url_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "allow_self_signed_certificate": { + "name": "allow_self_signed_certificate", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "allow_insecure_lan": { + "name": "allow_insecure_lan", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "download_path": { + "name": "download_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'games'" + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'Questarr'" + }, + "add_stopped": { + "name": "add_stopped", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "remove_completed": { + "name": "remove_completed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "post_import_category": { + "name": "post_import_category", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "settings": { + "name": "settings", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + }, + "updated_at": { + "name": "updated_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.game_downloads": { + "name": "game_downloads", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "downloader_id": { + "name": "downloader_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "download_type": { + "name": "download_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'torrent'" + }, + "download_hash": { + "name": "download_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "download_title": { + "name": "download_title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'downloading'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "file_size": { + "name": "file_size", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "added_at": { + "name": "added_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + }, + "completed_at": { + "name": "completed_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "game_downloads_downloader_hash_idx": { + "name": "game_downloads_downloader_hash_idx", + "columns": [ + { + "expression": "downloader_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "download_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "game_downloads_game_id_games_id_fk": { + "name": "game_downloads_game_id_games_id_fk", + "tableFrom": "game_downloads", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_downloads_downloader_id_downloaders_id_fk": { + "name": "game_downloads_downloader_id_downloaders_id_fk", + "tableFrom": "game_downloads", + "tableTo": "downloaders", + "columnsFrom": ["downloader_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.game_files": { + "name": "game_files", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "download_id": { + "name": "download_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "original_name": { + "name": "original_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stored_name": { + "name": "stored_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category_overridden": { + "name": "category_overridden", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_size": { + "name": "file_size", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": { + "game_files_game_id_idx": { + "name": "game_files_game_id_idx", + "columns": [ + { + "expression": "game_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "game_files_download_id_idx": { + "name": "game_files_download_id_idx", + "columns": [ + { + "expression": "download_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "game_files_game_id_games_id_fk": { + "name": "game_files_game_id_games_id_fk", + "tableFrom": "game_files", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_files_download_id_game_downloads_id_fk": { + "name": "game_files_download_id_game_downloads_id_fk", + "tableFrom": "game_files", + "tableTo": "game_downloads", + "columnsFrom": ["download_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.game_journal_entries": { + "name": "game_journal_entries", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": { + "game_journal_entries_game_user_idx": { + "name": "game_journal_entries_game_user_idx", + "columns": [ + { + "expression": "game_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "game_journal_entries_game_id_games_id_fk": { + "name": "game_journal_entries_game_id_games_id_fk", + "tableFrom": "game_journal_entries", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_journal_entries_user_id_users_id_fk": { + "name": "game_journal_entries_user_id_users_id_fk", + "tableFrom": "game_journal_entries", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.game_milestones": { + "name": "game_milestones", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "completed_at": { + "name": "completed_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": { + "game_milestones_game_user_idx": { + "name": "game_milestones_game_user_idx", + "columns": [ + { + "expression": "game_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "game_milestones_game_id_games_id_fk": { + "name": "game_milestones_game_id_games_id_fk", + "tableFrom": "game_milestones", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_milestones_user_id_users_id_fk": { + "name": "game_milestones_user_id_users_id_fk", + "tableFrom": "game_milestones", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.game_screenshots": { + "name": "game_screenshots", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "caption": { + "name": "caption", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": { + "game_screenshots_game_user_idx": { + "name": "game_screenshots_game_user_idx", + "columns": [ + { + "expression": "game_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "game_screenshots_game_id_games_id_fk": { + "name": "game_screenshots_game_id_games_id_fk", + "tableFrom": "game_screenshots", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_screenshots_user_id_users_id_fk": { + "name": "game_screenshots_user_id_users_id_fk", + "tableFrom": "game_screenshots", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.games": { + "name": "games", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "igdb_id": { + "name": "igdb_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "steam_appid": { + "name": "steam_appid", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cover_url": { + "name": "cover_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "release_date": { + "name": "release_date", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "rating": { + "name": "rating", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "platforms": { + "name": "platforms", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "target_platform_id": { + "name": "target_platform_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_platform_name": { + "name": "target_platform_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "genres": { + "name": "genres", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "themes": { + "name": "themes", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "publishers": { + "name": "publishers", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "developers": { + "name": "developers", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "screenshots": { + "name": "screenshots", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'manual'" + }, + "igdb_websites": { + "name": "igdb_websites", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "expansions": { + "name": "expansions", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "aggregated_rating": { + "name": "aggregated_rating", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "time_to_beat_hastily": { + "name": "time_to_beat_hastily", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "time_to_beat_normally": { + "name": "time_to_beat_normally", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "time_to_beat_completely": { + "name": "time_to_beat_completely", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'wanted'" + }, + "original_release_date": { + "name": "original_release_date", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "release_status": { + "name": "release_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'upcoming'" + }, + "early_access": { + "name": "early_access", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "hidden": { + "name": "hidden", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_adult_content": { + "name": "is_adult_content", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_age_restricted": { + "name": "is_age_restricted", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "user_rating": { + "name": "user_rating", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "library_path": { + "name": "library_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "installed_version": { + "name": "installed_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "search_results_available": { + "name": "search_results_available", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "search_results_available_at": { + "name": "search_results_available_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "update_search_results_available": { + "name": "update_search_results_available", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "packs_search_results_available": { + "name": "packs_search_results_available", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "added_at": { + "name": "added_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + }, + "completed_at": { + "name": "completed_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "games_user_id_users_id_fk": { + "name": "games_user_id_users_id_fk", + "tableFrom": "games", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.import_task_items": { + "name": "import_task_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "item_name": { + "name": "item_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "result": { + "name": "result", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "game_title": { + "name": "game_title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": { + "import_task_items_task_id_idx": { + "name": "import_task_items_task_id_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "import_task_items_task_id_import_tasks_id_fk": { + "name": "import_task_items_task_id_import_tasks_id_fk", + "tableFrom": "import_task_items", + "tableTo": "import_tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.import_tasks": { + "name": "import_tasks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "task_type": { + "name": "task_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "triggered_by": { + "name": "triggered_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + }, + "started_at": { + "name": "started_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "total_items": { + "name": "total_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "added_items": { + "name": "added_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "skipped_items": { + "name": "skipped_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "failed_items": { + "name": "failed_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "import_tasks_user_id_users_id_fk": { + "name": "import_tasks_user_id_users_id_fk", + "tableFrom": "import_tasks", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.indexers": { + "name": "indexers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'torznab'" + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "categories": { + "name": "categories", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "rss_enabled": { + "name": "rss_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "auto_search_enabled": { + "name": "auto_search_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "allow_insecure_lan": { + "name": "allow_insecure_lan", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + }, + "updated_at": { + "name": "updated_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notifications": { + "name": "notifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "read": { + "name": "read", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": { + "notifications_user_id_users_id_fk": { + "name": "notifications_user_id_users_id_fk", + "tableFrom": "notifications", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.path_mappings": { + "name": "path_mappings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "remote_path": { + "name": "remote_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "local_path": { + "name": "local_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "remote_host": { + "name": "remote_host", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.platform_mappings": { + "name": "platform_mappings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "igdb_platform_id": { + "name": "igdb_platform_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "source_platform_name": { + "name": "source_platform_name", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.release_blacklist": { + "name": "release_blacklist", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "release_title": { + "name": "release_title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "indexer_name": { + "name": "indexer_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": { + "release_blacklist_game_title_idx": { + "name": "release_blacklist_game_title_idx", + "columns": [ + { + "expression": "game_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "release_title", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "release_blacklist_game_id_games_id_fk": { + "name": "release_blacklist_game_id_games_id_fk", + "tableFrom": "release_blacklist", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.root_folders": { + "name": "root_folders", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "allow_delete": { + "name": "allow_delete", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accessible": { + "name": "accessible", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "disk_free_bytes": { + "name": "disk_free_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "disk_total_bytes": { + "name": "disk_total_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "last_scanned_at": { + "name": "last_scanned_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "root_folders_path_unique": { + "name": "root_folders_path_unique", + "nullsNotDistinct": false, + "columns": ["path"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.rss_feed_items": { + "name": "rss_feed_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "feed_id": { + "name": "feed_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "guid": { + "name": "guid", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pub_date": { + "name": "pub_date", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "source_name": { + "name": "source_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "igdb_game_id": { + "name": "igdb_game_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "igdb_game_name": { + "name": "igdb_game_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cover_url": { + "name": "cover_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": { + "rss_feed_items_feed_id_rss_feeds_id_fk": { + "name": "rss_feed_items_feed_id_rss_feeds_id_fk", + "tableFrom": "rss_feed_items", + "tableTo": "rss_feeds", + "columnsFrom": ["feed_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.rss_feeds": { + "name": "rss_feeds", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'custom'" + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "mapping": { + "name": "mapping", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "last_check": { + "name": "last_check", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'ok'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + }, + "updated_at": { + "name": "updated_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.system_config": { + "name": "system_config", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_settings": { + "name": "user_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auto_search_enabled": { + "name": "auto_search_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "auto_download_enabled": { + "name": "auto_download_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "notification_preferences": { + "name": "notification_preferences", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "search_interval_hours": { + "name": "search_interval_hours", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 6 + }, + "igdb_rate_limit_per_second": { + "name": "igdb_rate_limit_per_second", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 3 + }, + "download_rules": { + "name": "download_rules", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_auto_search": { + "name": "last_auto_search", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "xrel_scene_releases": { + "name": "xrel_scene_releases", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "xrel_p2p_releases": { + "name": "xrel_p2p_releases", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auto_search_unreleased": { + "name": "auto_search_unreleased", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "steam_sync_failures": { + "name": "steam_sync_failures", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "steam_sync_enabled": { + "name": "steam_sync_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "steam_sync_interval_hours": { + "name": "steam_sync_interval_hours", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 24 + }, + "last_steam_sync": { + "name": "last_steam_sync", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "preferred_release_groups": { + "name": "preferred_release_groups", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "filter_by_preferred_groups": { + "name": "filter_by_preferred_groups", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "release_name_blacklist": { + "name": "release_name_blacklist", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "preferred_platform": { + "name": "preferred_platform", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hide_adult_content": { + "name": "hide_adult_content", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "hide_age_restricted_content": { + "name": "hide_age_restricted_content", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "hide_shelved_by_default": { + "name": "hide_shelved_by_default", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "hide_owned_in_has_results": { + "name": "hide_owned_in_has_results", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "enable_post_processing": { + "name": "enable_post_processing", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auto_unpack": { + "name": "auto_unpack", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "rename_pattern": { + "name": "rename_pattern", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'{Title} ({Region})'" + }, + "overwrite_existing": { + "name": "overwrite_existing", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "transfer_mode": { + "name": "transfer_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'hardlink'" + }, + "import_platform_ids": { + "name": "import_platform_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "ignored_extensions": { + "name": "ignored_extensions", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "min_file_size": { + "name": "min_file_size", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "library_root": { + "name": "library_root", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'/data'" + }, + "auto_delete_after_import": { + "name": "auto_delete_after_import", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "sort_extras": { + "name": "sort_extras", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "telemetry_enabled": { + "name": "telemetry_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": { + "user_settings_user_id_users_id_fk": { + "name": "user_settings_user_id_users_id_fk", + "tableFrom": "user_settings", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_settings_user_id_unique": { + "name": "user_settings_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "steam_id_64": { + "name": "steam_id_64", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_username_unique": { + "name": "users_username_unique", + "nullsNotDistinct": false, + "columns": ["username"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.xrel_notified_releases": { + "name": "xrel_notified_releases", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "xrel_release_id": { + "name": "xrel_release_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" + } + }, + "indexes": {}, + "foreignKeys": { + "xrel_notified_releases_game_id_games_id_fk": { + "name": "xrel_notified_releases_game_id_games_id_fk", + "tableFrom": "xrel_notified_releases", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/migrations-pg/meta/_journal.json b/migrations-pg/meta/_journal.json index db773ba15..beed4a2b4 100644 --- a/migrations-pg/meta/_journal.json +++ b/migrations-pg/meta/_journal.json @@ -64,6 +64,13 @@ "when": 1791212677241, "tag": "0008_cultured_stephen_strange", "breakpoints": true + }, + { + "idx": 9, + "version": "7", + "when": 1791216991452, + "tag": "0009_spicy_black_bolt", + "breakpoints": true } ] } diff --git a/migrations/0044_faulty_blazing_skull.sql b/migrations/0044_faulty_blazing_skull.sql new file mode 100644 index 000000000..299ea7abb --- /dev/null +++ b/migrations/0044_faulty_blazing_skull.sql @@ -0,0 +1 @@ +ALTER TABLE `game_downloads` ADD `category` text; \ No newline at end of file diff --git a/migrations/meta/0044_snapshot.json b/migrations/meta/0044_snapshot.json new file mode 100644 index 000000000..6aad78140 --- /dev/null +++ b/migrations/meta/0044_snapshot.json @@ -0,0 +1,2344 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "64392a36-24be-4d3c-a415-f902d38e52ce", + "prevId": "d6f633c9-9943-4e6d-b369-e5bfb84b2c60", + "tables": { + "ai_auto_download_holds": { + "name": "ai_auto_download_holds", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "release_title": { + "name": "release_title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "ai_auto_download_holds_game_title_idx": { + "name": "ai_auto_download_holds_game_title_idx", + "columns": ["game_id", "release_title"], + "isUnique": true + } + }, + "foreignKeys": { + "ai_auto_download_holds_game_id_games_id_fk": { + "name": "ai_auto_download_holds_game_id_games_id_fk", + "tableFrom": "ai_auto_download_holds", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "api_keys": { + "name": "api_keys", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "key_hash": { + "name": "key_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + }, + "last_used_at": { + "name": "last_used_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "api_keys_key_hash_idx": { + "name": "api_keys_key_hash_idx", + "columns": ["key_hash"], + "isUnique": true + }, + "api_keys_user_id_idx": { + "name": "api_keys_user_id_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "downloaders": { + "name": "downloaders", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "use_ssl": { + "name": "use_ssl", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "url_path": { + "name": "url_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "allow_self_signed_certificate": { + "name": "allow_self_signed_certificate", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "allow_insecure_lan": { + "name": "allow_insecure_lan", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "download_path": { + "name": "download_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'games'" + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'Questarr'" + }, + "add_stopped": { + "name": "add_stopped", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "remove_completed": { + "name": "remove_completed", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "post_import_category": { + "name": "post_import_category", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "settings": { + "name": "settings", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "game_downloads": { + "name": "game_downloads", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "downloader_id": { + "name": "downloader_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "download_type": { + "name": "download_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'torrent'" + }, + "download_hash": { + "name": "download_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "download_title": { + "name": "download_title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'downloading'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "file_size": { + "name": "file_size", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "added_at": { + "name": "added_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + }, + "completed_at": { + "name": "completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "game_downloads_downloader_hash_idx": { + "name": "game_downloads_downloader_hash_idx", + "columns": ["downloader_id", "download_hash"], + "isUnique": true + } + }, + "foreignKeys": { + "game_downloads_game_id_games_id_fk": { + "name": "game_downloads_game_id_games_id_fk", + "tableFrom": "game_downloads", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_downloads_downloader_id_downloaders_id_fk": { + "name": "game_downloads_downloader_id_downloaders_id_fk", + "tableFrom": "game_downloads", + "tableTo": "downloaders", + "columnsFrom": ["downloader_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "game_files": { + "name": "game_files", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "download_id": { + "name": "download_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "original_name": { + "name": "original_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "stored_name": { + "name": "stored_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category_overridden": { + "name": "category_overridden", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_size": { + "name": "file_size", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "game_files_game_id_idx": { + "name": "game_files_game_id_idx", + "columns": ["game_id"], + "isUnique": false + }, + "game_files_download_id_idx": { + "name": "game_files_download_id_idx", + "columns": ["download_id"], + "isUnique": false + } + }, + "foreignKeys": { + "game_files_game_id_games_id_fk": { + "name": "game_files_game_id_games_id_fk", + "tableFrom": "game_files", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_files_download_id_game_downloads_id_fk": { + "name": "game_files_download_id_game_downloads_id_fk", + "tableFrom": "game_files", + "tableTo": "game_downloads", + "columnsFrom": ["download_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "game_journal_entries": { + "name": "game_journal_entries", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "game_journal_entries_game_user_idx": { + "name": "game_journal_entries_game_user_idx", + "columns": ["game_id", "user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "game_journal_entries_game_id_games_id_fk": { + "name": "game_journal_entries_game_id_games_id_fk", + "tableFrom": "game_journal_entries", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_journal_entries_user_id_users_id_fk": { + "name": "game_journal_entries_user_id_users_id_fk", + "tableFrom": "game_journal_entries", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "game_milestones": { + "name": "game_milestones", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "completed_at": { + "name": "completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "game_milestones_game_user_idx": { + "name": "game_milestones_game_user_idx", + "columns": ["game_id", "user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "game_milestones_game_id_games_id_fk": { + "name": "game_milestones_game_id_games_id_fk", + "tableFrom": "game_milestones", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_milestones_user_id_users_id_fk": { + "name": "game_milestones_user_id_users_id_fk", + "tableFrom": "game_milestones", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "game_screenshots": { + "name": "game_screenshots", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "caption": { + "name": "caption", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "game_screenshots_game_user_idx": { + "name": "game_screenshots_game_user_idx", + "columns": ["game_id", "user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "game_screenshots_game_id_games_id_fk": { + "name": "game_screenshots_game_id_games_id_fk", + "tableFrom": "game_screenshots", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "game_screenshots_user_id_users_id_fk": { + "name": "game_screenshots_user_id_users_id_fk", + "tableFrom": "game_screenshots", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "games": { + "name": "games", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "igdb_id": { + "name": "igdb_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "steam_appid": { + "name": "steam_appid", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cover_url": { + "name": "cover_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "release_date": { + "name": "release_date", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rating": { + "name": "rating", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "platforms": { + "name": "platforms", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_platform_id": { + "name": "target_platform_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_platform_name": { + "name": "target_platform_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "genres": { + "name": "genres", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "themes": { + "name": "themes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "publishers": { + "name": "publishers", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "developers": { + "name": "developers", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "screenshots": { + "name": "screenshots", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'manual'" + }, + "igdb_websites": { + "name": "igdb_websites", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expansions": { + "name": "expansions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "aggregated_rating": { + "name": "aggregated_rating", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_to_beat_hastily": { + "name": "time_to_beat_hastily", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_to_beat_normally": { + "name": "time_to_beat_normally", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_to_beat_completely": { + "name": "time_to_beat_completely", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'wanted'" + }, + "original_release_date": { + "name": "original_release_date", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "release_status": { + "name": "release_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'upcoming'" + }, + "early_access": { + "name": "early_access", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "hidden": { + "name": "hidden", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "is_adult_content": { + "name": "is_adult_content", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "is_age_restricted": { + "name": "is_age_restricted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "user_rating": { + "name": "user_rating", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "library_path": { + "name": "library_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "installed_version": { + "name": "installed_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "search_results_available": { + "name": "search_results_available", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "search_results_available_at": { + "name": "search_results_available_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "update_search_results_available": { + "name": "update_search_results_available", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "packs_search_results_available": { + "name": "packs_search_results_available", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "added_at": { + "name": "added_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + }, + "completed_at": { + "name": "completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "games_user_id_users_id_fk": { + "name": "games_user_id_users_id_fk", + "tableFrom": "games", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "import_task_items": { + "name": "import_task_items", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "item_name": { + "name": "item_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "result": { + "name": "result", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "game_title": { + "name": "game_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "import_task_items_task_id_idx": { + "name": "import_task_items_task_id_idx", + "columns": ["task_id"], + "isUnique": false + } + }, + "foreignKeys": { + "import_task_items_task_id_import_tasks_id_fk": { + "name": "import_task_items_task_id_import_tasks_id_fk", + "tableFrom": "import_task_items", + "tableTo": "import_tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "import_tasks": { + "name": "import_tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "task_type": { + "name": "task_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "triggered_by": { + "name": "triggered_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + }, + "started_at": { + "name": "started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "completed_at": { + "name": "completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "total_items": { + "name": "total_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "added_items": { + "name": "added_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "skipped_items": { + "name": "skipped_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "failed_items": { + "name": "failed_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "import_tasks_user_id_users_id_fk": { + "name": "import_tasks_user_id_users_id_fk", + "tableFrom": "import_tasks", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "indexers": { + "name": "indexers", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "protocol": { + "name": "protocol", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'torznab'" + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "categories": { + "name": "categories", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'[]'" + }, + "rss_enabled": { + "name": "rss_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "auto_search_enabled": { + "name": "auto_search_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "allow_insecure_lan": { + "name": "allow_insecure_lan", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "notifications": { + "name": "notifications", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "read": { + "name": "read", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": {}, + "foreignKeys": { + "notifications_user_id_users_id_fk": { + "name": "notifications_user_id_users_id_fk", + "tableFrom": "notifications", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "path_mappings": { + "name": "path_mappings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "remote_path": { + "name": "remote_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "local_path": { + "name": "local_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "remote_host": { + "name": "remote_host", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "platform_mappings": { + "name": "platform_mappings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "igdb_platform_id": { + "name": "igdb_platform_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_platform_name": { + "name": "source_platform_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "release_blacklist": { + "name": "release_blacklist", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "release_title": { + "name": "release_title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "indexer_name": { + "name": "indexer_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "release_blacklist_game_title_idx": { + "name": "release_blacklist_game_title_idx", + "columns": ["game_id", "release_title"], + "isUnique": true + } + }, + "foreignKeys": { + "release_blacklist_game_id_games_id_fk": { + "name": "release_blacklist_game_id_games_id_fk", + "tableFrom": "release_blacklist", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "root_folders": { + "name": "root_folders", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "allow_delete": { + "name": "allow_delete", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "accessible": { + "name": "accessible", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "disk_free_bytes": { + "name": "disk_free_bytes", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "disk_total_bytes": { + "name": "disk_total_bytes", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_scanned_at": { + "name": "last_scanned_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "root_folders_path_unique": { + "name": "root_folders_path_unique", + "columns": ["path"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "rss_feed_items": { + "name": "rss_feed_items", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "feed_id": { + "name": "feed_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "guid": { + "name": "guid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "pub_date": { + "name": "pub_date", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source_name": { + "name": "source_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "igdb_game_id": { + "name": "igdb_game_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "igdb_game_name": { + "name": "igdb_game_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cover_url": { + "name": "cover_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": {}, + "foreignKeys": { + "rss_feed_items_feed_id_rss_feeds_id_fk": { + "name": "rss_feed_items_feed_id_rss_feeds_id_fk", + "tableFrom": "rss_feed_items", + "tableTo": "rss_feeds", + "columnsFrom": ["feed_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "rss_feeds": { + "name": "rss_feeds", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'custom'" + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "mapping": { + "name": "mapping", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_check": { + "name": "last_check", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'ok'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "system_config": { + "name": "system_config", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_settings": { + "name": "user_settings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "auto_search_enabled": { + "name": "auto_search_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "auto_download_enabled": { + "name": "auto_download_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "notification_preferences": { + "name": "notification_preferences", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "search_interval_hours": { + "name": "search_interval_hours", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 6 + }, + "igdb_rate_limit_per_second": { + "name": "igdb_rate_limit_per_second", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 3 + }, + "download_rules": { + "name": "download_rules", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_auto_search": { + "name": "last_auto_search", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "xrel_scene_releases": { + "name": "xrel_scene_releases", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "xrel_p2p_releases": { + "name": "xrel_p2p_releases", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "auto_search_unreleased": { + "name": "auto_search_unreleased", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "steam_sync_failures": { + "name": "steam_sync_failures", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "steam_sync_enabled": { + "name": "steam_sync_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "steam_sync_interval_hours": { + "name": "steam_sync_interval_hours", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 24 + }, + "last_steam_sync": { + "name": "last_steam_sync", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "preferred_release_groups": { + "name": "preferred_release_groups", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "filter_by_preferred_groups": { + "name": "filter_by_preferred_groups", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "release_name_blacklist": { + "name": "release_name_blacklist", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "preferred_platform": { + "name": "preferred_platform", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hide_adult_content": { + "name": "hide_adult_content", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "hide_age_restricted_content": { + "name": "hide_age_restricted_content", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "hide_shelved_by_default": { + "name": "hide_shelved_by_default", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "hide_owned_in_has_results": { + "name": "hide_owned_in_has_results", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "enable_post_processing": { + "name": "enable_post_processing", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "auto_unpack": { + "name": "auto_unpack", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "rename_pattern": { + "name": "rename_pattern", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{Title} ({Region})'" + }, + "overwrite_existing": { + "name": "overwrite_existing", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "transfer_mode": { + "name": "transfer_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'hardlink'" + }, + "import_platform_ids": { + "name": "import_platform_ids", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'[]'" + }, + "ignored_extensions": { + "name": "ignored_extensions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'[]'" + }, + "min_file_size": { + "name": "min_file_size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "library_root": { + "name": "library_root", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'/data'" + }, + "auto_delete_after_import": { + "name": "auto_delete_after_import", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "sort_extras": { + "name": "sort_extras", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "telemetry_enabled": { + "name": "telemetry_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": { + "user_settings_user_id_unique": { + "name": "user_settings_user_id_unique", + "columns": ["user_id"], + "isUnique": true + } + }, + "foreignKeys": { + "user_settings_user_id_users_id_fk": { + "name": "user_settings_user_id_users_id_fk", + "tableFrom": "user_settings", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "steam_id_64": { + "name": "steam_id_64", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "users_username_unique": { + "name": "users_username_unique", + "columns": ["username"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "xrel_notified_releases": { + "name": "xrel_notified_releases", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "game_id": { + "name": "game_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "xrel_release_id": { + "name": "xrel_release_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(strftime('%s', 'now') * 1000)" + } + }, + "indexes": {}, + "foreignKeys": { + "xrel_notified_releases_game_id_games_id_fk": { + "name": "xrel_notified_releases_game_id_games_id_fk", + "tableFrom": "xrel_notified_releases", + "tableTo": "games", + "columnsFrom": ["game_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/migrations/meta/_journal.json b/migrations/meta/_journal.json index 6a0ba9d8e..b469e0f64 100644 --- a/migrations/meta/_journal.json +++ b/migrations/meta/_journal.json @@ -316,6 +316,13 @@ "when": 1791212676341, "tag": "0043_massive_dormammu", "breakpoints": true + }, + { + "idx": 44, + "version": "6", + "when": 1791216990567, + "tag": "0044_faulty_blazing_skull", + "breakpoints": true } ] } diff --git a/server/__tests__/api_routes.test.ts b/server/__tests__/api_routes.test.ts index ba7434899..2686f4a83 100644 --- a/server/__tests__/api_routes.test.ts +++ b/server/__tests__/api_routes.test.ts @@ -3110,6 +3110,26 @@ describe("API Routes - Extended Coverage", () => { ); }); + it("stores the category picked for the claimed download", async () => { + vi.mocked(storage.getTrackedDownloadKeys).mockResolvedValue(new Set()); + mockSabnzbdClaimTarget(); + vi.mocked(storage.addGameDownload).mockResolvedValue(undefined as any); + + const res = await request(app).post("/api/downloads/claim").send({ + downloaderId: "dl-1", + downloadHash: USENET_MIXED_CASE_ID, + downloadTitle: "Expansion.Name.v5.0", + currentStatus: "downloading", + category: "dlc", + gameId: "game-1", + }); + + expect(res.status).toBe(200); + expect(storage.addGameDownload).toHaveBeenCalledWith( + expect.objectContaining({ category: "dlc" }) + ); + }); + it("rejects a claim as a duplicate when the mixed-case Usenet id is already tracked", async () => { vi.mocked(storage.getTrackedDownloadKeys).mockResolvedValue( new Set([`dl-1:${USENET_MIXED_CASE_ID}`]) diff --git a/server/__tests__/game-version.test.ts b/server/__tests__/game-version.test.ts index 9a32c2e7b..69d64228a 100644 --- a/server/__tests__/game-version.test.ts +++ b/server/__tests__/game-version.test.ts @@ -52,6 +52,18 @@ describe("recordVersionFromCompletedDownload", () => { expect(await record(null, "Test.Game.Complete.Edition.v3.1-RUNE")).toBe("v3.1"); }); + it("trusts the category the user picked over the title", async () => { + getGame.mockResolvedValue({ id: "g1", installedVersion: null }); + // Claimed as DLC although the title reads like the base game. + expect( + await recordVersionFromCompletedDownload(store, "g1", "Expansion.Name.v5.0", "dlc") + ).toBeNull(); + // Claimed as the main game although the title mentions DLC. + expect( + await recordVersionFromCompletedDownload(store, "g1", "Game.Season.Pass.DLC.v2.0", "main") + ).toBe("v2.0"); + }); + it("does not notify when the version changed before the write", async () => { replaceGameInstalledVersion.mockResolvedValue(false); expect(await record("v1.0", "Test.Game.Update.v1.1-RUNE")).toBeNull(); diff --git a/server/cron.ts b/server/cron.ts index dc4a9b734..57ec91c16 100644 --- a/server/cron.ts +++ b/server/cron.ts @@ -963,7 +963,8 @@ export async function checkDownloadStatus() { await recordVersionFromCompletedDownload( storage, download.gameId, - download.downloadTitle + download.downloadTitle, + download.category ); // Update Game status to 'owned' (which means we have the files), unless diff --git a/server/game-version.ts b/server/game-version.ts index fa7aa6b9b..20839ae8b 100644 --- a/server/game-version.ts +++ b/server/game-version.ts @@ -11,7 +11,9 @@ import { notifyUser } from "./socket.js"; const DLC_ONLY = /\b(?:dlc|downloadable content|expansion|season pass)\b/i; const BUNDLED_DLC = /(?:\bincl(?:uding)?|\bwith|\+)[\s._-]*(?:all[\s._-]*)?dlcs?\b/gi; -function carriesBaseGameVersion(downloadTitle: string): boolean { +function carriesBaseGameVersion(downloadTitle: string, pickedCategory: string | null): boolean { + // The user's own pick (when claiming a download) beats anything read from the title. + if (pickedCategory) return pickedCategory === "main" || pickedCategory === "update"; const { category } = categorizeDownload(downloadTitle); if (category === "main" || category === "update") return true; return category === "dlc" && !DLC_ONLY.test(downloadTitle.replace(BUNDLED_DLC, "")); @@ -23,17 +25,19 @@ function carriesBaseGameVersion(downloadTitle: string): boolean { * finishes with post-processing off, or when the import is finalized. Only the full game * (editions included) or an update counts (a DLC's version says nothing about the base game), * and a known version is only ever moved forward: an older or incomparable release never - * overwrites what the user has. + * overwrites what the user has. `category` is the one the user picked when claiming the + * download, if any; otherwise it is inferred from the title. * Never throws, so a failure here can't break the download or import flow. Returns the version * recorded, if any. */ export async function recordVersionFromCompletedDownload( store: Pick, gameId: string, - downloadTitle: string + downloadTitle: string, + category: string | null = null ): Promise { try { - if (!carriesBaseGameVersion(downloadTitle)) return null; + if (!carriesBaseGameVersion(downloadTitle, category)) return null; const detected = extractVersionFromReleaseName(downloadTitle); if (!detected) return null; diff --git a/server/routes.ts b/server/routes.ts index d7bb26d3d..19d86c369 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -4103,6 +4103,7 @@ export async function registerRoutes(app: Express): Promise { downloadTitle, downloadType: isUsenetDownloaderType(downloader.type) ? "usenet" : "torrent", status: downloadStatus, + category, }) ); @@ -4271,6 +4272,7 @@ export async function registerRoutes(app: Express): Promise { downloadTitle: item.downloadTitle, downloadType: isUsenetDownloaderType(downloader.type) ? "usenet" : "torrent", status: downloadStatus, + category: item.category, }) ); await storage.updateGameSearchResultsAvailable(resolvedGameId, false); diff --git a/server/services/ImportManager.ts b/server/services/ImportManager.ts index 214bad325..dea840d9d 100644 --- a/server/services/ImportManager.ts +++ b/server/services/ImportManager.ts @@ -554,7 +554,12 @@ export class ImportManager { try { const download = await this.storage.getGameDownload(downloadId); if (download) { - await recordVersionFromCompletedDownload(this.storage, game.id, download.downloadTitle); + await recordVersionFromCompletedDownload( + this.storage, + game.id, + download.downloadTitle, + download.category + ); } } catch (error) { logger.warn({ error, downloadId }, "[ImportManager] Could not record the installed version"); diff --git a/server/storage.ts b/server/storage.ts index a0b85f0ec..28bffee3e 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -1277,6 +1277,7 @@ export class MemStorage implements IStorage { downloadType: insertGameDownload.downloadType || "torrent", errorMessage: insertGameDownload.errorMessage ?? null, fileSize: insertGameDownload.fileSize ?? null, + category: insertGameDownload.category ?? null, addedAt: new Date(), completedAt: null, }; @@ -2825,6 +2826,7 @@ export class DatabaseStorage implements IStorage { status: gameDownloads.status, errorMessage: gameDownloads.errorMessage, fileSize: gameDownloads.fileSize, + category: gameDownloads.category, addedAt: gameDownloads.addedAt, completedAt: gameDownloads.completedAt, downloaderName: downloaders.name, diff --git a/shared/schema.pg.ts b/shared/schema.pg.ts index 96f3b3e98..30356af6f 100644 --- a/shared/schema.pg.ts +++ b/shared/schema.pg.ts @@ -251,6 +251,7 @@ export const gameDownloads = pgTable( status: text("status").notNull().default("downloading"), errorMessage: text("error_message"), fileSize: bigint("file_size", { mode: "number" }), + category: text("category"), addedAt: timestampMs("added_at").default(sql`(EXTRACT(EPOCH FROM now()) * 1000)::bigint`), completedAt: timestampMs("completed_at"), }, diff --git a/shared/schema.ts b/shared/schema.ts index 40bdff14e..ef2ea469d 100644 --- a/shared/schema.ts +++ b/shared/schema.ts @@ -323,6 +323,9 @@ export const gameDownloads = sqliteTable( status: text("status").notNull().default("downloading"), errorMessage: text("error_message"), fileSize: integer("file_size"), + // The category the user picked when claiming the download (main, update, dlc...); null when + // it was only ever inferred from the title. + category: text("category"), addedAt: integer("added_at", { mode: "timestamp_ms" }).default( sql`(strftime('%s', 'now') * 1000)` ), From f5e5d483f781e8e85c5172f4c8739b4a9d77d41b Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 16:24:57 +0000 Subject: [PATCH 13/28] Skip early-access and hotfix versions, take the highest build of any build range Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- shared/__tests__/version-utils.test.ts | 4 ++++ shared/version-utils.ts | 15 ++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/shared/__tests__/version-utils.test.ts b/shared/__tests__/version-utils.test.ts index 3e8ee4087..b45d09833 100644 --- a/shared/__tests__/version-utils.test.ts +++ b/shared/__tests__/version-utils.test.ts @@ -22,6 +22,7 @@ describe("extractVersionFromReleaseName", () => { ["Game.v1.4.Update.Build.5000-RUNE", "Build 5000"], // the update's build target wins ["Game.Update.v1.0.to.v1.1-RUNE", "v1.1"], // an update's target, not its start ["Game.Update.Build.1000.to.Build.1200-RUNE", "Build 1200"], // same for build ranges + ["Game.Patch.Build.1000.to.Build.1200-RUNE", "Build 1200"], // without the word Update too ["Game.v1.2.Repack-PREDATOR", "v1.2"], // a group name is not a pre-release tag ])("finds the version in %s", (name, expected) => { expect(extractVersionFromReleaseName(name)).toBe(expected); @@ -35,6 +36,9 @@ describe("extractVersionFromReleaseName", () => { "Game.Update.v1.2-beta-RUNE", // pre-releases: a stable v1.2 would supersede it "Game.v2.0.RC1-GOG", "Game v1.3 Preview", + "Game.v1.2.Early.Access-P2P", // qualifiers that order differently from the bare number + "Game.Update.v1.2.Hotfix-RUNE", + "Game.v1.2.Fix-RUNE", ])("finds nothing in %s", (name) => { expect(extractVersionFromReleaseName(name)).toBeNull(); }); diff --git a/shared/version-utils.ts b/shared/version-utils.ts index 56d16e820..3f06b7287 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -41,9 +41,11 @@ const UPDATE_BUILD_VERSION = new RegExp( "i" ); -// "v1.2-beta", "1.2.RC1", "v2.0 Preview": a pre-release, which a later stable release of the -// same number supersedes. Names carrying one are treated as having no readable version. -const PRERELEASE_VERSION = /\d[\s._-]?(?:alpha|beta|rc|pre|preview|dev)(?![a-z])/i; +// "v1.2-beta", "1.2.RC1", "v2.0 Preview", "v1.2.Early.Access", "v1.2.Hotfix": a qualifier whose +// ordering against the bare number ("v1.2") isn't captured by it -- a later stable release or a +// hotfix of the same number differs. Names carrying one are treated as having no readable version. +const QUALIFIED_VERSION = + /\d[\s._-]?(?:alpha|beta|rc|pre|preview|dev|early[\s._-]?access|hot[\s._-]?fix|fix)(?![a-z])/i; const BUILD_VERSION_ALL = new RegExp(BUILD_VERSION.source, "gi"); /** @@ -51,7 +53,7 @@ const BUILD_VERSION_ALL = new RegExp(BUILD_VERSION.source, "gi"); * "Build 12345"), or null when the name carries none. */ export function extractVersionFromReleaseName(releaseName: string): string | null { - if (PRERELEASE_VERSION.test(releaseName)) return null; + if (QUALIFIED_VERSION.test(releaseName)) return null; // An update names the version it brings the game to, so what follows "Update" wins over the // base version before it ("Game.v1.0.Update.v1.1"), and its highest version wins over its // starting one ("Game.Update.v1.0.to.v1.1"). @@ -66,9 +68,8 @@ export function extractVersionFromReleaseName(releaseName: string): string | nul // Otherwise the highest of the versions named ("Game.v1.0.to.v1.1" brings the game to v1.1). const best = highestVVersion(releaseName, null); if (best) return best; - const build = BUILD_VERSION.exec(releaseName); - if (build?.[1]) return `Build ${build[1]}`; - return null; + // A build range ("Patch.Build.1000.to.Build.1200") brings the game to its highest build. + return highestBuild(releaseName); } function highestVVersion(text: string, initial: string | null): string | null { From 8c694085351b5acfa7d2392a71288b9b324a8069 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 16:37:14 +0000 Subject: [PATCH 14/28] Store the release category of searched and auto-grabbed downloads, ignore untargeted updates Version suggestions now only come from base-game downloads. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- client/src/components/GameDetailsModal.tsx | 6 ++- client/src/components/GameDownloadDialog.tsx | 6 +++ .../api_routes_async_download.test.ts | 44 ++++++++++++++++- server/cron.ts | 1 + server/game-version.ts | 26 +++------- server/middleware.ts | 4 ++ server/routes.ts | 14 +++++- shared/__tests__/version-utils.test.ts | 18 +++++++ shared/version-utils.ts | 47 +++++++++++++++++-- 9 files changed, 138 insertions(+), 28 deletions(-) diff --git a/client/src/components/GameDetailsModal.tsx b/client/src/components/GameDetailsModal.tsx index 6e6152be4..7816a521f 100644 --- a/client/src/components/GameDetailsModal.tsx +++ b/client/src/components/GameDetailsModal.tsx @@ -98,6 +98,7 @@ import { type XrelGameStatus } from "@shared/xrel-types"; import StatusBadge, { getStatusLabel } from "./StatusBadge"; import { apiRequest } from "@/lib/queryClient"; import { cn, safeUrl, formatBytes, isDiscoveryId } from "@/lib/utils"; +import { carriesBaseGameVersion } from "@shared/version-utils"; const GameDownloadDialog = lazy(() => import("./GameDownloadDialog")); @@ -637,7 +638,10 @@ export default function GameDetailsModal({ game, open, onOpenChange }: GameDetai }); const downloadReleaseNames = useMemo( - () => gameDownloads.map((download) => download.downloadTitle), + () => + gameDownloads + .filter((download) => carriesBaseGameVersion(download.downloadTitle, download.category)) + .map((download) => download.downloadTitle), [gameDownloads] ); diff --git a/client/src/components/GameDownloadDialog.tsx b/client/src/components/GameDownloadDialog.tsx index abce05438..a3d6bb782 100644 --- a/client/src/components/GameDownloadDialog.tsx +++ b/client/src/components/GameDownloadDialog.tsx @@ -77,6 +77,7 @@ import { } from "@shared/schema"; import { getCategoryLabel, + categorizeDownload, groupDownloadsByCategory, type DownloadCategory, } from "@shared/download-categorizer"; @@ -543,6 +544,11 @@ export default function GameDownloadDialog({ game, open, onOpenChange }: GameDow title: download.title, gameId: game?.id, downloadType: isUsenetItem(download) ? "usenet" : "torrent", + releaseCategory: categorizeDownload( + download.title, + download.aiReleaseType, + download.aiReleaseTypeConfidence + ).category, }); results.push(await response.json()); } diff --git a/server/__tests__/api_routes_async_download.test.ts b/server/__tests__/api_routes_async_download.test.ts index f481537cf..e0b640f37 100644 --- a/server/__tests__/api_routes_async_download.test.ts +++ b/server/__tests__/api_routes_async_download.test.ts @@ -142,7 +142,12 @@ describe("POST /api/downloads — async qBittorrent tracking", () => { mockGameRow(opts.gameId, opts.title); } - async function postDownload(payload: { url: string; title: string; gameId: string }) { + async function postDownload(payload: { + url: string; + title: string; + gameId: string; + releaseCategory?: string; + }) { const res = await request(app).post("/api/downloads").send(payload); expect(res.status).toBe(200); expect(res.body.success).toBe(true); @@ -265,6 +270,43 @@ describe("POST /api/downloads — async qBittorrent tracking", () => { ); }); + it("stores the release category the client classified the download as", async () => { + const gameId = "123e4567-e89b-12d3-a456-426614174002"; + mockSuccessCase({ + fallback: { + success: true, + id: "realhash123", + downloaderId: "d-1", + downloaderName: "qBittorrent", + attemptedDownloaders: ["qBittorrent"], + }, + gdId: "gd-2", + gameId, + hash: "realhash123", + title: "Expansion.Name.v5.0", + }); + + await postDownload({ + url: "https://example.com/sync.torrent", + title: "Expansion.Name.v5.0", + gameId, + releaseCategory: "dlc", + }); + + expect(storage.addGameDownload).toHaveBeenCalledWith( + expect.objectContaining({ category: "dlc" }) + ); + }); + + it("rejects an unknown release category", async () => { + const res = await request(app).post("/api/downloads").send({ + url: "https://example.com/sync.torrent", + title: "Game", + releaseCategory: "bogus", + }); + expect(res.status).toBe(400); + }); + it("prefers result.id over result.correlationTag when both are present", async () => { // Edge case: downloader returns both a real hash AND a correlationTag. // The route must use the real hash (id), not the tag. diff --git a/server/cron.ts b/server/cron.ts index 57ec91c16..f1655e675 100644 --- a/server/cron.ts +++ b/server/cron.ts @@ -1451,6 +1451,7 @@ export async function checkAutoSearch() { downloadTitle: item.title, status: "downloading", downloadType: item.downloadType, + category: "main", }); // Update game status diff --git a/server/game-version.ts b/server/game-version.ts index 20839ae8b..e26bdfca8 100644 --- a/server/game-version.ts +++ b/server/game-version.ts @@ -1,32 +1,20 @@ -import { categorizeDownload } from "../shared/download-categorizer.js"; -import { compareVersions, extractVersionFromReleaseName } from "../shared/version-utils.js"; +import { + carriesBaseGameVersion, + compareVersions, + extractVersionFromReleaseName, +} from "../shared/version-utils.js"; import type { IStorage } from "./storage.js"; import { logger } from "./logger.js"; import { notifyUser } from "./socket.js"; -// The categorizer files edition names ("Deluxe", "GOTY", "Complete") under DLC because those -// releases bundle DLC, but they are full games and their version is the base game's. Only these -// words mark a release that is DLC alone, once bundle mentions ("incl.DLC", "+ all DLCs") are -// set aside. -const DLC_ONLY = /\b(?:dlc|downloadable content|expansion|season pass)\b/i; -const BUNDLED_DLC = /(?:\bincl(?:uding)?|\bwith|\+)[\s._-]*(?:all[\s._-]*)?dlcs?\b/gi; - -function carriesBaseGameVersion(downloadTitle: string, pickedCategory: string | null): boolean { - // The user's own pick (when claiming a download) beats anything read from the title. - if (pickedCategory) return pickedCategory === "main" || pickedCategory === "update"; - const { category } = categorizeDownload(downloadTitle); - if (category === "main" || category === "update") return true; - return category === "dlc" && !DLC_ONLY.test(downloadTitle.replace(BUNDLED_DLC, "")); -} - /** * Records the version carried by an installed download's release name (e.g. "v1.2.3") as the * game's installed version. Call it once the files are really in place: when the download * finishes with post-processing off, or when the import is finalized. Only the full game * (editions included) or an update counts (a DLC's version says nothing about the base game), * and a known version is only ever moved forward: an older or incomparable release never - * overwrites what the user has. `category` is the one the user picked when claiming the - * download, if any; otherwise it is inferred from the title. + * overwrites what the user has. `category` is the one stored with the download, if any; + * otherwise it is inferred from the title. * Never throws, so a failure here can't break the download or import flow. Returns the version * recorded, if any. */ diff --git a/server/middleware.ts b/server/middleware.ts index 44c369e05..2fa88eb59 100644 --- a/server/middleware.ts +++ b/server/middleware.ts @@ -500,6 +500,10 @@ export const sanitizeDownloaderDownloadData = [ .trim() .isLength({ max: 100 }) .withMessage("Category must be at most 100 characters"), + body("releaseCategory") + .optional() + .isIn(["main", "update", "dlc", "extra", "packs"]) + .withMessage("Invalid release category"), body("downloadType") .optional() .trim() diff --git a/server/routes.ts b/server/routes.ts index 19d86c369..8211427ca 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -4351,8 +4351,17 @@ export async function registerRoutes(app: Express): Promise { validateRequest, async (req: Request, res: Response) => { try { - const { url, title, category, downloadPath, priority, gameId, downloadType, password } = - req.body; + const { + url, + title, + category, + downloadPath, + priority, + gameId, + downloadType, + password, + releaseCategory, + } = req.body; if (!url || !title) { return res.status(400).json({ error: "URL and title are required" }); @@ -4411,6 +4420,7 @@ export async function registerRoutes(app: Express): Promise { downloadTitle: title, status: "downloading", downloadType: downloadType || "torrent", + category: releaseCategory ?? null, }); // An update/DLC grabbed for a game the user is playing (or has diff --git a/shared/__tests__/version-utils.test.ts b/shared/__tests__/version-utils.test.ts index b45d09833..30fa636fa 100644 --- a/shared/__tests__/version-utils.test.ts +++ b/shared/__tests__/version-utils.test.ts @@ -2,6 +2,7 @@ import { describe, it, expect } from "vitest"; import { compareVersions, extractVersionFromReleaseName, + carriesBaseGameVersion, isReleasePossiblyNewer, parseVersion, } from "../version-utils"; @@ -39,6 +40,9 @@ describe("extractVersionFromReleaseName", () => { "Game.v1.2.Early.Access-P2P", // qualifiers that order differently from the bare number "Game.Update.v1.2.Hotfix-RUNE", "Game.v1.2.Fix-RUNE", + "Game.v1.2.Update-RUNE", // an update whose target isn't named + "Game.v1.2.Update.2-CODEX", + "Game.v1.2.Patch-RUNE", ])("finds nothing in %s", (name) => { expect(extractVersionFromReleaseName(name)).toBeNull(); }); @@ -78,6 +82,20 @@ describe("compareVersions", () => { }); }); +describe("carriesBaseGameVersion", () => { + it("follows the stored category when there is one", () => { + expect(carriesBaseGameVersion("Expansion.Name.v5.0", "dlc")).toBe(false); + expect(carriesBaseGameVersion("Game.Season.Pass.DLC.v2.0", "update")).toBe(true); + }); + + it("reads the title otherwise, counting editions as the full game", () => { + expect(carriesBaseGameVersion("Game.v1.2-RUNE", null)).toBe(true); + expect(carriesBaseGameVersion("Game.GOTY.v2.0.incl.DLC-GOG", null)).toBe(true); + expect(carriesBaseGameVersion("Game.Season.Pass.DLC.v5.0-RUNE", null)).toBe(false); + expect(carriesBaseGameVersion("Game.OST-RUNE", undefined)).toBe(false); + }); +}); + describe("isReleasePossiblyNewer", () => { it("is true when nothing is known", () => { expect(isReleasePossiblyNewer("Game.Update.v1.1-RUNE", null)).toBe(true); diff --git a/shared/version-utils.ts b/shared/version-utils.ts index 3f06b7287..bac6cd0b7 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -1,3 +1,5 @@ +import { categorizeDownload } from "./download-categorizer.js"; + /** * Game version helpers: detect a version in a release name, and compare two versions. * @@ -47,6 +49,10 @@ const UPDATE_BUILD_VERSION = new RegExp( const QUALIFIED_VERSION = /\d[\s._-]?(?:alpha|beta|rc|pre|preview|dev|early[\s._-]?access|hot[\s._-]?fix|fix)(?![a-z])/i; const BUILD_VERSION_ALL = new RegExp(BUILD_VERSION.source, "gi"); +const UPDATE_MARKER = new RegExp( + String.raw`${NOT_PRECEDED_BY_ALNUM}(?:update|patch)${NOT_FOLLOWED_BY_ALNUM}`, + "i" +); /** * Finds a version in a release name and returns it in display form ("v1.2.3" or @@ -65,11 +71,20 @@ export function extractVersionFromReleaseName(releaseName: string): string | nul // Likewise for builds: "Update.Build.1000.to.Build.1200" brings the game to Build 1200. const updateBuild = UPDATE_BUILD_VERSION.exec(releaseName); if (updateBuild) return highestBuild(releaseName.slice(updateBuild.index)); - // Otherwise the highest of the versions named ("Game.v1.0.to.v1.1" brings the game to v1.1). - const best = highestVVersion(releaseName, null); - if (best) return best; - // A build range ("Patch.Build.1000.to.Build.1200") brings the game to its highest build. - return highestBuild(releaseName); + // An update or patch with no target named carries the base game's version at most + // ("Game.v1.2.Update"), which says nothing about where it leads; only a range does + // ("Game.v1.0.to.v1.1.Patch", "Patch.Build.1000.to.Build.1200"). + if (UPDATE_MARKER.test(releaseName)) { + if (countMatches(releaseName, V_VERSION_ALL) > 1) return highestVVersion(releaseName, null); + if (countMatches(releaseName, BUILD_VERSION_ALL) > 1) return highestBuild(releaseName); + return null; + } + // Otherwise the highest of the versions named, then of the builds. + return highestVVersion(releaseName, null) ?? highestBuild(releaseName); +} + +function countMatches(text: string, pattern: RegExp): number { + return Array.from(text.matchAll(pattern)).length; } function highestVVersion(text: string, initial: string | null): string | null { @@ -140,3 +155,25 @@ export function isReleasePossiblyNewer( const cmp = compareVersions(releaseVersion, installedVersion); return cmp === null || cmp > 0; } + +// The categorizer files edition names ("Deluxe", "GOTY", "Complete") under DLC because those +// releases bundle DLC, but they are full games and their version is the base game's. Only these +// words mark a release that is DLC alone, once bundle mentions ("incl.DLC", "+ all DLCs") are +// set aside. +const DLC_ONLY = /\b(?:dlc|downloadable content|expansion|season pass)\b/i; +const BUNDLED_DLC = /(?:\bincl(?:uding)?|\bwith|\+)[\s._-]*(?:all[\s._-]*)?dlcs?\b/gi; + +/** + * Whether a download's version is the base game's: true for the full game (editions included) + * and updates, false for DLC, packs and extras. `category` is the one stored with the download + * (picked by the user, or classified when it was grabbed); without it, the title decides. + */ +export function carriesBaseGameVersion( + downloadTitle: string, + category: string | null | undefined +): boolean { + if (category) return category === "main" || category === "update"; + const byTitle = categorizeDownload(downloadTitle).category; + if (byTitle === "main" || byTitle === "update") return true; + return byTitle === "dlc" && !DLC_ONLY.test(downloadTitle.replace(BUNDLED_DLC, "")); +} From dd29ac8eecadb967a8847d0fa3daa2779912363f Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 16:47:51 +0000 Subject: [PATCH 15/28] Read versions after Patch markers, store full-game editions as main Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- client/src/components/GameDownloadDialog.tsx | 6 +-- shared/__tests__/version-utils.test.ts | 16 ++++++++ shared/version-utils.ts | 41 +++++++++++++++----- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/client/src/components/GameDownloadDialog.tsx b/client/src/components/GameDownloadDialog.tsx index a3d6bb782..e33e6f7a1 100644 --- a/client/src/components/GameDownloadDialog.tsx +++ b/client/src/components/GameDownloadDialog.tsx @@ -77,10 +77,10 @@ import { } from "@shared/schema"; import { getCategoryLabel, - categorizeDownload, groupDownloadsByCategory, type DownloadCategory, } from "@shared/download-categorizer"; +import { inferReleaseCategory } from "@shared/version-utils"; import type { ReleaseType } from "@shared/typesafe-types"; import { parseReleaseMetadata, @@ -544,11 +544,11 @@ export default function GameDownloadDialog({ game, open, onOpenChange }: GameDow title: download.title, gameId: game?.id, downloadType: isUsenetItem(download) ? "usenet" : "torrent", - releaseCategory: categorizeDownload( + releaseCategory: inferReleaseCategory( download.title, download.aiReleaseType, download.aiReleaseTypeConfidence - ).category, + ), }); results.push(await response.json()); } diff --git a/shared/__tests__/version-utils.test.ts b/shared/__tests__/version-utils.test.ts index 30fa636fa..afd05a01d 100644 --- a/shared/__tests__/version-utils.test.ts +++ b/shared/__tests__/version-utils.test.ts @@ -3,6 +3,7 @@ import { compareVersions, extractVersionFromReleaseName, carriesBaseGameVersion, + inferReleaseCategory, isReleasePossiblyNewer, parseVersion, } from "../version-utils"; @@ -24,6 +25,8 @@ describe("extractVersionFromReleaseName", () => { ["Game.Update.v1.0.to.v1.1-RUNE", "v1.1"], // an update's target, not its start ["Game.Update.Build.1000.to.Build.1200-RUNE", "Build 1200"], // same for build ranges ["Game.Patch.Build.1000.to.Build.1200-RUNE", "Build 1200"], // without the word Update too + ["Game.Patch.v1.2-RUNE", "v1.2"], // "Patch" names its target like "Update" + ["Game.Patch.1.2-RUNE", "v1.2"], ["Game.v1.2.Repack-PREDATOR", "v1.2"], // a group name is not a pre-release tag ])("finds the version in %s", (name, expected) => { expect(extractVersionFromReleaseName(name)).toBe(expected); @@ -82,6 +85,19 @@ describe("compareVersions", () => { }); }); +describe("inferReleaseCategory", () => { + it("files full-game editions as the main game", () => { + expect(inferReleaseCategory("The.Witcher.3.Complete.Edition.v4.04-GOG")).toBe("main"); + expect(inferReleaseCategory("Game.GOTY.v2.0.incl.DLC-GOG")).toBe("main"); + }); + + it("keeps real DLC and a confident AI classification", () => { + expect(inferReleaseCategory("Game.Season.Pass.DLC-RUNE")).toBe("dlc"); + expect(inferReleaseCategory("Expansion.Name.v5.0", "dlc", 0.95)).toBe("dlc"); + expect(inferReleaseCategory("Game.Complete.Edition-GOG", "dlc", 0.95)).toBe("dlc"); + }); +}); + describe("carriesBaseGameVersion", () => { it("follows the stored category when there is one", () => { expect(carriesBaseGameVersion("Expansion.Name.v5.0", "dlc")).toBe(false); diff --git a/shared/version-utils.ts b/shared/version-utils.ts index bac6cd0b7..758981f59 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -1,4 +1,5 @@ -import { categorizeDownload } from "./download-categorizer.js"; +import { categorizeDownload, type DownloadCategory } from "./download-categorizer.js"; +import type { ReleaseType } from "./typesafe-types.js"; /** * Game version helpers: detect a version in a release name, and compare two versions. @@ -31,15 +32,15 @@ const BUILD_VERSION = new RegExp( String.raw`${NOT_PRECEDED_BY_ALNUM}build[\s._-]?(\d+)${NOT_FOLLOWED_BY_ALNUM}`, "i" ); -// "Update.v2", "Update.1.05", "Update 2.1.3" -- a version right after "Update". Without a "v" it +// "Update.v2", "Update.1.05", "Patch 2.1.3" -- a version right after "Update" or "Patch". Without a "v" it // needs a dot, so "Update 2" (the second update pack) isn't read as version 2. const UPDATE_VERSION = new RegExp( - String.raw`${NOT_PRECEDED_BY_ALNUM}update[\s._-](?:v\s?(\d+(?:\.\d+)*)|(\d+(?:\.\d+)+))${NOT_FOLLOWED_BY_ALNUM}`, + String.raw`${NOT_PRECEDED_BY_ALNUM}(?:update|patch)[\s._-](?:v\s?(\d+(?:\.\d+)*)|(\d+(?:\.\d+)+))${NOT_FOLLOWED_BY_ALNUM}`, "i" ); // "Update.Build.5000" -- an update whose target is a build number. const UPDATE_BUILD_VERSION = new RegExp( - String.raw`${NOT_PRECEDED_BY_ALNUM}update[\s._-]build[\s._-]?(\d+)${NOT_FOLLOWED_BY_ALNUM}`, + String.raw`${NOT_PRECEDED_BY_ALNUM}(?:update|patch)[\s._-]build[\s._-]?(\d+)${NOT_FOLLOWED_BY_ALNUM}`, "i" ); @@ -163,17 +164,39 @@ export function isReleasePossiblyNewer( const DLC_ONLY = /\b(?:dlc|downloadable content|expansion|season pass)\b/i; const BUNDLED_DLC = /(?:\bincl(?:uding)?|\bwith|\+)[\s._-]*(?:all[\s._-]*)?dlcs?\b/gi; +/** + * The category to store with a download grabbed from search results: the categorizer's (title, + * or AI classification when more confident), except that a title filed under DLC only for its + * edition words ("Complete.Edition", "GOTY.incl.DLC") is the full game. + */ +export function inferReleaseCategory( + downloadTitle: string, + aiReleaseType?: ReleaseType | null, + aiReleaseTypeConfidence?: number | null +): DownloadCategory { + const byTitle = categorizeDownload(downloadTitle); + const result = categorizeDownload(downloadTitle, aiReleaseType, aiReleaseTypeConfidence); + const titleDecided = + result.category === byTitle.category && result.confidence === byTitle.confidence; + if ( + titleDecided && + result.category === "dlc" && + !DLC_ONLY.test(downloadTitle.replace(BUNDLED_DLC, "")) + ) { + return "main"; + } + return result.category; +} + /** * Whether a download's version is the base game's: true for the full game (editions included) * and updates, false for DLC, packs and extras. `category` is the one stored with the download - * (picked by the user, or classified when it was grabbed); without it, the title decides. + * (picked by the user, or inferred when it was grabbed); without it, the title decides. */ export function carriesBaseGameVersion( downloadTitle: string, category: string | null | undefined ): boolean { - if (category) return category === "main" || category === "update"; - const byTitle = categorizeDownload(downloadTitle).category; - if (byTitle === "main" || byTitle === "update") return true; - return byTitle === "dlc" && !DLC_ONLY.test(downloadTitle.replace(BUNDLED_DLC, "")); + const effective = category || inferReleaseCategory(downloadTitle); + return effective === "main" || effective === "update"; } From 5f2b8c331735192aa977ec6cd548bfe9c3490359 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 16:48:32 +0000 Subject: [PATCH 16/28] Ignore an Enter that confirms an IME composition in the version field Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- client/__tests__/InstalledVersionField.test.tsx | 7 +++++++ client/src/components/InstalledVersionField.tsx | 2 ++ 2 files changed, 9 insertions(+) diff --git a/client/__tests__/InstalledVersionField.test.tsx b/client/__tests__/InstalledVersionField.test.tsx index 5483b8566..242ead556 100644 --- a/client/__tests__/InstalledVersionField.test.tsx +++ b/client/__tests__/InstalledVersionField.test.tsx @@ -75,6 +75,13 @@ describe("InstalledVersionField", () => { ); }); + it("does not save on an Enter that confirms an IME composition", () => { + const input = renderField(null); + fireEvent.change(input, { target: { value: "v2" } }); + fireEvent.keyDown(input, { key: "Enter", isComposing: true }); + expect(apiRequest).not.toHaveBeenCalled(); + }); + it("clears the version when emptied and blurred", async () => { const input = renderField("v1.0"); fireEvent.change(input, { target: { value: "" } }); diff --git a/client/src/components/InstalledVersionField.tsx b/client/src/components/InstalledVersionField.tsx index eb960fac1..a6dbf1fdb 100644 --- a/client/src/components/InstalledVersionField.tsx +++ b/client/src/components/InstalledVersionField.tsx @@ -113,6 +113,8 @@ export default function InstalledVersionField({ onBlur={() => save(draft)} onKeyDown={(e) => { if (e.key === "Enter") { + // Enter confirming an IME candidate is not a submit. + if (e.nativeEvent.isComposing) return; e.preventDefault(); save(draft); } else if (e.key === "Escape" && draft !== (installedVersion ?? "")) { From c8a5fa5a2441e2adcf316043481c401350fdaa24 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 16:59:37 +0000 Subject: [PATCH 17/28] Keep an edited version draft across refreshes, skip versions after a qualifier Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- .../__tests__/InstalledVersionField.test.tsx | 21 +++++++++++++++++++ .../src/components/InstalledVersionField.tsx | 11 ++++++++-- shared/__tests__/version-utils.test.ts | 4 ++++ shared/version-utils.ts | 8 +++++-- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/client/__tests__/InstalledVersionField.test.tsx b/client/__tests__/InstalledVersionField.test.tsx index 242ead556..9f65d29b7 100644 --- a/client/__tests__/InstalledVersionField.test.tsx +++ b/client/__tests__/InstalledVersionField.test.tsx @@ -93,6 +93,27 @@ describe("InstalledVersionField", () => { ); }); + it("follows a new server value but keeps a draft being edited", () => { + const client = createTestQueryClient(); + const view = (installedVersion: string | null, id = gameId) => ( + + + + ); + const { rerender } = render(view("v1.0")); + const input = screen.getByLabelText("Installed version"); + + rerender(view("v1.1")); + expect(input).toHaveValue("v1.1"); + + fireEvent.change(input, { target: { value: "v2" } }); + rerender(view("v1.2")); + expect(input).toHaveValue("v2"); + + rerender(view("v3.0", "game-2")); + expect(input).toHaveValue("v3.0"); + }); + it("does not save when the value did not change", () => { const input = renderField("v1.0"); fireEvent.blur(input); diff --git a/client/src/components/InstalledVersionField.tsx b/client/src/components/InstalledVersionField.tsx index a6dbf1fdb..8e8d3801a 100644 --- a/client/src/components/InstalledVersionField.tsx +++ b/client/src/components/InstalledVersionField.tsx @@ -48,9 +48,16 @@ export default function InstalledVersionField({ // race and the latest value always lands last. const queued = useRef<{ value: string | null } | null>(null); - // Follow the server value (another tab, a finished download detecting a newer version). + // The server value the draft last followed, and for which game. + const synced = useRef({ gameId, value: installedVersion ?? "" }); + + // Follow the server value (another tab, a finished download detecting a newer version), + // unless the user has edited the draft since: a refetch must not wipe what they are typing. useEffect(() => { - setDraft(installedVersion ?? ""); + const next = installedVersion ?? ""; + const previous = synced.current; + synced.current = { gameId, value: next }; + setDraft((draft) => (previous.gameId !== gameId || draft === previous.value ? next : draft)); }, [gameId, installedVersion]); const mutation = useMutation({ diff --git a/shared/__tests__/version-utils.test.ts b/shared/__tests__/version-utils.test.ts index afd05a01d..e0e1ff7cb 100644 --- a/shared/__tests__/version-utils.test.ts +++ b/shared/__tests__/version-utils.test.ts @@ -28,6 +28,7 @@ describe("extractVersionFromReleaseName", () => { ["Game.Patch.v1.2-RUNE", "v1.2"], // "Patch" names its target like "Update" ["Game.Patch.1.2-RUNE", "v1.2"], ["Game.v1.2.Repack-PREDATOR", "v1.2"], // a group name is not a pre-release tag + ["Game.Crackfix.v1.2-RUNE", "v1.2"], // "fix" inside a word is no qualifier ])("finds the version in %s", (name, expected) => { expect(extractVersionFromReleaseName(name)).toBe(expected); }); @@ -43,6 +44,9 @@ describe("extractVersionFromReleaseName", () => { "Game.v1.2.Early.Access-P2P", // qualifiers that order differently from the bare number "Game.Update.v1.2.Hotfix-RUNE", "Game.v1.2.Fix-RUNE", + "Game.Hotfix.v1.2-RUNE", // the qualifier can come first too + "Game.Beta.v1.2-RUNE", + "Game.Early.Access.v1.2-RUNE", "Game.v1.2.Update-RUNE", // an update whose target isn't named "Game.v1.2.Update.2-CODEX", "Game.v1.2.Patch-RUNE", diff --git a/shared/version-utils.ts b/shared/version-utils.ts index 758981f59..f3bdf1379 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -47,8 +47,12 @@ const UPDATE_BUILD_VERSION = new RegExp( // "v1.2-beta", "1.2.RC1", "v2.0 Preview", "v1.2.Early.Access", "v1.2.Hotfix": a qualifier whose // ordering against the bare number ("v1.2") isn't captured by it -- a later stable release or a // hotfix of the same number differs. Names carrying one are treated as having no readable version. -const QUALIFIED_VERSION = - /\d[\s._-]?(?:alpha|beta|rc|pre|preview|dev|early[\s._-]?access|hot[\s._-]?fix|fix)(?![a-z])/i; +// The qualifier can also come first ("Game.Hotfix.v1.2", "Game.Early.Access.v1.2"). +const QUALIFIER = String.raw`(?:alpha|beta|rc|pre|preview|dev|early[\s._-]?access|hot[\s._-]?fix|fix)`; +const QUALIFIED_VERSION = new RegExp( + String.raw`\d[\s._-]?${QUALIFIER}(?![a-z])|(? Date: Mon, 5 Oct 2026 17:13:47 +0000 Subject: [PATCH 18/28] Suggest versions only from completed downloads, reject letter-suffixed versions Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- client/__tests__/GameDetailsModal.test.tsx | 27 ++++++++++++++++++++++ client/src/components/GameDetailsModal.tsx | 7 +++++- shared/__tests__/version-utils.test.ts | 3 +++ shared/version-utils.ts | 7 ++++-- 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/client/__tests__/GameDetailsModal.test.tsx b/client/__tests__/GameDetailsModal.test.tsx index 8dd6697e5..3f2442ed9 100644 --- a/client/__tests__/GameDetailsModal.test.tsx +++ b/client/__tests__/GameDetailsModal.test.tsx @@ -489,6 +489,33 @@ describe("GameDetailsModal", () => { expect(screen.getByText("Show less")).toBeInTheDocument(); }); + it("suggests installed versions only from downloads that completed", async () => { + const download = (id: string, downloadTitle: string, status: string) => ({ + id, + gameId: "1", + downloadTitle, + status, + category: "main", + }); + (global.fetch as ReturnType).mockImplementation( + makeFetchMock({ + "/api/games/1/downloads": [ + download("a", "Test.Game.v1.1-RUNE", "imported"), + download("b", "Test.Game.v1.2-RUNE", "completed"), + download("c", "Test.Game.v1.3-RUNE", "failed"), + download("d", "Test.Game.v1.4-RUNE", "downloading"), + ], + }) + ); + + renderComponent(); + + expect(await screen.findByTestId("button-version-suggestion-v1.2")).toBeInTheDocument(); + expect(screen.getByTestId("button-version-suggestion-v1.1")).toBeInTheDocument(); + expect(screen.queryByTestId("button-version-suggestion-v1.3")).not.toBeInTheDocument(); + expect(screen.queryByTestId("button-version-suggestion-v1.4")).not.toBeInTheDocument(); + }); + it("renders the Your rating section", () => { renderComponent(); // Links tab is forceMount-ed; always in DOM diff --git a/client/src/components/GameDetailsModal.tsx b/client/src/components/GameDetailsModal.tsx index 7816a521f..39c44795a 100644 --- a/client/src/components/GameDetailsModal.tsx +++ b/client/src/components/GameDetailsModal.tsx @@ -640,7 +640,12 @@ export default function GameDetailsModal({ game, open, onOpenChange }: GameDetai const downloadReleaseNames = useMemo( () => gameDownloads - .filter((download) => carriesBaseGameVersion(download.downloadTitle, download.category)) + // Only downloads that really landed: a failed or pending one was never installed. + .filter( + (download) => + (download.status === "completed" || download.status === "imported") && + carriesBaseGameVersion(download.downloadTitle, download.category) + ) .map((download) => download.downloadTitle), [gameDownloads] ); diff --git a/shared/__tests__/version-utils.test.ts b/shared/__tests__/version-utils.test.ts index e0e1ff7cb..cbaf99618 100644 --- a/shared/__tests__/version-utils.test.ts +++ b/shared/__tests__/version-utils.test.ts @@ -45,6 +45,8 @@ describe("extractVersionFromReleaseName", () => { "Game.Update.v1.2.Hotfix-RUNE", "Game.v1.2.Fix-RUNE", "Game.Hotfix.v1.2-RUNE", // the qualifier can come first too + "Game.Update.v1.2b-RUNE", // a letter-suffixed version is not cut short to v1 + "Game.v1.2b-RUNE", "Game.Beta.v1.2-RUNE", "Game.Early.Access.v1.2-RUNE", "Game.v1.2.Update-RUNE", // an update whose target isn't named @@ -120,6 +122,7 @@ describe("isReleasePossiblyNewer", () => { it("is true when nothing is known", () => { expect(isReleasePossiblyNewer("Game.Update.v1.1-RUNE", null)).toBe(true); expect(isReleasePossiblyNewer("Game.Update-RUNE", "v1.2")).toBe(true); + expect(isReleasePossiblyNewer("Game.Update.v1.2b-RUNE", "v1")).toBe(true); expect(isReleasePossiblyNewer("Game.Update.v1.1-RUNE", "latest")).toBe(true); }); diff --git a/shared/version-utils.ts b/shared/version-utils.ts index f3bdf1379..5563c348d 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -20,10 +20,13 @@ export interface ParsedVersion { // `.`, `-`, `(`, `[` and spaces are all used as separators in release names. const NOT_PRECEDED_BY_ALNUM = "(?": otherwise "v1.2b" would +// backtrack to "v1" (the "." after it satisfies the boundary). Such a version reads as none. +const VERSION_END = String.raw`(?![a-z0-9]|\.\d)`; // "v1.2.3", "v123456", "v1.0.2.34567", "v 1.05" const V_VERSION = new RegExp( - String.raw`${NOT_PRECEDED_BY_ALNUM}v\s?(\d+(?:\.\d+)*)${NOT_FOLLOWED_BY_ALNUM}`, + String.raw`${NOT_PRECEDED_BY_ALNUM}v\s?(\d+(?:\.\d+)*)${VERSION_END}`, "i" ); const V_VERSION_ALL = new RegExp(V_VERSION.source, "gi"); @@ -35,7 +38,7 @@ const BUILD_VERSION = new RegExp( // "Update.v2", "Update.1.05", "Patch 2.1.3" -- a version right after "Update" or "Patch". Without a "v" it // needs a dot, so "Update 2" (the second update pack) isn't read as version 2. const UPDATE_VERSION = new RegExp( - String.raw`${NOT_PRECEDED_BY_ALNUM}(?:update|patch)[\s._-](?:v\s?(\d+(?:\.\d+)*)|(\d+(?:\.\d+)+))${NOT_FOLLOWED_BY_ALNUM}`, + String.raw`${NOT_PRECEDED_BY_ALNUM}(?:update|patch)[\s._-](?:v\s?(\d+(?:\.\d+)*)|(\d+(?:\.\d+)+))${VERSION_END}`, "i" ); // "Update.Build.5000" -- an update whose target is a build number. From 497d4affd33a1fcff977232fceb257501ae94513 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 17:23:32 +0000 Subject: [PATCH 19/28] Read unprefixed update ranges, split DLC names on underscores Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- shared/__tests__/version-utils.test.ts | 2 ++ shared/version-utils.ts | 31 +++++++++++++++++++------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/shared/__tests__/version-utils.test.ts b/shared/__tests__/version-utils.test.ts index cbaf99618..164ce5aed 100644 --- a/shared/__tests__/version-utils.test.ts +++ b/shared/__tests__/version-utils.test.ts @@ -23,6 +23,7 @@ describe("extractVersionFromReleaseName", () => { ["Game.v1.0.to.v1.1.Patch-RUNE", "v1.1"], // highest of several ["Game.v1.4.Update.Build.5000-RUNE", "Build 5000"], // the update's build target wins ["Game.Update.v1.0.to.v1.1-RUNE", "v1.1"], // an update's target, not its start + ["Game.Update.1.0.to.1.1-RUNE", "v1.1"], // the same without "v" ["Game.Update.Build.1000.to.Build.1200-RUNE", "Build 1200"], // same for build ranges ["Game.Patch.Build.1000.to.Build.1200-RUNE", "Build 1200"], // without the word Update too ["Game.Patch.v1.2-RUNE", "v1.2"], // "Patch" names its target like "Update" @@ -99,6 +100,7 @@ describe("inferReleaseCategory", () => { it("keeps real DLC and a confident AI classification", () => { expect(inferReleaseCategory("Game.Season.Pass.DLC-RUNE")).toBe("dlc"); + expect(inferReleaseCategory("Game_DLC_v5.0")).toBe("dlc"); // "_" separates words too expect(inferReleaseCategory("Expansion.Name.v5.0", "dlc", 0.95)).toBe("dlc"); expect(inferReleaseCategory("Game.Complete.Edition-GOG", "dlc", 0.95)).toBe("dlc"); }); diff --git a/shared/version-utils.ts b/shared/version-utils.ts index 5563c348d..a63449dab 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -57,6 +57,11 @@ const QUALIFIED_VERSION = new RegExp( "i" ); const BUILD_VERSION_ALL = new RegExp(BUILD_VERSION.source, "gi"); +// "1.1" with no "v", as in the target of "Update.1.0.to.1.1". +const DOTTED_VERSION_ALL = new RegExp( + String.raw`${NOT_PRECEDED_BY_ALNUM}(\d+(?:\.\d+)+)${VERSION_END}`, + "gi" +); const UPDATE_MARKER = new RegExp( String.raw`${NOT_PRECEDED_BY_ALNUM}(?:update|patch)${NOT_FOLLOWED_BY_ALNUM}`, "i" @@ -74,7 +79,10 @@ export function extractVersionFromReleaseName(releaseName: string): string | nul const update = UPDATE_VERSION.exec(releaseName); const updateVersion = update?.[1] ?? update?.[2]; if (update && updateVersion) { - return highestVVersion(releaseName.slice(update.index), `v${updateVersion}`); + const rest = releaseName.slice(update.index); + const best = highestVVersion(rest, `v${updateVersion}`); + // Without a "v" ("Update.1.0.to.1.1"), the range's other end is unprefixed too. + return update[1] ? best : highestDottedVersion(rest, best); } // Likewise for builds: "Update.Build.1000.to.Build.1200" brings the game to Build 1200. const updateBuild = UPDATE_BUILD_VERSION.exec(releaseName); @@ -104,6 +112,15 @@ function highestVVersion(text: string, initial: string | null): string | null { return best; } +function highestDottedVersion(text: string, initial: string | null): string | null { + let best = initial; + for (const match of text.matchAll(DOTTED_VERSION_ALL)) { + const candidate = `v${match[1]}`; + if (best === null || (compareVersions(candidate, best) ?? 0) > 0) best = candidate; + } + return best; +} + function highestBuild(text: string): string | null { let best: number | null = null; for (const match of text.matchAll(BUILD_VERSION_ALL)) { @@ -181,15 +198,13 @@ export function inferReleaseCategory( aiReleaseType?: ReleaseType | null, aiReleaseTypeConfidence?: number | null ): DownloadCategory { - const byTitle = categorizeDownload(downloadTitle); - const result = categorizeDownload(downloadTitle, aiReleaseType, aiReleaseTypeConfidence); + // The categorizer's word boundaries don't split on "_" ("Game_DLC_v5.0"). + const title = downloadTitle.replace(/_/g, " "); + const byTitle = categorizeDownload(title); + const result = categorizeDownload(title, aiReleaseType, aiReleaseTypeConfidence); const titleDecided = result.category === byTitle.category && result.confidence === byTitle.confidence; - if ( - titleDecided && - result.category === "dlc" && - !DLC_ONLY.test(downloadTitle.replace(BUNDLED_DLC, "")) - ) { + if (titleDecided && result.category === "dlc" && !DLC_ONLY.test(title.replace(BUNDLED_DLC, ""))) { return "main"; } return result.category; From e31371b10264dc8eeea8362c100138af360e1637 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 17:30:17 +0000 Subject: [PATCH 20/28] Keep the version save pending until the games refetch lands Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- .../__tests__/InstalledVersionField.test.tsx | 25 +++++++++++++++++++ .../src/components/InstalledVersionField.tsx | 6 ++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/client/__tests__/InstalledVersionField.test.tsx b/client/__tests__/InstalledVersionField.test.tsx index 9f65d29b7..f94ed4a9d 100644 --- a/client/__tests__/InstalledVersionField.test.tsx +++ b/client/__tests__/InstalledVersionField.test.tsx @@ -172,6 +172,31 @@ describe("InstalledVersionField", () => { }); }); + it("still saves the stored value typed back while the refetch is pending", async () => { + const client = createTestQueryClient(); + let finishRefetch: () => void = () => {}; + vi.spyOn(client, "invalidateQueries").mockReturnValueOnce( + new Promise((resolve) => (finishRefetch = resolve)) + ); + render( + + + + ); + const input = screen.getByLabelText("Installed version"); + fireEvent.change(input, { target: { value: "v2" } }); + fireEvent.keyDown(input, { key: "Enter" }); + await waitFor(() => expect(client.invalidateQueries).toHaveBeenCalled()); + fireEvent.change(input, { target: { value: "v1" } }); + fireEvent.blur(input); + + finishRefetch(); + await waitFor(() => expect(apiRequest).toHaveBeenCalledTimes(2)); + expect(apiRequest).toHaveBeenLastCalledWith("PATCH", `/api/games/${gameId}/installed-version`, { + installedVersion: "v1", + }); + }); + it("restores the stored value and warns when saving fails", async () => { apiRequest.mockRejectedValue(new Error("boom")); const input = renderField("v1.0"); diff --git a/client/src/components/InstalledVersionField.tsx b/client/src/components/InstalledVersionField.tsx index 8e8d3801a..b7296e669 100644 --- a/client/src/components/InstalledVersionField.tsx +++ b/client/src/components/InstalledVersionField.tsx @@ -66,9 +66,9 @@ export default function InstalledVersionField({ installedVersion: value, }); }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ["/api/games"] }); - }, + // Stays pending until the games refetch lands: until then `installedVersion` is stale, and + // typing the old value back must still count as a change. + onSuccess: () => queryClient.invalidateQueries({ queryKey: ["/api/games"] }), onError: () => { if (queued.current) return; // a newer value is about to be sent setDraft(installedVersion ?? ""); From 5ae8ed713e2a52c3c1c5fd3bfeb4c128d1838f11 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 17:41:21 +0000 Subject: [PATCH 21/28] Broadcast manual version edits, read mixed-prefix update ranges Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- server/__tests__/api_routes.test.ts | 2 ++ server/routes.ts | 8 ++++++-- shared/__tests__/version-utils.test.ts | 2 ++ shared/version-utils.ts | 7 ++++--- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/server/__tests__/api_routes.test.ts b/server/__tests__/api_routes.test.ts index 2686f4a83..f7b75f461 100644 --- a/server/__tests__/api_routes.test.ts +++ b/server/__tests__/api_routes.test.ts @@ -990,6 +990,8 @@ describe("API Routes - Extended Coverage", () => { "user-1", "v1.2.3" ); + const { notifyUser } = await import("../socket.js"); + expect(vi.mocked(notifyUser)).toHaveBeenCalledWith("gameUpdated", gameId); }); it("should clear the version with a blank value", async () => { diff --git a/server/routes.ts b/server/routes.ts index 8211427ca..320c951b3 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -1889,8 +1889,12 @@ export async function registerRoutes(app: Express): Promise { validateRequest, patchOwnGameField( updateGameInstalledVersionSchema, - (id, userId, { installedVersion }) => - storage.updateGameInstalledVersion(id, userId, installedVersion), + async (id, userId, { installedVersion }) => { + const game = await storage.updateGameInstalledVersion(id, userId, installedVersion); + // Lets the user's other tabs refresh their games query, which is otherwise never stale. + if (game) (await import("./socket.js")).notifyUser("gameUpdated", game.id); + return game; + }, { invalid: "Invalid installed version data", log: "error updating game installed version", diff --git a/shared/__tests__/version-utils.test.ts b/shared/__tests__/version-utils.test.ts index 164ce5aed..3cefb948e 100644 --- a/shared/__tests__/version-utils.test.ts +++ b/shared/__tests__/version-utils.test.ts @@ -24,6 +24,8 @@ describe("extractVersionFromReleaseName", () => { ["Game.v1.4.Update.Build.5000-RUNE", "Build 5000"], // the update's build target wins ["Game.Update.v1.0.to.v1.1-RUNE", "v1.1"], // an update's target, not its start ["Game.Update.1.0.to.1.1-RUNE", "v1.1"], // the same without "v" + ["Game.Update.v1.0.to.1.1-RUNE", "v1.1"], // or with only one end prefixed + ["Game.Update.v1.10.20-RUNE", "v1.10.20"], // not the tail "10.20" ["Game.Update.Build.1000.to.Build.1200-RUNE", "Build 1200"], // same for build ranges ["Game.Patch.Build.1000.to.Build.1200-RUNE", "Build 1200"], // without the word Update too ["Game.Patch.v1.2-RUNE", "v1.2"], // "Patch" names its target like "Update" diff --git a/shared/version-utils.ts b/shared/version-utils.ts index a63449dab..3f40c9df6 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -59,7 +59,8 @@ const QUALIFIED_VERSION = new RegExp( const BUILD_VERSION_ALL = new RegExp(BUILD_VERSION.source, "gi"); // "1.1" with no "v", as in the target of "Update.1.0.to.1.1". const DOTTED_VERSION_ALL = new RegExp( - String.raw`${NOT_PRECEDED_BY_ALNUM}(\d+(?:\.\d+)+)${VERSION_END}`, + // Not right after ".", so the tail of "v1.10.20" isn't read as "10.20". + String.raw`(? Date: Mon, 5 Oct 2026 17:53:37 +0000 Subject: [PATCH 22/28] Read unprefixed targets in ranges before a trailing patch marker Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- shared/__tests__/version-utils.test.ts | 1 + shared/version-utils.ts | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/shared/__tests__/version-utils.test.ts b/shared/__tests__/version-utils.test.ts index 3cefb948e..abeb2edf4 100644 --- a/shared/__tests__/version-utils.test.ts +++ b/shared/__tests__/version-utils.test.ts @@ -21,6 +21,7 @@ describe("extractVersionFromReleaseName", () => { ["Game.v1.0.Update.v1.1-RUNE", "v1.1"], // the update's target wins ["Game.v1.0.Update.v2-RUNE", "v2"], ["Game.v1.0.to.v1.1.Patch-RUNE", "v1.1"], // highest of several + ["Game.v1.0.to.1.1.Patch-RUNE", "v1.1"], // the target without "v" ["Game.v1.4.Update.Build.5000-RUNE", "Build 5000"], // the update's build target wins ["Game.Update.v1.0.to.v1.1-RUNE", "v1.1"], // an update's target, not its start ["Game.Update.1.0.to.1.1-RUNE", "v1.1"], // the same without "v" diff --git a/shared/version-utils.ts b/shared/version-utils.ts index 3f40c9df6..72a77ecbf 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -92,7 +92,9 @@ export function extractVersionFromReleaseName(releaseName: string): string | nul // ("Game.v1.2.Update"), which says nothing about where it leads; only a range does // ("Game.v1.0.to.v1.1.Patch", "Patch.Build.1000.to.Build.1200"). if (UPDATE_MARKER.test(releaseName)) { - if (countMatches(releaseName, V_VERSION_ALL) > 1) return highestVVersion(releaseName, null); + const versions = + countMatches(releaseName, V_VERSION_ALL) + countMatches(releaseName, DOTTED_VERSION_ALL); + if (versions > 1) return highestDottedVersion(releaseName, highestVVersion(releaseName, null)); if (countMatches(releaseName, BUILD_VERSION_ALL) > 1) return highestBuild(releaseName); return null; } From 421b894feff6ddc322276ba0cf236213bf62110f Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 17:57:04 +0000 Subject: [PATCH 23/28] Take an unprefixed number as an update target only after "to" Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- shared/__tests__/version-utils.test.ts | 1 + shared/version-utils.ts | 23 ++++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/shared/__tests__/version-utils.test.ts b/shared/__tests__/version-utils.test.ts index abeb2edf4..19c8399b2 100644 --- a/shared/__tests__/version-utils.test.ts +++ b/shared/__tests__/version-utils.test.ts @@ -27,6 +27,7 @@ describe("extractVersionFromReleaseName", () => { ["Game.Update.1.0.to.1.1-RUNE", "v1.1"], // the same without "v" ["Game.Update.v1.0.to.1.1-RUNE", "v1.1"], // or with only one end prefixed ["Game.Update.v1.10.20-RUNE", "v1.10.20"], // not the tail "10.20" + ["Game.Update.v1.2.Win.11.0-RUNE", "v1.2"], // a number outside a range is not a target ["Game.Update.Build.1000.to.Build.1200-RUNE", "Build 1200"], // same for build ranges ["Game.Patch.Build.1000.to.Build.1200-RUNE", "Build 1200"], // without the word Update too ["Game.Patch.v1.2-RUNE", "v1.2"], // "Patch" names its target like "Update" diff --git a/shared/version-utils.ts b/shared/version-utils.ts index 72a77ecbf..a6b04984b 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -57,10 +57,10 @@ const QUALIFIED_VERSION = new RegExp( "i" ); const BUILD_VERSION_ALL = new RegExp(BUILD_VERSION.source, "gi"); -// "1.1" with no "v", as in the target of "Update.1.0.to.1.1". -const DOTTED_VERSION_ALL = new RegExp( - // Not right after ".", so the tail of "v1.10.20" isn't read as "10.20". - String.raw`(? 1) return highestDottedVersion(releaseName, highestVVersion(releaseName, null)); + if (countMatches(releaseName, RANGE_TARGET_ALL) > 0) { + return highestRangeTarget(releaseName, highestVVersion(releaseName, null)); + } + if (countMatches(releaseName, V_VERSION_ALL) > 1) return highestVVersion(releaseName, null); if (countMatches(releaseName, BUILD_VERSION_ALL) > 1) return highestBuild(releaseName); return null; } @@ -115,10 +116,10 @@ function highestVVersion(text: string, initial: string | null): string | null { return best; } -function highestDottedVersion(text: string, initial: string | null): string | null { +function highestRangeTarget(text: string, initial: string | null): string | null { let best = initial; - for (const match of text.matchAll(DOTTED_VERSION_ALL)) { - const candidate = `v${match[1]}`; + for (const match of text.matchAll(RANGE_TARGET_ALL)) { + const candidate = `v${match[1] ?? match[2]}`; if (best === null || (compareVersions(candidate, best) ?? 0) > 0) best = candidate; } return best; From 837cde20fec04c5c13bb0559107a0aa579442a81 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 18:05:45 +0000 Subject: [PATCH 24/28] Read bare build range targets, normalize all separators before categorizing Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- shared/__tests__/version-utils.test.ts | 4 ++++ shared/version-utils.ts | 28 +++++++++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/shared/__tests__/version-utils.test.ts b/shared/__tests__/version-utils.test.ts index 19c8399b2..17e296d50 100644 --- a/shared/__tests__/version-utils.test.ts +++ b/shared/__tests__/version-utils.test.ts @@ -30,6 +30,8 @@ describe("extractVersionFromReleaseName", () => { ["Game.Update.v1.2.Win.11.0-RUNE", "v1.2"], // a number outside a range is not a target ["Game.Update.Build.1000.to.Build.1200-RUNE", "Build 1200"], // same for build ranges ["Game.Patch.Build.1000.to.Build.1200-RUNE", "Build 1200"], // without the word Update too + ["Game.Update.Build.1000.to.1200-RUNE", "Build 1200"], // a bare build target + ["Game.Build.1000.to.1200.Patch-RUNE", "Build 1200"], ["Game.Patch.v1.2-RUNE", "v1.2"], // "Patch" names its target like "Update" ["Game.Patch.1.2-RUNE", "v1.2"], ["Game.v1.2.Repack-PREDATOR", "v1.2"], // a group name is not a pre-release tag @@ -105,6 +107,8 @@ describe("inferReleaseCategory", () => { it("keeps real DLC and a confident AI classification", () => { expect(inferReleaseCategory("Game.Season.Pass.DLC-RUNE")).toBe("dlc"); expect(inferReleaseCategory("Game_DLC_v5.0")).toBe("dlc"); // "_" separates words too + expect(inferReleaseCategory("Game.Season.Pass.v5.0")).toBe("dlc"); + expect(inferReleaseCategory("Game.Downloadable.Content.v5.0")).toBe("dlc"); expect(inferReleaseCategory("Expansion.Name.v5.0", "dlc", 0.95)).toBe("dlc"); expect(inferReleaseCategory("Game.Complete.Edition-GOG", "dlc", 0.95)).toBe("dlc"); }); diff --git a/shared/version-utils.ts b/shared/version-utils.ts index a6b04984b..880bd9e27 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -63,6 +63,11 @@ const RANGE_TARGET_ALL = new RegExp( String.raw`${NOT_PRECEDED_BY_ALNUM}to[\s._-](?:v\s?(\d+(?:\.\d+)*)|(\d+(?:\.\d+)+))${VERSION_END}`, "gi" ); +// "to.1200" or "to.Build.1200", the far end of a build range. +const BUILD_RANGE_TARGET_ALL = new RegExp( + String.raw`${NOT_PRECEDED_BY_ALNUM}to[\s._-](?:build[\s._-]?)?(\d+)${VERSION_END}`, + "gi" +); const UPDATE_MARKER = new RegExp( String.raw`${NOT_PRECEDED_BY_ALNUM}(?:update|patch)${NOT_FOLLOWED_BY_ALNUM}`, "i" @@ -96,7 +101,7 @@ export function extractVersionFromReleaseName(releaseName: string): string | nul return highestRangeTarget(releaseName, highestVVersion(releaseName, null)); } if (countMatches(releaseName, V_VERSION_ALL) > 1) return highestVVersion(releaseName, null); - if (countMatches(releaseName, BUILD_VERSION_ALL) > 1) return highestBuild(releaseName); + if (buildNumbers(releaseName).length > 1) return highestBuild(releaseName); return null; } // Otherwise the highest of the versions named, then of the builds. @@ -125,13 +130,17 @@ function highestRangeTarget(text: string, initial: string | null): string | null return best; } +// Builds named in `text`, plus, once a build is named, a bare target after "to" +// ("Build.1000.to.1200"). +function buildNumbers(text: string): number[] { + const builds = Array.from(text.matchAll(BUILD_VERSION_ALL), (match) => Number(match[1])); + if (builds.length === 0) return builds; + return builds.concat(Array.from(text.matchAll(BUILD_RANGE_TARGET_ALL), (m) => Number(m[1]))); +} + function highestBuild(text: string): string | null { - let best: number | null = null; - for (const match of text.matchAll(BUILD_VERSION_ALL)) { - const build = Number(match[1]); - if (best === null || build > best) best = build; - } - return best === null ? null : `Build ${best}`; + const builds = buildNumbers(text); + return builds.length === 0 ? null : `Build ${Math.max(...builds)}`; } /** @@ -202,8 +211,9 @@ export function inferReleaseCategory( aiReleaseType?: ReleaseType | null, aiReleaseTypeConfidence?: number | null ): DownloadCategory { - // The categorizer's word boundaries don't split on "_" ("Game_DLC_v5.0"). - const title = downloadTitle.replace(/_/g, " "); + // The categorizer matches words, some of them multiword ("season pass"), so release + // separators become spaces ("Game_DLC_v5.0", "Game.Season.Pass.v5.0"). + const title = downloadTitle.replace(/[._-]+/g, " "); const byTitle = categorizeDownload(title); const result = categorizeDownload(title, aiReleaseType, aiReleaseTypeConfidence); const titleDecided = From ab36a72ac9187c3754210de3ad431c328dd88b10 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 18:14:06 +0000 Subject: [PATCH 25/28] Keep hyphenated markers like Add-On when categorizing release names Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- shared/__tests__/version-utils.test.ts | 1 + shared/version-utils.ts | 14 ++++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/shared/__tests__/version-utils.test.ts b/shared/__tests__/version-utils.test.ts index 17e296d50..74a700b23 100644 --- a/shared/__tests__/version-utils.test.ts +++ b/shared/__tests__/version-utils.test.ts @@ -109,6 +109,7 @@ describe("inferReleaseCategory", () => { expect(inferReleaseCategory("Game_DLC_v5.0")).toBe("dlc"); // "_" separates words too expect(inferReleaseCategory("Game.Season.Pass.v5.0")).toBe("dlc"); expect(inferReleaseCategory("Game.Downloadable.Content.v5.0")).toBe("dlc"); + expect(inferReleaseCategory("Game.Add-On.v5.0")).toBe("packs"); expect(inferReleaseCategory("Expansion.Name.v5.0", "dlc", 0.95)).toBe("dlc"); expect(inferReleaseCategory("Game.Complete.Edition-GOG", "dlc", 0.95)).toBe("dlc"); }); diff --git a/shared/version-utils.ts b/shared/version-utils.ts index 880bd9e27..6bd7cb8b4 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -211,14 +211,20 @@ export function inferReleaseCategory( aiReleaseType?: ReleaseType | null, aiReleaseTypeConfidence?: number | null ): DownloadCategory { - // The categorizer matches words, some of them multiword ("season pass"), so release - // separators become spaces ("Game_DLC_v5.0", "Game.Season.Pass.v5.0"). - const title = downloadTitle.replace(/[._-]+/g, " "); + // The categorizer matches words, some multiword ("season pass"), which release separators + // hide ("Game_DLC_v5.0", "Game.Season.Pass.v5.0"); a spaced title is tried when the raw one + // reads as the full game, so markers spelled with a separator ("Add-On") still match. + const spaced = downloadTitle.replace(/[._-]+/g, " "); + const title = categorizeDownload(downloadTitle).category === "main" ? spaced : downloadTitle; const byTitle = categorizeDownload(title); const result = categorizeDownload(title, aiReleaseType, aiReleaseTypeConfidence); const titleDecided = result.category === byTitle.category && result.confidence === byTitle.confidence; - if (titleDecided && result.category === "dlc" && !DLC_ONLY.test(title.replace(BUNDLED_DLC, ""))) { + if ( + titleDecided && + result.category === "dlc" && + !DLC_ONLY.test(spaced.replace(BUNDLED_DLC, "")) + ) { return "main"; } return result.category; From e2822c9f4909171e2535d3f4c828ad0b09d7b463 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 18:21:43 +0000 Subject: [PATCH 26/28] Compare again after losing the version write to a concurrent import Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- server/__tests__/game-version.test.ts | 23 +++++++++++++++++++ server/game-version.ts | 33 +++++++++++++++------------ 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/server/__tests__/game-version.test.ts b/server/__tests__/game-version.test.ts index 69d64228a..9397d1e9a 100644 --- a/server/__tests__/game-version.test.ts +++ b/server/__tests__/game-version.test.ts @@ -70,6 +70,29 @@ describe("recordVersionFromCompletedDownload", () => { expect(notifyUser).not.toHaveBeenCalled(); }); + it("compares again after losing the write to a concurrent older import", async () => { + // A v1.2 import wrote between this v1.3 import's read and its write. + getGame + .mockResolvedValueOnce({ id: "g1", installedVersion: "v1.0" }) + .mockResolvedValueOnce({ id: "g1", installedVersion: "v1.2" }); + replaceGameInstalledVersion.mockResolvedValueOnce(false).mockResolvedValueOnce(true); + const recorded = await recordVersionFromCompletedDownload(store, "g1", "Game.Update.v1.3-RUNE"); + expect(recorded).toBe("v1.3"); + expect(replaceGameInstalledVersion).toHaveBeenLastCalledWith("g1", "v1.2", "v1.3"); + expect(notifyUser).toHaveBeenCalledWith("gameUpdated", "g1"); + }); + + it("stops when a concurrent import already wrote a newer version", async () => { + getGame + .mockResolvedValueOnce({ id: "g1", installedVersion: "v1.0" }) + .mockResolvedValueOnce({ id: "g1", installedVersion: "v1.4" }); + replaceGameInstalledVersion.mockResolvedValueOnce(false); + expect( + await recordVersionFromCompletedDownload(store, "g1", "Game.Update.v1.3-RUNE") + ).toBeNull(); + expect(replaceGameInstalledVersion).toHaveBeenCalledTimes(1); + }); + it("compares against the current row, not the caller's snapshot", async () => { // The user moved to v2.0 while the v1.5 import was running. expect(await record("v2.0", "Test.Game.v1.5-RUNE")).toBeNull(); diff --git a/server/game-version.ts b/server/game-version.ts index e26bdfca8..c340d6da6 100644 --- a/server/game-version.ts +++ b/server/game-version.ts @@ -31,22 +31,25 @@ export async function recordVersionFromCompletedDownload( if (!detected) return null; // Read the current row: an import can run for minutes, during which the user may have - // edited the version or another import may have advanced it. - const game = await store.getGame(gameId); - if (!game) return null; - if (game.installedVersion?.trim()) { - const cmp = compareVersions(detected, game.installedVersion); - if (cmp === null || cmp <= 0) return null; + // edited the version or another import may have advanced it. The write only lands if the + // version is still the one just compared against; if something else wrote first, compare + // again against what it wrote, so a concurrent older import can't hold back a newer one. + let game: Awaited>; + for (let attempt = 0; ; attempt++) { + game = await store.getGame(gameId); + if (!game) return null; + if (game.installedVersion?.trim()) { + const cmp = compareVersions(detected, game.installedVersion); + if (cmp === null || cmp <= 0) return null; + } + const written = await store.replaceGameInstalledVersion( + game.id, + game.installedVersion ?? null, + detected + ); + if (written) break; + if (attempt >= 2) return null; } - - // Written only if the version is still the one just compared against, so a value the user - // saved in between is never overwritten. - const written = await store.replaceGameInstalledVersion( - game.id, - game.installedVersion ?? null, - detected - ); - if (!written) return null; logger.info( { gameId: game.id, previous: game.installedVersion, installedVersion: detected }, "Recorded game version from completed download" From e6b5e20b16cb4863aab9c503948ab9b4e03d99ea Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 18:54:31 +0000 Subject: [PATCH 27/28] Merge the installed-version migrations into one per dialect Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- .../0008_cultured_stephen_strange.sql | 1 - migrations-pg/0008_spotty_celestials.sql | 2 + migrations-pg/0009_spicy_black_bolt.sql | 1 - migrations-pg/meta/0008_snapshot.json | 8 +- migrations-pg/meta/0009_snapshot.json | 2313 ---------------- migrations-pg/meta/_journal.json | 11 +- migrations/0043_groovy_slyde.sql | 2 + migrations/0043_massive_dormammu.sql | 1 - migrations/0044_faulty_blazing_skull.sql | 1 - migrations/meta/0043_snapshot.json | 9 +- migrations/meta/0044_snapshot.json | 2344 ----------------- migrations/meta/_journal.json | 11 +- 12 files changed, 23 insertions(+), 4681 deletions(-) delete mode 100644 migrations-pg/0008_cultured_stephen_strange.sql create mode 100644 migrations-pg/0008_spotty_celestials.sql delete mode 100644 migrations-pg/0009_spicy_black_bolt.sql delete mode 100644 migrations-pg/meta/0009_snapshot.json create mode 100644 migrations/0043_groovy_slyde.sql delete mode 100644 migrations/0043_massive_dormammu.sql delete mode 100644 migrations/0044_faulty_blazing_skull.sql delete mode 100644 migrations/meta/0044_snapshot.json diff --git a/migrations-pg/0008_cultured_stephen_strange.sql b/migrations-pg/0008_cultured_stephen_strange.sql deleted file mode 100644 index e06c8b4ff..000000000 --- a/migrations-pg/0008_cultured_stephen_strange.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE "games" ADD COLUMN "installed_version" text; \ No newline at end of file diff --git a/migrations-pg/0008_spotty_celestials.sql b/migrations-pg/0008_spotty_celestials.sql new file mode 100644 index 000000000..b639a63a5 --- /dev/null +++ b/migrations-pg/0008_spotty_celestials.sql @@ -0,0 +1,2 @@ +ALTER TABLE "game_downloads" ADD COLUMN "category" text;--> statement-breakpoint +ALTER TABLE "games" ADD COLUMN "installed_version" text; \ No newline at end of file diff --git a/migrations-pg/0009_spicy_black_bolt.sql b/migrations-pg/0009_spicy_black_bolt.sql deleted file mode 100644 index 39ebdc259..000000000 --- a/migrations-pg/0009_spicy_black_bolt.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE "game_downloads" ADD COLUMN "category" text; \ No newline at end of file diff --git a/migrations-pg/meta/0008_snapshot.json b/migrations-pg/meta/0008_snapshot.json index 4f6ce1dbf..4e8c305a3 100644 --- a/migrations-pg/meta/0008_snapshot.json +++ b/migrations-pg/meta/0008_snapshot.json @@ -1,5 +1,5 @@ { - "id": "ea184a7e-1f5f-46c6-b1f3-33072994a55b", + "id": "961d0664-04d8-4424-82a2-e6864113f154", "prevId": "569ebd28-47ce-4be9-9daf-24d98a63ba0e", "version": "7", "dialect": "postgresql", @@ -393,6 +393,12 @@ "primaryKey": false, "notNull": false }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false + }, "added_at": { "name": "added_at", "type": "bigint", diff --git a/migrations-pg/meta/0009_snapshot.json b/migrations-pg/meta/0009_snapshot.json deleted file mode 100644 index 1b5a0a0ec..000000000 --- a/migrations-pg/meta/0009_snapshot.json +++ /dev/null @@ -1,2313 +0,0 @@ -{ - "id": "a0938e4a-d81e-4240-afa2-5ef321e792cd", - "prevId": "ea184a7e-1f5f-46c6-b1f3-33072994a55b", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.ai_auto_download_holds": { - "name": "ai_auto_download_holds", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "release_title": { - "name": "release_title", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "reason": { - "name": "reason", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": { - "ai_auto_download_holds_game_title_idx": { - "name": "ai_auto_download_holds_game_title_idx", - "columns": [ - { - "expression": "game_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "release_title", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "ai_auto_download_holds_game_id_games_id_fk": { - "name": "ai_auto_download_holds_game_id_games_id_fk", - "tableFrom": "ai_auto_download_holds", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.api_keys": { - "name": "api_keys", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "key_hash": { - "name": "key_hash", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "prefix": { - "name": "prefix", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - }, - "last_used_at": { - "name": "last_used_at", - "type": "bigint", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "api_keys_key_hash_idx": { - "name": "api_keys_key_hash_idx", - "columns": [ - { - "expression": "key_hash", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - }, - "api_keys_user_id_idx": { - "name": "api_keys_user_id_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "api_keys_user_id_users_id_fk": { - "name": "api_keys_user_id_users_id_fk", - "tableFrom": "api_keys", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.downloaders": { - "name": "downloaders", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "url": { - "name": "url", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "port": { - "name": "port", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "use_ssl": { - "name": "use_ssl", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "url_path": { - "name": "url_path", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "allow_self_signed_certificate": { - "name": "allow_self_signed_certificate", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "allow_insecure_lan": { - "name": "allow_insecure_lan", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "username": { - "name": "username", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "enabled": { - "name": "enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "priority": { - "name": "priority", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "download_path": { - "name": "download_path", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "category": { - "name": "category", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'games'" - }, - "label": { - "name": "label", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'Questarr'" - }, - "add_stopped": { - "name": "add_stopped", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "remove_completed": { - "name": "remove_completed", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "post_import_category": { - "name": "post_import_category", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "settings": { - "name": "settings", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - }, - "updated_at": { - "name": "updated_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.game_downloads": { - "name": "game_downloads", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "downloader_id": { - "name": "downloader_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "download_type": { - "name": "download_type", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'torrent'" - }, - "download_hash": { - "name": "download_hash", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "download_title": { - "name": "download_title", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'downloading'" - }, - "error_message": { - "name": "error_message", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "file_size": { - "name": "file_size", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "category": { - "name": "category", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "added_at": { - "name": "added_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - }, - "completed_at": { - "name": "completed_at", - "type": "bigint", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "game_downloads_downloader_hash_idx": { - "name": "game_downloads_downloader_hash_idx", - "columns": [ - { - "expression": "downloader_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "download_hash", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "game_downloads_game_id_games_id_fk": { - "name": "game_downloads_game_id_games_id_fk", - "tableFrom": "game_downloads", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "game_downloads_downloader_id_downloaders_id_fk": { - "name": "game_downloads_downloader_id_downloaders_id_fk", - "tableFrom": "game_downloads", - "tableTo": "downloaders", - "columnsFrom": ["downloader_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.game_files": { - "name": "game_files", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "download_id": { - "name": "download_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "original_name": { - "name": "original_name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "stored_name": { - "name": "stored_name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "category": { - "name": "category", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "category_overridden": { - "name": "category_overridden", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "file_path": { - "name": "file_path", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "file_size": { - "name": "file_size", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": { - "game_files_game_id_idx": { - "name": "game_files_game_id_idx", - "columns": [ - { - "expression": "game_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "game_files_download_id_idx": { - "name": "game_files_download_id_idx", - "columns": [ - { - "expression": "download_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "game_files_game_id_games_id_fk": { - "name": "game_files_game_id_games_id_fk", - "tableFrom": "game_files", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "game_files_download_id_game_downloads_id_fk": { - "name": "game_files_download_id_game_downloads_id_fk", - "tableFrom": "game_files", - "tableTo": "game_downloads", - "columnsFrom": ["download_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.game_journal_entries": { - "name": "game_journal_entries", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "note": { - "name": "note", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": { - "game_journal_entries_game_user_idx": { - "name": "game_journal_entries_game_user_idx", - "columns": [ - { - "expression": "game_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "game_journal_entries_game_id_games_id_fk": { - "name": "game_journal_entries_game_id_games_id_fk", - "tableFrom": "game_journal_entries", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "game_journal_entries_user_id_users_id_fk": { - "name": "game_journal_entries_user_id_users_id_fk", - "tableFrom": "game_journal_entries", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.game_milestones": { - "name": "game_milestones", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "label": { - "name": "label", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "completed_at": { - "name": "completed_at", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": { - "game_milestones_game_user_idx": { - "name": "game_milestones_game_user_idx", - "columns": [ - { - "expression": "game_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "game_milestones_game_id_games_id_fk": { - "name": "game_milestones_game_id_games_id_fk", - "tableFrom": "game_milestones", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "game_milestones_user_id_users_id_fk": { - "name": "game_milestones_user_id_users_id_fk", - "tableFrom": "game_milestones", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.game_screenshots": { - "name": "game_screenshots", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "file_path": { - "name": "file_path", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "caption": { - "name": "caption", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": { - "game_screenshots_game_user_idx": { - "name": "game_screenshots_game_user_idx", - "columns": [ - { - "expression": "game_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "game_screenshots_game_id_games_id_fk": { - "name": "game_screenshots_game_id_games_id_fk", - "tableFrom": "game_screenshots", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "game_screenshots_user_id_users_id_fk": { - "name": "game_screenshots_user_id_users_id_fk", - "tableFrom": "game_screenshots", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.games": { - "name": "games", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "igdb_id": { - "name": "igdb_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "steam_appid": { - "name": "steam_appid", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "summary": { - "name": "summary", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cover_url": { - "name": "cover_url", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "release_date": { - "name": "release_date", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "rating": { - "name": "rating", - "type": "double precision", - "primaryKey": false, - "notNull": false - }, - "platforms": { - "name": "platforms", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "target_platform_id": { - "name": "target_platform_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "target_platform_name": { - "name": "target_platform_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "genres": { - "name": "genres", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "themes": { - "name": "themes", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "publishers": { - "name": "publishers", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "developers": { - "name": "developers", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "screenshots": { - "name": "screenshots", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "source": { - "name": "source", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'manual'" - }, - "igdb_websites": { - "name": "igdb_websites", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "expansions": { - "name": "expansions", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "aggregated_rating": { - "name": "aggregated_rating", - "type": "double precision", - "primaryKey": false, - "notNull": false - }, - "time_to_beat_hastily": { - "name": "time_to_beat_hastily", - "type": "double precision", - "primaryKey": false, - "notNull": false - }, - "time_to_beat_normally": { - "name": "time_to_beat_normally", - "type": "double precision", - "primaryKey": false, - "notNull": false - }, - "time_to_beat_completely": { - "name": "time_to_beat_completely", - "type": "double precision", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'wanted'" - }, - "original_release_date": { - "name": "original_release_date", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "release_status": { - "name": "release_status", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'upcoming'" - }, - "early_access": { - "name": "early_access", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "hidden": { - "name": "hidden", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "is_adult_content": { - "name": "is_adult_content", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "is_age_restricted": { - "name": "is_age_restricted", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "user_rating": { - "name": "user_rating", - "type": "double precision", - "primaryKey": false, - "notNull": false - }, - "library_path": { - "name": "library_path", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "installed_version": { - "name": "installed_version", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "search_results_available": { - "name": "search_results_available", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "search_results_available_at": { - "name": "search_results_available_at", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "update_search_results_available": { - "name": "update_search_results_available", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "packs_search_results_available": { - "name": "packs_search_results_available", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "added_at": { - "name": "added_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - }, - "completed_at": { - "name": "completed_at", - "type": "bigint", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "games_user_id_users_id_fk": { - "name": "games_user_id_users_id_fk", - "tableFrom": "games", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.import_task_items": { - "name": "import_task_items", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "task_id": { - "name": "task_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "item_name": { - "name": "item_name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "result": { - "name": "result", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "game_title": { - "name": "game_title", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "error_message": { - "name": "error_message", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": { - "import_task_items_task_id_idx": { - "name": "import_task_items_task_id_idx", - "columns": [ - { - "expression": "task_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "import_task_items_task_id_import_tasks_id_fk": { - "name": "import_task_items_task_id_import_tasks_id_fk", - "tableFrom": "import_task_items", - "tableTo": "import_tasks", - "columnsFrom": ["task_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.import_tasks": { - "name": "import_tasks", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "task_type": { - "name": "task_type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "triggered_by": { - "name": "triggered_by", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'pending'" - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - }, - "started_at": { - "name": "started_at", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "completed_at": { - "name": "completed_at", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "total_items": { - "name": "total_items", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "added_items": { - "name": "added_items", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "skipped_items": { - "name": "skipped_items", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "failed_items": { - "name": "failed_items", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "error_message": { - "name": "error_message", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "import_tasks_user_id_users_id_fk": { - "name": "import_tasks_user_id_users_id_fk", - "tableFrom": "import_tasks", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.indexers": { - "name": "indexers", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "url": { - "name": "url", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "api_key": { - "name": "api_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "protocol": { - "name": "protocol", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'torznab'" - }, - "enabled": { - "name": "enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "priority": { - "name": "priority", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "categories": { - "name": "categories", - "type": "jsonb", - "primaryKey": false, - "notNull": false, - "default": "'[]'::jsonb" - }, - "rss_enabled": { - "name": "rss_enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "auto_search_enabled": { - "name": "auto_search_enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "allow_insecure_lan": { - "name": "allow_insecure_lan", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - }, - "updated_at": { - "name": "updated_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.notifications": { - "name": "notifications", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "message": { - "name": "message", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "link": { - "name": "link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "read": { - "name": "read", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": {}, - "foreignKeys": { - "notifications_user_id_users_id_fk": { - "name": "notifications_user_id_users_id_fk", - "tableFrom": "notifications", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.path_mappings": { - "name": "path_mappings", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "remote_path": { - "name": "remote_path", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "local_path": { - "name": "local_path", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "remote_host": { - "name": "remote_host", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.platform_mappings": { - "name": "platform_mappings", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "igdb_platform_id": { - "name": "igdb_platform_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "source_platform_name": { - "name": "source_platform_name", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.release_blacklist": { - "name": "release_blacklist", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "release_title": { - "name": "release_title", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "indexer_name": { - "name": "indexer_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": { - "release_blacklist_game_title_idx": { - "name": "release_blacklist_game_title_idx", - "columns": [ - { - "expression": "game_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "release_title", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "release_blacklist_game_id_games_id_fk": { - "name": "release_blacklist_game_id_games_id_fk", - "tableFrom": "release_blacklist", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.root_folders": { - "name": "root_folders", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "path": { - "name": "path", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "enabled": { - "name": "enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "allow_delete": { - "name": "allow_delete", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "accessible": { - "name": "accessible", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "disk_free_bytes": { - "name": "disk_free_bytes", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "disk_total_bytes": { - "name": "disk_total_bytes", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "last_scanned_at": { - "name": "last_scanned_at", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "root_folders_path_unique": { - "name": "root_folders_path_unique", - "nullsNotDistinct": false, - "columns": ["path"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.rss_feed_items": { - "name": "rss_feed_items", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "feed_id": { - "name": "feed_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "guid": { - "name": "guid", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "link": { - "name": "link", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "pub_date": { - "name": "pub_date", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "source_name": { - "name": "source_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "igdb_game_id": { - "name": "igdb_game_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "igdb_game_name": { - "name": "igdb_game_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cover_url": { - "name": "cover_url", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": {}, - "foreignKeys": { - "rss_feed_items_feed_id_rss_feeds_id_fk": { - "name": "rss_feed_items_feed_id_rss_feeds_id_fk", - "tableFrom": "rss_feed_items", - "tableTo": "rss_feeds", - "columnsFrom": ["feed_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.rss_feeds": { - "name": "rss_feeds", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "url": { - "name": "url", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'custom'" - }, - "enabled": { - "name": "enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "mapping": { - "name": "mapping", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "last_check": { - "name": "last_check", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'ok'" - }, - "error_message": { - "name": "error_message", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - }, - "updated_at": { - "name": "updated_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.system_config": { - "name": "system_config", - "schema": "", - "columns": { - "key": { - "name": "key", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "value": { - "name": "value", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "updated_at": { - "name": "updated_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_settings": { - "name": "user_settings", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "auto_search_enabled": { - "name": "auto_search_enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "auto_download_enabled": { - "name": "auto_download_enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "notification_preferences": { - "name": "notification_preferences", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "search_interval_hours": { - "name": "search_interval_hours", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 6 - }, - "igdb_rate_limit_per_second": { - "name": "igdb_rate_limit_per_second", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 3 - }, - "download_rules": { - "name": "download_rules", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "last_auto_search": { - "name": "last_auto_search", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "xrel_scene_releases": { - "name": "xrel_scene_releases", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "xrel_p2p_releases": { - "name": "xrel_p2p_releases", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "auto_search_unreleased": { - "name": "auto_search_unreleased", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "steam_sync_failures": { - "name": "steam_sync_failures", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "steam_sync_enabled": { - "name": "steam_sync_enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "steam_sync_interval_hours": { - "name": "steam_sync_interval_hours", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 24 - }, - "last_steam_sync": { - "name": "last_steam_sync", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "preferred_release_groups": { - "name": "preferred_release_groups", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "filter_by_preferred_groups": { - "name": "filter_by_preferred_groups", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "release_name_blacklist": { - "name": "release_name_blacklist", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "preferred_platform": { - "name": "preferred_platform", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "hide_adult_content": { - "name": "hide_adult_content", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "hide_age_restricted_content": { - "name": "hide_age_restricted_content", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "hide_shelved_by_default": { - "name": "hide_shelved_by_default", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "hide_owned_in_has_results": { - "name": "hide_owned_in_has_results", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "enable_post_processing": { - "name": "enable_post_processing", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "auto_unpack": { - "name": "auto_unpack", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "rename_pattern": { - "name": "rename_pattern", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'{Title} ({Region})'" - }, - "overwrite_existing": { - "name": "overwrite_existing", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "transfer_mode": { - "name": "transfer_mode", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'hardlink'" - }, - "import_platform_ids": { - "name": "import_platform_ids", - "type": "jsonb", - "primaryKey": false, - "notNull": false, - "default": "'[]'::jsonb" - }, - "ignored_extensions": { - "name": "ignored_extensions", - "type": "jsonb", - "primaryKey": false, - "notNull": false, - "default": "'[]'::jsonb" - }, - "min_file_size": { - "name": "min_file_size", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "library_root": { - "name": "library_root", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'/data'" - }, - "auto_delete_after_import": { - "name": "auto_delete_after_import", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "sort_extras": { - "name": "sort_extras", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "telemetry_enabled": { - "name": "telemetry_enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "updated_at": { - "name": "updated_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": {}, - "foreignKeys": { - "user_settings_user_id_users_id_fk": { - "name": "user_settings_user_id_users_id_fk", - "tableFrom": "user_settings", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_settings_user_id_unique": { - "name": "user_settings_user_id_unique", - "nullsNotDistinct": false, - "columns": ["user_id"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.users": { - "name": "users", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "username": { - "name": "username", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "password_hash": { - "name": "password_hash", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "steam_id_64": { - "name": "steam_id_64", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "users_username_unique": { - "name": "users_username_unique", - "nullsNotDistinct": false, - "columns": ["username"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.xrel_notified_releases": { - "name": "xrel_notified_releases", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xrel_release_id": { - "name": "xrel_release_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": "(EXTRACT(EPOCH FROM now()) * 1000)::bigint" - } - }, - "indexes": {}, - "foreignKeys": { - "xrel_notified_releases_game_id_games_id_fk": { - "name": "xrel_notified_releases_game_id_games_id_fk", - "tableFrom": "xrel_notified_releases", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": {}, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} diff --git a/migrations-pg/meta/_journal.json b/migrations-pg/meta/_journal.json index beed4a2b4..adc7dc486 100644 --- a/migrations-pg/meta/_journal.json +++ b/migrations-pg/meta/_journal.json @@ -61,15 +61,8 @@ { "idx": 8, "version": "7", - "when": 1791212677241, - "tag": "0008_cultured_stephen_strange", - "breakpoints": true - }, - { - "idx": 9, - "version": "7", - "when": 1791216991452, - "tag": "0009_spicy_black_bolt", + "when": 1791226213942, + "tag": "0008_spotty_celestials", "breakpoints": true } ] diff --git a/migrations/0043_groovy_slyde.sql b/migrations/0043_groovy_slyde.sql new file mode 100644 index 000000000..5d6bfe9f2 --- /dev/null +++ b/migrations/0043_groovy_slyde.sql @@ -0,0 +1,2 @@ +ALTER TABLE `game_downloads` ADD `category` text;--> statement-breakpoint +ALTER TABLE `games` ADD `installed_version` text; \ No newline at end of file diff --git a/migrations/0043_massive_dormammu.sql b/migrations/0043_massive_dormammu.sql deleted file mode 100644 index b3df82a2e..000000000 --- a/migrations/0043_massive_dormammu.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE `games` ADD `installed_version` text; \ No newline at end of file diff --git a/migrations/0044_faulty_blazing_skull.sql b/migrations/0044_faulty_blazing_skull.sql deleted file mode 100644 index 299ea7abb..000000000 --- a/migrations/0044_faulty_blazing_skull.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE `game_downloads` ADD `category` text; \ No newline at end of file diff --git a/migrations/meta/0043_snapshot.json b/migrations/meta/0043_snapshot.json index e4a2c0b0c..474f9ca1d 100644 --- a/migrations/meta/0043_snapshot.json +++ b/migrations/meta/0043_snapshot.json @@ -1,7 +1,7 @@ { "version": "6", "dialect": "sqlite", - "id": "d6f633c9-9943-4e6d-b369-e5bfb84b2c60", + "id": "07de75d5-fb0e-439c-a9a9-fb209dd4b3b4", "prevId": "eb7a6251-80b1-4ba9-8d4c-12d0d198d3b6", "tables": { "ai_auto_download_holds": { @@ -390,6 +390,13 @@ "notNull": false, "autoincrement": false }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, "added_at": { "name": "added_at", "type": "integer", diff --git a/migrations/meta/0044_snapshot.json b/migrations/meta/0044_snapshot.json deleted file mode 100644 index 6aad78140..000000000 --- a/migrations/meta/0044_snapshot.json +++ /dev/null @@ -1,2344 +0,0 @@ -{ - "version": "6", - "dialect": "sqlite", - "id": "64392a36-24be-4d3c-a415-f902d38e52ce", - "prevId": "d6f633c9-9943-4e6d-b369-e5bfb84b2c60", - "tables": { - "ai_auto_download_holds": { - "name": "ai_auto_download_holds", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "release_title": { - "name": "release_title", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reason": { - "name": "reason", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": { - "ai_auto_download_holds_game_title_idx": { - "name": "ai_auto_download_holds_game_title_idx", - "columns": ["game_id", "release_title"], - "isUnique": true - } - }, - "foreignKeys": { - "ai_auto_download_holds_game_id_games_id_fk": { - "name": "ai_auto_download_holds_game_id_games_id_fk", - "tableFrom": "ai_auto_download_holds", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "api_keys": { - "name": "api_keys", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_hash": { - "name": "key_hash", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "prefix": { - "name": "prefix", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - }, - "last_used_at": { - "name": "last_used_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "api_keys_key_hash_idx": { - "name": "api_keys_key_hash_idx", - "columns": ["key_hash"], - "isUnique": true - }, - "api_keys_user_id_idx": { - "name": "api_keys_user_id_idx", - "columns": ["user_id"], - "isUnique": false - } - }, - "foreignKeys": { - "api_keys_user_id_users_id_fk": { - "name": "api_keys_user_id_users_id_fk", - "tableFrom": "api_keys", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "downloaders": { - "name": "downloaders", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "url": { - "name": "url", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "port": { - "name": "port", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "use_ssl": { - "name": "use_ssl", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": false - }, - "url_path": { - "name": "url_path", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "allow_self_signed_certificate": { - "name": "allow_self_signed_certificate", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "allow_insecure_lan": { - "name": "allow_insecure_lan", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "username": { - "name": "username", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enabled": { - "name": "enabled", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": true - }, - "priority": { - "name": "priority", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 1 - }, - "download_path": { - "name": "download_path", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "category": { - "name": "category", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "'games'" - }, - "label": { - "name": "label", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "'Questarr'" - }, - "add_stopped": { - "name": "add_stopped", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": false - }, - "remove_completed": { - "name": "remove_completed", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": false - }, - "post_import_category": { - "name": "post_import_category", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "settings": { - "name": "settings", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - }, - "updated_at": { - "name": "updated_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "game_downloads": { - "name": "game_downloads", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "downloader_id": { - "name": "downloader_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "download_type": { - "name": "download_type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'torrent'" - }, - "download_hash": { - "name": "download_hash", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "download_title": { - "name": "download_title", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'downloading'" - }, - "error_message": { - "name": "error_message", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "file_size": { - "name": "file_size", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "category": { - "name": "category", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "added_at": { - "name": "added_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - }, - "completed_at": { - "name": "completed_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "game_downloads_downloader_hash_idx": { - "name": "game_downloads_downloader_hash_idx", - "columns": ["downloader_id", "download_hash"], - "isUnique": true - } - }, - "foreignKeys": { - "game_downloads_game_id_games_id_fk": { - "name": "game_downloads_game_id_games_id_fk", - "tableFrom": "game_downloads", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "game_downloads_downloader_id_downloaders_id_fk": { - "name": "game_downloads_downloader_id_downloaders_id_fk", - "tableFrom": "game_downloads", - "tableTo": "downloaders", - "columnsFrom": ["downloader_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "game_files": { - "name": "game_files", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "download_id": { - "name": "download_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "original_name": { - "name": "original_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "stored_name": { - "name": "stored_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "category": { - "name": "category", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "category_overridden": { - "name": "category_overridden", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "file_path": { - "name": "file_path", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "file_size": { - "name": "file_size", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": { - "game_files_game_id_idx": { - "name": "game_files_game_id_idx", - "columns": ["game_id"], - "isUnique": false - }, - "game_files_download_id_idx": { - "name": "game_files_download_id_idx", - "columns": ["download_id"], - "isUnique": false - } - }, - "foreignKeys": { - "game_files_game_id_games_id_fk": { - "name": "game_files_game_id_games_id_fk", - "tableFrom": "game_files", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "game_files_download_id_game_downloads_id_fk": { - "name": "game_files_download_id_game_downloads_id_fk", - "tableFrom": "game_files", - "tableTo": "game_downloads", - "columnsFrom": ["download_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "game_journal_entries": { - "name": "game_journal_entries", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "note": { - "name": "note", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": { - "game_journal_entries_game_user_idx": { - "name": "game_journal_entries_game_user_idx", - "columns": ["game_id", "user_id"], - "isUnique": false - } - }, - "foreignKeys": { - "game_journal_entries_game_id_games_id_fk": { - "name": "game_journal_entries_game_id_games_id_fk", - "tableFrom": "game_journal_entries", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "game_journal_entries_user_id_users_id_fk": { - "name": "game_journal_entries_user_id_users_id_fk", - "tableFrom": "game_journal_entries", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "game_milestones": { - "name": "game_milestones", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "label": { - "name": "label", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "completed_at": { - "name": "completed_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": { - "game_milestones_game_user_idx": { - "name": "game_milestones_game_user_idx", - "columns": ["game_id", "user_id"], - "isUnique": false - } - }, - "foreignKeys": { - "game_milestones_game_id_games_id_fk": { - "name": "game_milestones_game_id_games_id_fk", - "tableFrom": "game_milestones", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "game_milestones_user_id_users_id_fk": { - "name": "game_milestones_user_id_users_id_fk", - "tableFrom": "game_milestones", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "game_screenshots": { - "name": "game_screenshots", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "file_path": { - "name": "file_path", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "caption": { - "name": "caption", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": { - "game_screenshots_game_user_idx": { - "name": "game_screenshots_game_user_idx", - "columns": ["game_id", "user_id"], - "isUnique": false - } - }, - "foreignKeys": { - "game_screenshots_game_id_games_id_fk": { - "name": "game_screenshots_game_id_games_id_fk", - "tableFrom": "game_screenshots", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "game_screenshots_user_id_users_id_fk": { - "name": "game_screenshots_user_id_users_id_fk", - "tableFrom": "game_screenshots", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "games": { - "name": "games", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "igdb_id": { - "name": "igdb_id", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "steam_appid": { - "name": "steam_appid", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "summary": { - "name": "summary", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cover_url": { - "name": "cover_url", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "release_date": { - "name": "release_date", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "rating": { - "name": "rating", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "platforms": { - "name": "platforms", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "target_platform_id": { - "name": "target_platform_id", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "target_platform_name": { - "name": "target_platform_name", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "genres": { - "name": "genres", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "themes": { - "name": "themes", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "publishers": { - "name": "publishers", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "developers": { - "name": "developers", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "screenshots": { - "name": "screenshots", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "source": { - "name": "source", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "'manual'" - }, - "igdb_websites": { - "name": "igdb_websites", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "expansions": { - "name": "expansions", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "aggregated_rating": { - "name": "aggregated_rating", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_to_beat_hastily": { - "name": "time_to_beat_hastily", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_to_beat_normally": { - "name": "time_to_beat_normally", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_to_beat_completely": { - "name": "time_to_beat_completely", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'wanted'" - }, - "original_release_date": { - "name": "original_release_date", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "release_status": { - "name": "release_status", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "'upcoming'" - }, - "early_access": { - "name": "early_access", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "hidden": { - "name": "hidden", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "is_adult_content": { - "name": "is_adult_content", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "is_age_restricted": { - "name": "is_age_restricted", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "user_rating": { - "name": "user_rating", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "library_path": { - "name": "library_path", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "installed_version": { - "name": "installed_version", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "search_results_available": { - "name": "search_results_available", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "search_results_available_at": { - "name": "search_results_available_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "update_search_results_available": { - "name": "update_search_results_available", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "packs_search_results_available": { - "name": "packs_search_results_available", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "added_at": { - "name": "added_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - }, - "completed_at": { - "name": "completed_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "games_user_id_users_id_fk": { - "name": "games_user_id_users_id_fk", - "tableFrom": "games", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "import_task_items": { - "name": "import_task_items", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "task_id": { - "name": "task_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "item_name": { - "name": "item_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "game_title": { - "name": "game_title", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "error_message": { - "name": "error_message", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": { - "import_task_items_task_id_idx": { - "name": "import_task_items_task_id_idx", - "columns": ["task_id"], - "isUnique": false - } - }, - "foreignKeys": { - "import_task_items_task_id_import_tasks_id_fk": { - "name": "import_task_items_task_id_import_tasks_id_fk", - "tableFrom": "import_task_items", - "tableTo": "import_tasks", - "columnsFrom": ["task_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "import_tasks": { - "name": "import_tasks", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "task_type": { - "name": "task_type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "triggered_by": { - "name": "triggered_by", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'pending'" - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - }, - "started_at": { - "name": "started_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "completed_at": { - "name": "completed_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "total_items": { - "name": "total_items", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "added_items": { - "name": "added_items", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "skipped_items": { - "name": "skipped_items", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "failed_items": { - "name": "failed_items", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "error_message": { - "name": "error_message", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "import_tasks_user_id_users_id_fk": { - "name": "import_tasks_user_id_users_id_fk", - "tableFrom": "import_tasks", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "indexers": { - "name": "indexers", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "url": { - "name": "url", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "api_key": { - "name": "api_key", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "protocol": { - "name": "protocol", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'torznab'" - }, - "enabled": { - "name": "enabled", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": true - }, - "priority": { - "name": "priority", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 1 - }, - "categories": { - "name": "categories", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "'[]'" - }, - "rss_enabled": { - "name": "rss_enabled", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": true - }, - "auto_search_enabled": { - "name": "auto_search_enabled", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": true - }, - "allow_insecure_lan": { - "name": "allow_insecure_lan", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - }, - "updated_at": { - "name": "updated_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "notifications": { - "name": "notifications", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "message": { - "name": "message", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "link": { - "name": "link", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "read": { - "name": "read", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": {}, - "foreignKeys": { - "notifications_user_id_users_id_fk": { - "name": "notifications_user_id_users_id_fk", - "tableFrom": "notifications", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "path_mappings": { - "name": "path_mappings", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "remote_path": { - "name": "remote_path", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "local_path": { - "name": "local_path", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "remote_host": { - "name": "remote_host", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "platform_mappings": { - "name": "platform_mappings", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "igdb_platform_id": { - "name": "igdb_platform_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "source_platform_name": { - "name": "source_platform_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "release_blacklist": { - "name": "release_blacklist", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "release_title": { - "name": "release_title", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "indexer_name": { - "name": "indexer_name", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": { - "release_blacklist_game_title_idx": { - "name": "release_blacklist_game_title_idx", - "columns": ["game_id", "release_title"], - "isUnique": true - } - }, - "foreignKeys": { - "release_blacklist_game_id_games_id_fk": { - "name": "release_blacklist_game_id_games_id_fk", - "tableFrom": "release_blacklist", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "root_folders": { - "name": "root_folders", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "path": { - "name": "path", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enabled": { - "name": "enabled", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": true - }, - "allow_delete": { - "name": "allow_delete", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "accessible": { - "name": "accessible", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "disk_free_bytes": { - "name": "disk_free_bytes", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "disk_total_bytes": { - "name": "disk_total_bytes", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "last_scanned_at": { - "name": "last_scanned_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": { - "root_folders_path_unique": { - "name": "root_folders_path_unique", - "columns": ["path"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "rss_feed_items": { - "name": "rss_feed_items", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "feed_id": { - "name": "feed_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "guid": { - "name": "guid", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "link": { - "name": "link", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "pub_date": { - "name": "pub_date", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "source_name": { - "name": "source_name", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "igdb_game_id": { - "name": "igdb_game_id", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "igdb_game_name": { - "name": "igdb_game_name", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cover_url": { - "name": "cover_url", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": {}, - "foreignKeys": { - "rss_feed_items_feed_id_rss_feeds_id_fk": { - "name": "rss_feed_items_feed_id_rss_feeds_id_fk", - "tableFrom": "rss_feed_items", - "tableTo": "rss_feeds", - "columnsFrom": ["feed_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "rss_feeds": { - "name": "rss_feeds", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "url": { - "name": "url", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'custom'" - }, - "enabled": { - "name": "enabled", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": true - }, - "mapping": { - "name": "mapping", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "last_check": { - "name": "last_check", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "'ok'" - }, - "error_message": { - "name": "error_message", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - }, - "updated_at": { - "name": "updated_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "system_config": { - "name": "system_config", - "columns": { - "key": { - "name": "key", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "value": { - "name": "value", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "user_settings": { - "name": "user_settings", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "auto_search_enabled": { - "name": "auto_search_enabled", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": true - }, - "auto_download_enabled": { - "name": "auto_download_enabled", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "notification_preferences": { - "name": "notification_preferences", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "search_interval_hours": { - "name": "search_interval_hours", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 6 - }, - "igdb_rate_limit_per_second": { - "name": "igdb_rate_limit_per_second", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 3 - }, - "download_rules": { - "name": "download_rules", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "last_auto_search": { - "name": "last_auto_search", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "xrel_scene_releases": { - "name": "xrel_scene_releases", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": true - }, - "xrel_p2p_releases": { - "name": "xrel_p2p_releases", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "auto_search_unreleased": { - "name": "auto_search_unreleased", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "steam_sync_failures": { - "name": "steam_sync_failures", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "steam_sync_enabled": { - "name": "steam_sync_enabled", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "steam_sync_interval_hours": { - "name": "steam_sync_interval_hours", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 24 - }, - "last_steam_sync": { - "name": "last_steam_sync", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "preferred_release_groups": { - "name": "preferred_release_groups", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "filter_by_preferred_groups": { - "name": "filter_by_preferred_groups", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "release_name_blacklist": { - "name": "release_name_blacklist", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "preferred_platform": { - "name": "preferred_platform", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "hide_adult_content": { - "name": "hide_adult_content", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": true - }, - "hide_age_restricted_content": { - "name": "hide_age_restricted_content", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": true - }, - "hide_shelved_by_default": { - "name": "hide_shelved_by_default", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": true - }, - "hide_owned_in_has_results": { - "name": "hide_owned_in_has_results", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": true - }, - "enable_post_processing": { - "name": "enable_post_processing", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "auto_unpack": { - "name": "auto_unpack", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "rename_pattern": { - "name": "rename_pattern", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'{Title} ({Region})'" - }, - "overwrite_existing": { - "name": "overwrite_existing", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "transfer_mode": { - "name": "transfer_mode", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'hardlink'" - }, - "import_platform_ids": { - "name": "import_platform_ids", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "'[]'" - }, - "ignored_extensions": { - "name": "ignored_extensions", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "'[]'" - }, - "min_file_size": { - "name": "min_file_size", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "library_root": { - "name": "library_root", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'/data'" - }, - "auto_delete_after_import": { - "name": "auto_delete_after_import", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "sort_extras": { - "name": "sort_extras", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "telemetry_enabled": { - "name": "telemetry_enabled", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "updated_at": { - "name": "updated_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": { - "user_settings_user_id_unique": { - "name": "user_settings_user_id_unique", - "columns": ["user_id"], - "isUnique": true - } - }, - "foreignKeys": { - "user_settings_user_id_users_id_fk": { - "name": "user_settings_user_id_users_id_fk", - "tableFrom": "user_settings", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "users": { - "name": "users", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "username": { - "name": "username", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "password_hash": { - "name": "password_hash", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "steam_id_64": { - "name": "steam_id_64", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "users_username_unique": { - "name": "users_username_unique", - "columns": ["username"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "xrel_notified_releases": { - "name": "xrel_notified_releases", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "game_id": { - "name": "game_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "xrel_release_id": { - "name": "xrel_release_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(strftime('%s', 'now') * 1000)" - } - }, - "indexes": {}, - "foreignKeys": { - "xrel_notified_releases_game_id_games_id_fk": { - "name": "xrel_notified_releases_game_id_games_id_fk", - "tableFrom": "xrel_notified_releases", - "tableTo": "games", - "columnsFrom": ["game_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - } - }, - "views": {}, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "indexes": {} - } -} diff --git a/migrations/meta/_journal.json b/migrations/meta/_journal.json index b469e0f64..d91faa092 100644 --- a/migrations/meta/_journal.json +++ b/migrations/meta/_journal.json @@ -313,15 +313,8 @@ { "idx": 43, "version": "6", - "when": 1791212676341, - "tag": "0043_massive_dormammu", - "breakpoints": true - }, - { - "idx": 44, - "version": "6", - "when": 1791216990567, - "tag": "0044_faulty_blazing_skull", + "when": 1791226212843, + "tag": "0043_groovy_slyde", "breakpoints": true } ] From c257078bc19b3f798e73d43fbd263315e636ceb4 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 18:54:32 +0000 Subject: [PATCH 28/28] Fix SonarCloud findings on the installed-version code Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01E1E7VzAePnSst4yYWpwScV --- server/storage.ts | 12 ++++++------ shared/version-utils.ts | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/server/storage.ts b/server/storage.ts index 28bffee3e..317a51ea9 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -751,28 +751,28 @@ export class MemStorage implements IStorage { return updatedGame; } - async updateGameInstalledVersion( + updateGameInstalledVersion( id: string, userId: string, installedVersion: string | null ): Promise { const game = this.games.get(id); - if (!game || game.userId !== userId) return undefined; + if (game?.userId !== userId) return Promise.resolve(undefined); const updatedGame: Game = { ...game, installedVersion }; this.games.set(id, updatedGame); - return updatedGame; + return Promise.resolve(updatedGame); } - async replaceGameInstalledVersion( + replaceGameInstalledVersion( id: string, expected: string | null, installedVersion: string ): Promise { const game = this.games.get(id); - if (!game || (game.installedVersion ?? null) !== expected) return false; + if (!game || (game.installedVersion ?? null) !== expected) return Promise.resolve(false); this.games.set(id, { ...game, installedVersion }); - return true; + return Promise.resolve(true); } async getGameJournalEntries(gameId: string, userId: string): Promise { diff --git a/shared/version-utils.ts b/shared/version-utils.ts index 6bd7cb8b4..b9764609e 100644 --- a/shared/version-utils.ts +++ b/shared/version-utils.ts @@ -69,7 +69,7 @@ const BUILD_RANGE_TARGET_ALL = new RegExp( "gi" ); const UPDATE_MARKER = new RegExp( - String.raw`${NOT_PRECEDED_BY_ALNUM}(?:update|patch)${NOT_FOLLOWED_BY_ALNUM}`, + `${NOT_PRECEDED_BY_ALNUM}(?:update|patch)${NOT_FOLLOWED_BY_ALNUM}`, "i" );