feat(db): add embedded auto-migrating schema system

Replace 4 independent schema management code paths (Docker shell
script, setup wizard pg_restore, test helpers, manual psql) with a
single migration runner embedded in the server binary.

The new server/migrations/ package uses Go embed to bundle all SQL
schemas. On startup, Migrate() creates a schema_version tracking
table, detects existing databases (auto-marks baseline as applied),
and runs pending migrations in transactions.

Key changes:
- Consolidated init.sql + 9.2-update + 33 patches into 0001_init.sql
- Setup wizard simplified to single "Apply schema" checkbox
- Test helpers use migrations.Migrate() instead of pg_restore
- Docker no longer needs schema volume mounts or init script
- Seed data (shops, events, gacha) embedded and applied via API
- Future migrations just add 0002_*.sql files — no manual steps
This commit is contained in:
Houmgaor
2026-02-23 21:19:21 +01:00
parent 6a7db47723
commit 27fb0faa1e
62 changed files with 4736 additions and 932 deletions

View File

@@ -81,7 +81,6 @@ jobs:
./www/
./savedata/
./bin/
./bundled-schema/
retention-days: 7
- name: Build Windows-amd64
@@ -97,7 +96,6 @@ jobs:
./www/
./savedata/
./bin/
./bundled-schema/
retention-days: 7
lint:

View File

@@ -45,9 +45,7 @@ jobs:
cp config.example.json staging/
cp -r www/ staging/www/
cp -r savedata/ staging/savedata/
cp -r schemas/ staging/schemas/
# Create a standalone SCHEMA.sql from init schema for convenience
cp schemas/init.sql staging/SCHEMA.sql
# Schema is now embedded in the binary via server/migrations/
cd staging && zip -r ../erupe-${{ matrix.os_name }}.zip .
- name: Upload build artifact
@@ -70,8 +68,8 @@ jobs:
with:
path: artifacts
- name: Copy SCHEMA.sql for standalone download
run: cp schemas/init.sql SCHEMA.sql
- name: Copy standalone schema for download
run: cp server/migrations/sql/0001_init.sql SCHEMA.sql
- name: Create GitHub Release
uses: softprops/action-gh-release@v2

View File

@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Embedded auto-migrating database schema system (`server/migrations/`): the server binary now contains all SQL schemas and runs migrations automatically on startup — no more `pg_restore`, manual patch ordering, or external `schemas/` directory needed
- Setup wizard: web-based first-run configuration at `http://localhost:8080` when `config.json` is missing — guides users through database connection, schema initialization, and server settings
- CI: Coverage threshold enforcement — fails build if total coverage drops below 50%
- CI: Release workflow that automatically builds and uploads Linux/Windows binaries to GitHub Releases on tag push
@@ -25,6 +26,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Schema management consolidated: replaced 4 independent code paths (Docker shell script, setup wizard, test helpers, manual psql) with a single embedded migration runner
- Setup wizard simplified: 3 schema checkboxes replaced with single "Apply database schema" checkbox
- Docker simplified: removed schema volume mounts and init script — the server binary handles everything
- Test helpers simplified: `ApplyTestSchema` now uses the migration runner instead of `pg_restore` + manual patch application
- Updated minimum Go version requirement from 1.23 to 1.25
- Improved config handling
- Refactored logout flow to save all data before cleanup (prevents data loss race conditions)

View File

@@ -16,7 +16,6 @@ RUN adduser -D -h /app erupe
WORKDIR /app
COPY --from=builder /build/erupe-ce .
COPY --from=builder /build/schemas/ ./schemas/
# www/ and bin/ are mounted at runtime if needed

View File

@@ -51,27 +51,21 @@ Docker handles the database automatically. You only need to provide quest files
2. Set up PostgreSQL and create a database:
```bash
wget https://github.com/Mezeporta/Erupe/releases/latest/download/SCHEMA.sql
psql -U postgres -d erupe -f SCHEMA.sql
createdb -U postgres erupe
```
3. Apply any patch schemas from [schemas/patch-schema/](./schemas/patch-schema/) in numerical order:
The server will automatically apply all schema migrations on first startup.
```bash
psql -U postgres -d erupe -f schemas/patch-schema/01-example-patch.sql
# Repeat for each patch file
```
4. Copy and edit the config:
3. Copy and edit the config:
```bash
cp config.example.json config.json
# Edit config.json with your database credentials
```
5. Download [quest/scenario files](#quest--scenario-files) and extract them to `bin/`
4. Download [quest/scenario files](#quest--scenario-files) and extract them to `bin/`
6. Run: `./erupe-ce`
5. Run: `./erupe-ce`
### Option C: From Source
@@ -124,7 +118,7 @@ go mod tidy
go build -o erupe-ce
```
**Check for new patch schemas** in [schemas/patch-schema/](./schemas/patch-schema/) after pulling — apply any you haven't run yet, in numerical order.
Database schema migrations are applied automatically when the server starts — no manual SQL steps needed.
### Docker
@@ -135,8 +129,6 @@ docker compose build
docker compose up
```
Apply any new patch schemas via pgAdmin or `psql` into the running container.
## Configuration
Edit `config.json` before starting the server. The essential settings are:
@@ -210,7 +202,7 @@ Erupe uses a structured schema system:
- **Initialization Schema**: Bootstraps database to version 9.1.0
- **Update Schemas**: Production-ready updates for new releases
- **Patch Schemas**: Development updates (subject to change)
- **Bundled Schemas**: Demo templates for shops, distributions, events, and gacha in [schemas/bundled-schema/](./schemas/bundled-schema/)
- **Seed Data**: Demo templates for shops, distributions, events, and gacha in [server/migrations/seed/](./server/migrations/seed/)
**Note**: Only use patch schemas if you're following active development. They get consolidated into update schemas on release.

View File

@@ -14,8 +14,6 @@ services:
- "5432:5432"
volumes:
- ./db-data/:/var/lib/postgresql/
- ../schemas/:/schemas/
- ./init/setup.sh:/docker-entrypoint-initdb.d/setup.sh
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s

View File

@@ -1,27 +0,0 @@
#!/bin/bash
set -e
echo "INIT: Restoring database schema..."
pg_restore --username="$POSTGRES_USER" --dbname="$POSTGRES_DB" --no-owner --no-acl --verbose /schemas/init.sql || {
echo "WARN: pg_restore exited with errors (this is expected if the database already has objects)"
}
echo "Updating!"
for file in /schemas/update-schema/*; do
echo " Applying $file"
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" -1 -f "$file"
done
echo "Patching!"
for file in /schemas/patch-schema/*; do
[ -f "$file" ] || continue
echo " Applying $file"
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" -1 -f "$file"
done
echo "Loading bundled data (shops, events, gacha)..."
for file in /schemas/bundled-schema/*; do
[ -f "$file" ] || continue
echo " Applying $file"
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" -1 -f "$file"
done

11
main.go
View File

@@ -16,6 +16,7 @@ import (
"erupe-ce/server/channelserver"
"erupe-ce/server/discordbot"
"erupe-ce/server/entranceserver"
"erupe-ce/server/migrations"
"erupe-ce/server/setup"
"erupe-ce/server/signserver"
"strings"
@@ -154,6 +155,16 @@ func main() {
logger.Info("Database: Started successfully")
// Run database migrations
applied, migErr := migrations.Migrate(db, logger.Named("migrations"))
if migErr != nil {
preventClose(config, fmt.Sprintf("Database migration failed: %s", migErr.Error()))
}
if applied > 0 {
ver, _ := migrations.Version(db)
logger.Info(fmt.Sprintf("Database: Applied %d migration(s), now at version %d", applied, ver))
}
// Pre-compute all server IDs this instance will own, so we only
// delete our own rows (safe for multi-instance on the same DB).
var ownedServerIDs []string

Binary file not shown.

View File

@@ -1,13 +0,0 @@
BEGIN;
ALTER TABLE users ADD COLUMN IF NOT EXISTS psn_id TEXT;
ALTER TABLE public.sign_sessions ADD COLUMN id SERIAL;
ALTER TABLE public.sign_sessions ADD CONSTRAINT sign_sessions_pkey PRIMARY KEY (id);
ALTER TABLE public.sign_sessions ALTER COLUMN user_id DROP NOT NULL;
ALTER TABLE public.sign_sessions ADD COLUMN psn_id TEXT;
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
ALTER TABLE public.users ADD COLUMN IF NOT EXISTS wiiu_key TEXT;
END;

View File

@@ -1,29 +0,0 @@
BEGIN;
CREATE TABLE IF NOT EXISTS tower (
char_id INT,
tr INT,
trp INT,
tsp INT,
block1 INT,
block2 INT,
skills TEXT,
gems TEXT
);
ALTER TABLE IF EXISTS guild_characters
ADD COLUMN IF NOT EXISTS tower_mission_1 INT;
ALTER TABLE IF EXISTS guild_characters
ADD COLUMN IF NOT EXISTS tower_mission_2 INT;
ALTER TABLE IF EXISTS guild_characters
ADD COLUMN IF NOT EXISTS tower_mission_3 INT;
ALTER TABLE IF EXISTS guilds
ADD COLUMN IF NOT EXISTS tower_mission_page INT DEFAULT 1;
ALTER TABLE IF EXISTS guilds
ADD COLUMN IF NOT EXISTS tower_rp INT DEFAULT 0;
END;

View File

@@ -1,14 +0,0 @@
BEGIN;
create table if not exists event_quests
(
id serial primary key,
max_players integer,
quest_type integer not null,
quest_id integer not null,
mark integer
);
ALTER TABLE IF EXISTS public.servers DROP COLUMN IF EXISTS season;
END;

View File

@@ -1,7 +0,0 @@
CREATE TABLE public.trend_weapons
(
weapon_id integer NOT NULL,
weapon_type integer NOT NULL,
count integer DEFAULT 0,
PRIMARY KEY (weapon_id)
);

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.gacha_entries
ADD COLUMN name text;
END;

View File

@@ -1,11 +0,0 @@
BEGIN;
ALTER TABLE gook RENAME TO goocoo;
ALTER TABLE goocoo RENAME COLUMN gook0 TO goocoo0;
ALTER TABLE goocoo RENAME COLUMN gook1 TO goocoo1;
ALTER TABLE goocoo RENAME COLUMN gook2 TO goocoo2;
ALTER TABLE goocoo RENAME COLUMN gook3 TO goocoo3;
ALTER TABLE goocoo RENAME COLUMN gook4 TO goocoo4;
END;

View File

@@ -1,9 +0,0 @@
BEGIN;
CREATE TABLE IF NOT EXISTS scenario_counter (
id serial primary key,
scenario_id numeric not null,
category_id numeric not null
);
END;

View File

@@ -1,12 +0,0 @@
CREATE TABLE public.kill_logs
(
id serial,
character_id integer NOT NULL,
monster integer NOT NULL,
quantity integer NOT NULL,
timestamp timestamp with time zone NOT NULL,
PRIMARY KEY (id)
);
ALTER TABLE IF EXISTS public.guild_characters
ADD COLUMN box_claimed timestamp with time zone DEFAULT now();

View File

@@ -1,26 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.guild_hunts DROP COLUMN IF EXISTS hunters;
ALTER TABLE IF EXISTS public.guild_characters
ADD COLUMN treasure_hunt integer;
ALTER TABLE IF EXISTS public.guild_hunts
ADD COLUMN start timestamp with time zone NOT NULL DEFAULT now();
UPDATE guild_hunts SET start=to_timestamp(return);
ALTER TABLE IF EXISTS public.guild_hunts DROP COLUMN IF EXISTS "return";
ALTER TABLE IF EXISTS public.guild_hunts
RENAME claimed TO collected;
CREATE TABLE public.guild_hunts_claimed
(
hunt_id integer NOT NULL,
character_id integer NOT NULL
);
ALTER TABLE IF EXISTS public.guild_hunts DROP COLUMN IF EXISTS treasure;
END;

View File

@@ -1,36 +0,0 @@
BEGIN;
-- This will delete all of your old distribution data!
--ALTER TABLE IF EXISTS public.distribution DROP COLUMN IF EXISTS data;
CREATE TABLE public.distribution_items
(
id serial PRIMARY KEY,
distribution_id integer NOT NULL,
item_type integer NOT NULL,
item_id integer,
quantity integer
);
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_hr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_hr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_sr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_sr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_gr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_gr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_hr DROP NOT NULL;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_hr DROP NOT NULL;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_sr DROP NOT NULL;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_sr DROP NOT NULL;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_gr DROP NOT NULL;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_gr DROP NOT NULL;
UPDATE distribution SET min_hr=NULL WHERE min_hr=65535;
UPDATE distribution SET max_hr=NULL WHERE max_hr=65535;
UPDATE distribution SET min_sr=NULL WHERE min_sr=65535;
UPDATE distribution SET max_sr=NULL WHERE max_sr=65535;
UPDATE distribution SET min_gr=NULL WHERE min_gr=65535;
UPDATE distribution SET max_gr=NULL WHERE max_gr=65535;
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.event_quests ADD COLUMN IF NOT EXISTS flags integer;
END;

View File

@@ -1,10 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.event_quests ADD COLUMN IF NOT EXISTS start_time timestamp with time zone NOT NULL DEFAULT now();
ALTER TABLE IF EXISTS public.event_quests ADD COLUMN IF NOT EXISTS active_duration int;
ALTER TABLE IF EXISTS public.event_quests ADD COLUMN IF NOT EXISTS inactive_duration int;
UPDATE public.event_quests SET active_duration=NULL, inactive_duration=NULL;
ALTER TABLE IF EXISTS public.event_quests RENAME active_duration TO active_days;
ALTER TABLE IF EXISTS public.event_quests RENAME inactive_duration TO inactive_days;
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.guild_characters ADD COLUMN trial_vote integer;
END;

View File

@@ -1,20 +0,0 @@
DO $$ BEGIN
-- Only apply if the new-schema columns exist (item_type vs legacy itemtype)
IF EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name='fpoint_items' AND column_name='item_type'
) THEN
DELETE FROM public.fpoint_items;
ALTER TABLE public.fpoint_items ALTER COLUMN item_type SET NOT NULL;
ALTER TABLE public.fpoint_items ALTER COLUMN item_id SET NOT NULL;
ALTER TABLE public.fpoint_items ALTER COLUMN quantity SET NOT NULL;
ALTER TABLE public.fpoint_items ALTER COLUMN fpoints SET NOT NULL;
ALTER TABLE public.fpoint_items DROP COLUMN IF EXISTS trade_type;
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name='fpoint_items' AND column_name='buyable'
) THEN
ALTER TABLE public.fpoint_items ADD COLUMN buyable boolean NOT NULL DEFAULT false;
END IF;
END IF;
END $$;

View File

@@ -1,5 +0,0 @@
BEGIN;
UPDATE goocoo SET goocoo0=NULL, goocoo1=NULL, goocoo2=NULL, goocoo3=NULL, goocoo4=NULL;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.users ADD COLUMN discord_token text;
ALTER TABLE IF EXISTS public.users ADD COLUMN discord_id text;
END;

View File

@@ -1,12 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.users ADD COLUMN op boolean;
CREATE TABLE public.bans
(
user_id integer NOT NULL,
expires timestamp with time zone,
PRIMARY KEY (user_id)
);
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
ALTER TABLE users ADD COLUMN IF NOT EXISTS timer bool;
END;

View File

@@ -1,16 +0,0 @@
CREATE TABLE IF NOT EXISTS festa_submissions (
character_id int NOT NULL,
guild_id int NOT NULL,
trial_type int NOT NULL,
souls int NOT NULL,
timestamp timestamp with time zone NOT NULL
);
ALTER TABLE guild_characters DROP COLUMN IF EXISTS souls;
DO $$ BEGIN
ALTER TYPE festival_colour RENAME TO festival_color;
EXCEPTION
WHEN undefined_object THEN NULL;
WHEN duplicate_object THEN NULL;
END $$;

View File

@@ -1,6 +0,0 @@
BEGIN;
UPDATE guilds SET item_box=NULL;
UPDATE users SET item_box=NULL;
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.characters RENAME hrp TO hr;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE guilds ADD COLUMN IF NOT EXISTS room_rp INT DEFAULT 0;
ALTER TABLE guilds ADD COLUMN IF NOT EXISTS room_expiry TIMESTAMP WITHOUT TIME ZONE;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE distribution ADD COLUMN rights INTEGER;
ALTER TABLE distribution ADD COLUMN selection BOOLEAN;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.stamps RENAME hl_next TO hl_checked;
ALTER TABLE IF EXISTS public.stamps RENAME ex_next TO ex_checked;
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
CREATE SEQUENCE IF NOT EXISTS public.rasta_id_seq;
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
ALTER TABLE mail ADD COLUMN IF NOT EXISTS is_sys_message BOOLEAN NOT NULL DEFAULT false;
END;

View File

@@ -1,15 +0,0 @@
BEGIN;
-- Initialize otomoairou (mercenary data) with default empty data for characters that have NULL or empty values
-- This prevents error logs when loading mercenary data during zone transitions
UPDATE characters
SET otomoairou = decode(repeat('00', 10), 'hex')
WHERE otomoairou IS NULL OR length(otomoairou) = 0;
-- Initialize platemyset (plate configuration) with default empty data for characters that have NULL or empty values
-- This prevents error logs when loading plate data during zone transitions
UPDATE characters
SET platemyset = decode(repeat('00', 1920), 'hex')
WHERE platemyset IS NULL OR length(platemyset) = 0;
COMMIT;

View File

@@ -1,7 +0,0 @@
-- Drop transient binary columns that are now memory-only.
-- UserBinary type2/type3 and characters.minidata are session state
-- resent by the client on every login; they do not need persistence.
ALTER TABLE user_binary DROP COLUMN IF EXISTS type2;
ALTER TABLE user_binary DROP COLUMN IF EXISTS type3;
ALTER TABLE characters DROP COLUMN IF EXISTS minidata;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.guilds
ADD COLUMN IF NOT EXISTS weekly_bonus_users INT NOT NULL DEFAULT 0;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.gacha_stepup
ADD COLUMN IF NOT EXISTS created_at TIMESTAMP WITH TIME ZONE DEFAULT now();
ALTER TABLE IF EXISTS public.guilds
ADD COLUMN IF NOT EXISTS rp_reset_at TIMESTAMP WITH TIME ZONE;
END;

View File

@@ -1,3 +0,0 @@
ALTER TABLE IF EXISTS public.stamps ADD COLUMN IF NOT EXISTS monthly_claimed TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.stamps ADD COLUMN IF NOT EXISTS monthly_hl_claimed TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.stamps ADD COLUMN IF NOT EXISTS monthly_ex_claimed TIMESTAMP WITH TIME ZONE;

View File

@@ -1,6 +0,0 @@
BEGIN;
-- Add soft-delete column to guild_posts, matching the pattern used by characters and mail tables.
ALTER TABLE guild_posts ADD COLUMN IF NOT EXISTS deleted boolean DEFAULT false NOT NULL;
COMMIT;

View File

@@ -1,241 +0,0 @@
BEGIN;
DROP TABLE IF EXISTS public.fpoint_items;
CREATE TABLE IF NOT EXISTS public.fpoint_items (
id serial PRIMARY KEY,
item_type integer,
item_id integer,
quantity integer,
fpoints integer,
trade_type integer
);
ALTER TABLE IF EXISTS public.characters ADD bonus_quests INT NOT NULL DEFAULT 0;
ALTER TABLE IF EXISTS public.characters ADD daily_quests INT NOT NULL DEFAULT 0;
ALTER TABLE IF EXISTS public.characters ADD promo_points INT NOT NULL DEFAULT 0;
ALTER TABLE IF EXISTS public.guild_characters ADD rp_today INT DEFAULT 0;
ALTER TABLE IF EXISTS public.guild_characters ADD rp_yesterday INT DEFAULT 0;
UPDATE public.characters SET savemercenary = NULL;
ALTER TABLE IF EXISTS public.characters ADD rasta_id INT;
ALTER TABLE IF EXISTS public.characters ADD pact_id INT;
ALTER TABLE IF EXISTS public.characters ADD stampcard INT NOT NULL DEFAULT 0;
ALTER TABLE IF EXISTS public.characters DROP COLUMN IF EXISTS gacha_prem;
ALTER TABLE IF EXISTS public.characters DROP COLUMN IF EXISTS gacha_trial;
ALTER TABLE IF EXISTS public.characters DROP COLUMN IF EXISTS frontier_points;
ALTER TABLE IF EXISTS public.users ADD IF NOT EXISTS gacha_premium INT;
ALTER TABLE IF EXISTS public.users ADD IF NOT EXISTS gacha_trial INT;
ALTER TABLE IF EXISTS public.users ADD IF NOT EXISTS frontier_points INT;
DROP TABLE IF EXISTS public.gacha_shop;
CREATE TABLE IF NOT EXISTS public.gacha_shop (
id SERIAL PRIMARY KEY,
min_gr INTEGER,
min_hr INTEGER,
name TEXT,
url_banner TEXT,
url_feature TEXT,
url_thumbnail TEXT,
wide BOOLEAN,
recommended BOOLEAN,
gacha_type INTEGER,
hidden BOOLEAN
);
DROP TABLE IF EXISTS public.gacha_shop_items;
CREATE TABLE IF NOT EXISTS public.gacha_entries (
id SERIAL PRIMARY KEY,
gacha_id INTEGER,
entry_type INTEGER,
item_type INTEGER,
item_number INTEGER,
item_quantity INTEGER,
weight INTEGER,
rarity INTEGER,
rolls INTEGER,
frontier_points INTEGER,
daily_limit INTEGER
);
CREATE TABLE IF NOT EXISTS public.gacha_items (
id SERIAL PRIMARY KEY,
entry_id INTEGER,
item_type INTEGER,
item_id INTEGER,
quantity INTEGER
);
DROP TABLE IF EXISTS public.stepup_state;
CREATE TABLE IF NOT EXISTS public.gacha_stepup (
gacha_id INTEGER,
step INTEGER,
character_id INTEGER
);
DROP TABLE IF EXISTS public.lucky_box_state;
CREATE TABLE IF NOT EXISTS public.gacha_box (
gacha_id INTEGER,
entry_id INTEGER,
character_id INTEGER
);
DROP TABLE IF EXISTS public.login_boost_state;
CREATE TABLE IF NOT EXISTS public.login_boost (
char_id INTEGER,
week_req INTEGER,
expiration TIMESTAMP WITH TIME ZONE,
reset TIMESTAMP WITH TIME ZONE
);
ALTER TABLE IF EXISTS public.characters ADD COLUMN mezfes BYTEA;
ALTER TABLE IF EXISTS public.characters ALTER COLUMN daily_time TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.characters ALTER COLUMN guild_post_checked TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.characters ALTER COLUMN boost_time TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.characters ADD COLUMN IF NOT EXISTS cafe_reset TIMESTAMP WITHOUT TIME ZONE;
ALTER TABLE IF EXISTS public.characters ALTER COLUMN cafe_reset TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN deadline TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.events ALTER COLUMN start_time TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.feature_weapon ALTER COLUMN start_time TYPE TIMESTAMP WITH TIME ZONE;
CREATE TABLE IF NOT EXISTS public.feature_weapon
(
start_time TIMESTAMP WITH TIME ZONE NOT NULL,
featured INTEGER NOT NULL
);
ALTER TABLE IF EXISTS public.guild_alliances ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.guild_applications ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.guild_characters ALTER COLUMN joined_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.guild_posts ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.characters ALTER COLUMN daily_time TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.guilds ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.mail ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.stamps ALTER COLUMN hl_next TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.stamps ALTER COLUMN ex_next TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.titles ALTER COLUMN unlocked_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.titles ALTER COLUMN updated_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.users ALTER COLUMN last_login TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.users ALTER COLUMN return_expires TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.guild_meals DROP COLUMN IF EXISTS expires;
ALTER TABLE IF EXISTS public.guild_meals ADD COLUMN IF NOT EXISTS created_at TIMESTAMP WITH TIME ZONE;
DROP TABLE IF EXISTS public.account_ban;
DROP TABLE IF EXISTS public.account_history;
DROP TABLE IF EXISTS public.account_moderation;
DROP TABLE IF EXISTS public.account_sub;
DROP TABLE IF EXISTS public.history;
DROP TABLE IF EXISTS public.questlists;
DROP TABLE IF EXISTS public.schema_migrations;
DROP TABLE IF EXISTS public.user_binaries;
DROP PROCEDURE IF EXISTS raviinit;
DROP PROCEDURE IF EXISTS ravireset;
ALTER TABLE IF EXISTS public.normal_shop_items RENAME TO shop_items;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN shoptype TO shop_type;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN shopid TO shop_id;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN itemhash TO id;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN itemid TO item_id;
ALTER TABLE IF EXISTS public.shop_items ALTER COLUMN points TYPE integer;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN points TO cost;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN tradequantity TO quantity;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN rankreqlow TO min_hr;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN rankreqhigh TO min_sr;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN rankreqg TO min_gr;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN storelevelreq TO store_level;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN maximumquantity TO max_quantity;
ALTER TABLE IF EXISTS public.shop_items DROP COLUMN IF EXISTS boughtquantity;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN roadfloorsrequired TO road_floors;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN weeklyfataliskills TO road_fatalis;
ALTER TABLE public.shop_items RENAME CONSTRAINT normal_shop_items_pkey TO shop_items_pkey;
ALTER TABLE IF EXISTS public.shop_items DROP CONSTRAINT IF EXISTS normal_shop_items_itemhash_key;
CREATE SEQUENCE IF NOT EXISTS public.shop_items_id_seq;
ALTER SEQUENCE IF EXISTS public.shop_items_id_seq OWNER TO postgres;
ALTER TABLE IF EXISTS public.shop_items ALTER COLUMN id SET DEFAULT nextval('shop_items_id_seq'::regclass);
ALTER SEQUENCE IF EXISTS public.shop_items_id_seq OWNED BY shop_items.id;
SELECT setval('shop_items_id_seq', (SELECT MAX(id) FROM public.shop_items));
DROP TABLE IF EXISTS public.shop_item_state;
CREATE TABLE IF NOT EXISTS public.shop_items_bought (
character_id INTEGER,
shop_item_id INTEGER,
bought INTEGER
);
UPDATE users SET rights = rights-2;
ALTER TABLE IF EXISTS public.users ALTER COLUMN rights SET DEFAULT 12;
END;

View File

@@ -3,17 +3,16 @@ package channelserver
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
"sync"
"testing"
"time"
"erupe-ce/server/channelserver/compression/nullcomp"
"erupe-ce/server/migrations"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
"go.uber.org/zap"
)
var (
@@ -104,147 +103,14 @@ func CleanTestDB(t *testing.T, db *sqlx.DB) {
}
}
// ApplyTestSchema applies the database schema from init.sql using pg_restore
// ApplyTestSchema applies the database schema using the embedded migration system.
func ApplyTestSchema(t *testing.T, db *sqlx.DB) {
t.Helper()
// Find the project root (where schemas/ directory is located)
projectRoot := findProjectRoot(t)
schemaPath := filepath.Join(projectRoot, "schemas", "init.sql")
// Get the connection config
config := DefaultTestDBConfig()
// Use pg_restore to load the schema dump
// The init.sql file is a pg_dump custom format, so we need pg_restore
cmd := exec.Command("pg_restore",
"-h", config.Host,
"-p", config.Port,
"-U", config.User,
"-d", config.DBName,
"--no-owner",
"--no-acl",
schemaPath,
)
cmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", config.Password))
output, err := cmd.CombinedOutput()
logger, _ := zap.NewDevelopment()
_, err := migrations.Migrate(db, logger.Named("test-migrations"))
if err != nil {
out := string(output)
// pg_restore reports non-fatal warnings (version mismatches, already exists) as errors.
// Only fail if we see no "errors ignored on restore" summary, which means a real failure.
if !strings.Contains(out, "errors ignored on restore") {
t.Fatalf("pg_restore failed: %v\n%s", err, out)
}
t.Logf("pg_restore completed with non-fatal warnings (ignored)")
}
// Apply the 9.2 update schema (init.sql bootstraps to 9.1.0)
applyUpdateSchema(t, db, projectRoot)
// Apply patch schemas in order
applyPatchSchemas(t, db, projectRoot)
}
// applyUpdateSchema applies the 9.2 update schema that bridges init.sql (v9.1.0) to v9.2.0.
// It runs each statement individually to tolerate partial failures (e.g. role references).
func applyUpdateSchema(t *testing.T, db *sqlx.DB, projectRoot string) {
t.Helper()
updatePath := filepath.Join(projectRoot, "schemas", "update-schema", "9.2-update.sql")
updateSQL, err := os.ReadFile(updatePath)
if err != nil {
t.Logf("Warning: Could not read 9.2 update schema: %v", err)
return
}
// Strip the outer BEGIN/END transaction wrapper so we can run statements individually.
content := string(updateSQL)
content = strings.Replace(content, "BEGIN;", "", 1)
// Remove trailing END; (last occurrence)
if idx := strings.LastIndex(content, "END;"); idx >= 0 {
content = content[:idx] + content[idx+4:]
}
// Split on semicolons and execute each statement, tolerating errors from
// role references or already-applied changes.
for _, stmt := range strings.Split(content, ";") {
stmt = strings.TrimSpace(stmt)
if stmt == "" {
continue
}
_, _ = db.Exec(stmt) // Errors expected for role mismatches, already-applied changes, etc.
}
}
// applyPatchSchemas applies all patch schema files in numeric order
func applyPatchSchemas(t *testing.T, db *sqlx.DB, projectRoot string) {
t.Helper()
patchDir := filepath.Join(projectRoot, "schemas", "patch-schema")
entries, err := os.ReadDir(patchDir)
if err != nil {
t.Logf("Warning: Could not read patch-schema directory: %v", err)
return
}
// Sort patch files numerically
var patchFiles []string
for _, entry := range entries {
if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".sql") {
patchFiles = append(patchFiles, entry.Name())
}
}
sort.Strings(patchFiles)
// Apply each patch in its own transaction
for _, filename := range patchFiles {
patchPath := filepath.Join(patchDir, filename)
patchSQL, err := os.ReadFile(patchPath)
if err != nil {
t.Logf("Warning: Failed to read patch file %s: %v", filename, err)
continue
}
// Start a new transaction for each patch
tx, err := db.Begin()
if err != nil {
t.Logf("Warning: Failed to start transaction for patch %s: %v", filename, err)
continue
}
_, err = tx.Exec(string(patchSQL))
if err != nil {
_ = tx.Rollback()
t.Logf("Warning: Failed to apply patch %s: %v", filename, err)
// Continue with other patches even if one fails
} else {
_ = tx.Commit()
}
}
}
// findProjectRoot finds the project root directory by looking for the schemas directory
func findProjectRoot(t *testing.T) string {
t.Helper()
// Start from current directory and walk up
dir, err := os.Getwd()
if err != nil {
t.Fatalf("Failed to get working directory: %v", err)
}
for {
schemasPath := filepath.Join(dir, "schemas")
if stat, err := os.Stat(schemasPath); err == nil && stat.IsDir() {
return dir
}
parent := filepath.Dir(dir)
if parent == dir {
t.Fatal("Could not find project root (schemas directory not found)")
}
dir = parent
t.Fatalf("Failed to apply schema migrations: %v", err)
}
}

View File

@@ -0,0 +1,229 @@
package migrations
import (
"embed"
"fmt"
"io/fs"
"sort"
"strconv"
"strings"
"github.com/jmoiron/sqlx"
"go.uber.org/zap"
)
//go:embed sql/*.sql
var migrationFS embed.FS
//go:embed seed/*.sql
var seedFS embed.FS
// Migrate creates the schema_version table if needed, detects existing databases
// (auto-marks baseline as applied), then runs all pending migrations in order.
// Each migration runs in its own transaction.
func Migrate(db *sqlx.DB, logger *zap.Logger) (int, error) {
if err := ensureVersionTable(db); err != nil {
return 0, fmt.Errorf("creating schema_version table: %w", err)
}
if err := detectExistingDB(db, logger); err != nil {
return 0, fmt.Errorf("detecting existing database: %w", err)
}
migrations, err := readMigrations()
if err != nil {
return 0, fmt.Errorf("reading migration files: %w", err)
}
applied, err := appliedVersions(db)
if err != nil {
return 0, fmt.Errorf("querying applied versions: %w", err)
}
count := 0
for _, m := range migrations {
if applied[m.version] {
continue
}
logger.Info(fmt.Sprintf("Applying migration %04d: %s", m.version, m.filename))
if err := applyMigration(db, m); err != nil {
return count, fmt.Errorf("applying %s: %w", m.filename, err)
}
count++
}
return count, nil
}
// ApplySeedData runs all seed/*.sql files. Not tracked in schema_version.
// Safe to run multiple times if seed files use ON CONFLICT DO NOTHING.
func ApplySeedData(db *sqlx.DB, logger *zap.Logger) (int, error) {
files, err := fs.ReadDir(seedFS, "seed")
if err != nil {
return 0, fmt.Errorf("reading seed directory: %w", err)
}
var names []string
for _, f := range files {
if !f.IsDir() && strings.HasSuffix(f.Name(), ".sql") {
names = append(names, f.Name())
}
}
sort.Strings(names)
count := 0
for _, name := range names {
data, err := seedFS.ReadFile("seed/" + name)
if err != nil {
return count, fmt.Errorf("reading seed file %s: %w", name, err)
}
logger.Info(fmt.Sprintf("Applying seed data: %s", name))
if _, err := db.Exec(string(data)); err != nil {
return count, fmt.Errorf("executing seed file %s: %w", name, err)
}
count++
}
return count, nil
}
// Version returns the highest applied migration number, or 0 if none.
func Version(db *sqlx.DB) (int, error) {
var exists bool
err := db.QueryRow(`SELECT EXISTS(
SELECT 1 FROM information_schema.tables
WHERE table_schema = 'public' AND table_name = 'schema_version'
)`).Scan(&exists)
if err != nil {
return 0, err
}
if !exists {
return 0, nil
}
var version int
err = db.QueryRow("SELECT COALESCE(MAX(version), 0) FROM schema_version").Scan(&version)
return version, err
}
type migration struct {
version int
filename string
sql string
}
func ensureVersionTable(db *sqlx.DB) error {
_, err := db.Exec(`CREATE TABLE IF NOT EXISTS schema_version (
version INTEGER PRIMARY KEY,
filename TEXT NOT NULL,
applied_at TIMESTAMPTZ DEFAULT now()
)`)
return err
}
// detectExistingDB checks if the database has tables but no schema_version rows.
// If so, it marks the baseline migration (version 1) as already applied.
func detectExistingDB(db *sqlx.DB, logger *zap.Logger) error {
var count int
if err := db.QueryRow("SELECT COUNT(*) FROM schema_version").Scan(&count); err != nil {
return err
}
if count > 0 {
return nil // Already tracked
}
// Check if the database has any user tables (beyond schema_version itself)
var tableCount int
err := db.QueryRow(`SELECT COUNT(*) FROM information_schema.tables
WHERE table_schema = 'public' AND table_name != 'schema_version'`).Scan(&tableCount)
if err != nil {
return err
}
if tableCount == 0 {
return nil // Fresh database
}
// Existing database without migration tracking — mark baseline as applied
logger.Info("Detected existing database without schema_version tracking, marking baseline as applied")
_, err = db.Exec("INSERT INTO schema_version (version, filename) VALUES (1, '0001_init.sql')")
return err
}
func readMigrations() ([]migration, error) {
files, err := fs.ReadDir(migrationFS, "sql")
if err != nil {
return nil, err
}
var migrations []migration
for _, f := range files {
if f.IsDir() || !strings.HasSuffix(f.Name(), ".sql") {
continue
}
version, err := parseVersion(f.Name())
if err != nil {
return nil, fmt.Errorf("parsing version from %s: %w", f.Name(), err)
}
data, err := migrationFS.ReadFile("sql/" + f.Name())
if err != nil {
return nil, err
}
migrations = append(migrations, migration{
version: version,
filename: f.Name(),
sql: string(data),
})
}
sort.Slice(migrations, func(i, j int) bool {
return migrations[i].version < migrations[j].version
})
return migrations, nil
}
func parseVersion(filename string) (int, error) {
parts := strings.SplitN(filename, "_", 2)
if len(parts) < 2 {
return 0, fmt.Errorf("invalid migration filename: %s (expected NNNN_description.sql)", filename)
}
return strconv.Atoi(parts[0])
}
func appliedVersions(db *sqlx.DB) (map[int]bool, error) {
rows, err := db.Query("SELECT version FROM schema_version")
if err != nil {
return nil, err
}
defer func() { _ = rows.Close() }()
applied := make(map[int]bool)
for rows.Next() {
var v int
if err := rows.Scan(&v); err != nil {
return nil, err
}
applied[v] = true
}
return applied, rows.Err()
}
func applyMigration(db *sqlx.DB, m migration) error {
tx, err := db.Begin()
if err != nil {
return err
}
if _, err := tx.Exec(m.sql); err != nil {
_ = tx.Rollback()
return err
}
if _, err := tx.Exec(
"INSERT INTO schema_version (version, filename) VALUES ($1, $2)",
m.version, m.filename,
); err != nil {
_ = tx.Rollback()
return err
}
return tx.Commit()
}

View File

@@ -0,0 +1,202 @@
package migrations
import (
"fmt"
"os"
"testing"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
"go.uber.org/zap"
)
func testDB(t *testing.T) *sqlx.DB {
t.Helper()
host := getEnv("TEST_DB_HOST", "localhost")
port := getEnv("TEST_DB_PORT", "5433")
user := getEnv("TEST_DB_USER", "test")
password := getEnv("TEST_DB_PASSWORD", "test")
dbName := getEnv("TEST_DB_NAME", "erupe_test")
connStr := fmt.Sprintf(
"host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
host, port, user, password, dbName,
)
db, err := sqlx.Open("postgres", connStr)
if err != nil {
t.Skipf("Test database not available: %v", err)
return nil
}
if err := db.Ping(); err != nil {
_ = db.Close()
t.Skipf("Test database not available: %v", err)
return nil
}
// Clean slate
_, err = db.Exec("DROP SCHEMA public CASCADE; CREATE SCHEMA public;")
if err != nil {
t.Fatalf("Failed to clean database: %v", err)
}
return db
}
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
func TestMigrateEmptyDB(t *testing.T) {
db := testDB(t)
defer func() { _ = db.Close() }()
logger, _ := zap.NewDevelopment()
applied, err := Migrate(db, logger)
if err != nil {
t.Fatalf("Migrate failed: %v", err)
}
if applied != 1 {
t.Errorf("expected 1 migration applied, got %d", applied)
}
ver, err := Version(db)
if err != nil {
t.Fatalf("Version failed: %v", err)
}
if ver != 1 {
t.Errorf("expected version 1, got %d", ver)
}
}
func TestMigrateAlreadyMigrated(t *testing.T) {
db := testDB(t)
defer func() { _ = db.Close() }()
logger, _ := zap.NewDevelopment()
// First run
_, err := Migrate(db, logger)
if err != nil {
t.Fatalf("First Migrate failed: %v", err)
}
// Second run should apply 0
applied, err := Migrate(db, logger)
if err != nil {
t.Fatalf("Second Migrate failed: %v", err)
}
if applied != 0 {
t.Errorf("expected 0 migrations on second run, got %d", applied)
}
}
func TestMigrateExistingDBWithoutSchemaVersion(t *testing.T) {
db := testDB(t)
defer func() { _ = db.Close() }()
logger, _ := zap.NewDevelopment()
// Simulate an existing database: create a dummy table
_, err := db.Exec("CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)")
if err != nil {
t.Fatalf("Failed to create dummy table: %v", err)
}
// Migrate should detect existing DB and auto-mark baseline
applied, err := Migrate(db, logger)
if err != nil {
t.Fatalf("Migrate failed: %v", err)
}
// Baseline (0001) is auto-marked, so 0 "new" migrations applied
if applied != 0 {
t.Errorf("expected 0 migrations applied (baseline auto-marked), got %d", applied)
}
ver, err := Version(db)
if err != nil {
t.Fatalf("Version failed: %v", err)
}
if ver != 1 {
t.Errorf("expected version 1 (auto-marked baseline), got %d", ver)
}
}
func TestVersionEmptyDB(t *testing.T) {
db := testDB(t)
defer func() { _ = db.Close() }()
ver, err := Version(db)
if err != nil {
t.Fatalf("Version failed: %v", err)
}
if ver != 0 {
t.Errorf("expected version 0 on empty DB, got %d", ver)
}
}
func TestApplySeedData(t *testing.T) {
db := testDB(t)
defer func() { _ = db.Close() }()
logger, _ := zap.NewDevelopment()
// Apply schema first
_, err := Migrate(db, logger)
if err != nil {
t.Fatalf("Migrate failed: %v", err)
}
count, err := ApplySeedData(db, logger)
if err != nil {
t.Fatalf("ApplySeedData failed: %v", err)
}
if count == 0 {
t.Error("expected at least 1 seed file applied, got 0")
}
}
func TestParseVersion(t *testing.T) {
tests := []struct {
filename string
want int
wantErr bool
}{
{"0001_init.sql", 1, false},
{"0002_add_users.sql", 2, false},
{"0100_big_change.sql", 100, false},
{"bad.sql", 0, true},
}
for _, tt := range tests {
got, err := parseVersion(tt.filename)
if (err != nil) != tt.wantErr {
t.Errorf("parseVersion(%q) error = %v, wantErr %v", tt.filename, err, tt.wantErr)
continue
}
if got != tt.want {
t.Errorf("parseVersion(%q) = %d, want %d", tt.filename, got, tt.want)
}
}
}
func TestReadMigrations(t *testing.T) {
migrations, err := readMigrations()
if err != nil {
t.Fatalf("readMigrations failed: %v", err)
}
if len(migrations) == 0 {
t.Fatal("expected at least 1 migration, got 0")
}
if migrations[0].version != 1 {
t.Errorf("first migration version = %d, want 1", migrations[0].version)
}
if migrations[0].filename != "0001_init.sql" {
t.Errorf("first migration filename = %q, want 0001_init.sql", migrations[0].filename)
}
}

View File

@@ -0,0 +1,11 @@
BEGIN;
-- Adds a Distribution that can be accepted up to 20 times that gives one of Item Type 30 (Item Box extra page)
INSERT INTO distribution (type, event_name, description, times_acceptable, data) VALUES (1, 'Extra Item Storage', '~C05Adds one new page to your Item Box.', 20, ''::bytea);
INSERT INTO distribution_items (distribution_id, item_type, quantity) VALUES ((SELECT id FROM distribution ORDER BY id DESC LIMIT 1), 30, 1);
-- Adds a Distribution that can be accepted up to 20 times that gives one of Item Type 31 (Equipment Box extra page)
INSERT INTO distribution (type, event_name, description, times_acceptable, data) VALUES (1, 'Extra Equipment Storage', '~C05Adds one new page to your Equipment Box.', 20, ''::bytea);
INSERT INTO distribution_items (distribution_id, item_type, quantity) VALUES ((SELECT id FROM distribution ORDER BY id DESC LIMIT 1), 31, 1);
END;

View File

@@ -0,0 +1,45 @@
BEGIN;
INSERT INTO public.shop_items
(shop_type, shop_id, item_id, cost, quantity, min_hr, min_sr, min_gr, store_level, max_quantity, road_floors, road_fatalis)
VALUES
(8,5,1,30,10,0,0,0,0,10,0,0),
(8,5,2,60,10,0,0,0,0,10,0,0),
(8,5,3,60,10,0,0,0,0,10,0,0),
(8,5,4,30,10,0,0,0,0,10,0,0),
(8,5,5,60,10,0,0,0,0,10,0,0),
(8,5,6,80,10,0,0,0,1,10,0,0),
(8,5,7,80,10,0,0,0,1,10,0,0),
(8,5,8,80,10,0,0,0,1,10,0,0),
(8,5,9,100,10,0,0,0,2,10,0,0),
(8,5,10,100,10,0,0,0,2,10,0,0),
(8,5,11,100,10,0,0,0,2,10,0,0),
(8,5,12,100,10,0,0,0,2,10,0,0),
(8,5,13,100,10,0,0,0,2,10,0,0),
(8,5,14,200,10,0,0,0,2,10,0,0),
(8,5,15,500,10,0,0,0,3,10,0,0),
(8,5,16,1000,10,0,0,0,3,10,0,0),
(8,5,20,30,10,0,0,0,0,10,0,0),
(8,5,21,30,10,0,0,0,0,10,0,0),
(8,5,22,60,10,0,0,0,0,10,0,0),
(8,5,23,60,10,0,0,0,0,10,0,0),
(8,5,24,60,10,0,0,0,0,10,0,0),
(8,5,25,80,10,0,0,0,1,10,0,0),
(8,5,26,80,10,0,0,0,1,10,0,0),
(8,5,27,500,10,0,0,1,3,10,0,0),
(8,5,28,60,10,0,0,0,0,10,0,0),
(8,5,29,60,10,299,0,0,0,10,0,0),
(8,5,30,100,10,0,0,1,3,10,0,0),
(8,5,31,80,10,299,0,0,1,10,0,0),
(8,5,32,80,10,299,0,0,1,10,0,0),
(8,5,33,80,10,299,0,0,1,10,0,0),
(8,7,2209,400,1,299,0,0,2,5,0,0),
(8,7,2208,400,1,299,0,0,2,5,0,0),
(8,7,5113,400,1,299,0,0,2,5,0,0),
(8,7,3571,400,1,299,0,0,2,5,0,0),
(8,7,3572,400,1,299,0,0,2,5,0,0),
(8,7,3738,400,1,299,0,0,2,5,0,0),
(8,7,3737,400,1,299,0,0,2,5,0,0),
(8,7,4399,400,1,299,0,0,2,5,0,0);
END;

View File

@@ -0,0 +1,292 @@
BEGIN;
-- Ripped quests
INSERT INTO public.event_quests (max_players, quest_type, quest_id, mark) VALUES
(0,9,40060,0),
(0,9,40079,0),
(0,9,40080,0),
(0,9,40081,0),
(0,9,40133,0),
(0,9,40134,0),
(0,9,40135,0),
(0,9,40136,0),
(0,9,40137,0),
(0,9,40138,0),
(0,9,40142,0),
(0,9,40143,0),
(0,9,40161,0),
(0,9,40162,0),
(4,9,40173,0),
(4,9,40174,0),
(0,9,40201,0),
(0,9,40218,0),
(4,43,40236,1),
(4,28,40241,1),
(0,8,50534,0),
(4,18,50852,1),
(4,18,50940,1),
(4,18,51024,1),
(4,18,51025,1),
(4,18,51026,1),
(4,18,51027,1),
(4,38,51052,9),
(4,38,51053,9),
(4,18,51059,1),
(4,38,51107,9),
(4,24,51125,0),
(1,24,51126,0),
(4,24,51127,0),
(4,24,51128,0),
(4,24,51129,0),
(4,26,53034,1),
(4,18,53140,1),
(4,18,53187,1),
(4,18,53201,1),
(1,18,53253,1),
(4,26,53307,1),
(4,24,53314,0),
(4,24,53315,0),
(4,24,53316,0),
(4,24,53317,0),
(4,24,53318,0),
(4,24,53319,0),
(4,24,53320,0),
(4,24,53321,0),
(4,24,53324,0),
(1,18,53326,2),
(4,31,54244,0),
(0,8,54425,0),
(4,28,54449,1),
(4,28,54593,1),
(4,28,54594,1),
(4,28,54603,1),
(4,28,54604,1),
(4,28,54605,1),
(4,28,54606,1),
(1,28,54608,0),
(1,28,54609,0),
(32,40,54751,0),
(32,40,54752,0),
(32,40,54753,0),
(32,40,54754,0),
(32,40,54755,0),
(32,40,54756,0),
(32,40,54757,0),
(32,40,54758,0),
(32,40,54759,0),
(32,40,54760,0),
(32,40,54761,0),
(4,28,54801,0),
(4,28,55002,1),
(4,28,55195,0),
(4,28,55202,0),
(4,28,55203,0),
(4,28,55204,0),
(0,8,55369,0),
(4,28,55464,1),
(4,43,55513,1),
(4,28,55529,0),
(4,28,55532,0),
(1,28,55536,0),
(1,28,55537,0),
(32,50,55596,0),
(32,50,55597,0),
(32,50,55598,0),
(32,50,55599,0),
(32,50,55601,0),
(32,50,55602,0),
(32,50,55603,0),
(32,50,55604,0),
(32,50,55605,0),
(32,50,55606,0),
(32,50,55607,0),
(4,28,55619,0),
(4,28,55670,1),
(4,39,55679,9),
(4,39,55680,9),
(4,43,55691,1),
(4,43,55692,1),
(4,43,55693,1),
(4,43,55694,1),
(4,43,55695,1),
(4,43,55696,1),
(4,43,55697,1),
(4,43,55698,1),
(1,43,55728,1),
(4,43,55738,1),
(0,8,55767,0),
(0,8,55768,0),
(4,28,55771,1),
(4,39,55772,9),
(8,51,55796,0),
(8,51,55797,0),
(8,51,55798,0),
(8,51,55799,0),
(8,51,55801,0),
(8,51,55802,0),
(8,51,55803,0),
(8,51,55804,0),
(8,51,55805,0),
(8,51,55806,0),
(8,51,55807,0),
(1,28,55808,0),
(0,8,55870,0),
(0,8,55872,0),
(0,8,55879,0),
(0,8,55880,0),
(0,8,55881,0),
(0,8,55882,0),
(4,28,55896,1),
(0,8,55897,0),
(0,8,55899,0),
(0,8,55901,0),
(0,8,55902,0),
(0,8,55903,0),
(0,8,55904,0),
(0,8,55905,0),
(0,8,55906,0),
(0,8,55907,0),
(0,8,55908,0),
(0,8,55909,0),
(0,8,55910,0),
(0,8,55911,0),
(0,8,55912,0),
(4,39,55916,9),
(4,39,55917,9),
(4,39,55918,9),
(4,39,55919,9),
(4,28,55920,0),
(4,39,55921,9),
(4,39,55922,9),
(4,43,55923,1),
(4,43,55924,1),
(4,43,55925,1),
(4,43,55926,1),
(4,43,55929,1),
(4,43,55930,1),
(4,43,55931,1),
(4,43,55932,1),
(4,28,55935,0),
(4,28,55936,0),
(4,28,55937,0),
(4,28,55938,0),
(4,28,55939,0),
(4,28,55948,0),
(4,28,55949,0),
(4,28,55950,0),
(4,28,55951,0),
(1,28,55963,0),
(4,28,55964,1),
(4,28,55967,1),
(4,43,56042,1),
(4,43,56056,1),
(4,43,56058,1),
(4,43,56059,1),
(4,43,56063,1),
(4,43,56064,1),
(4,43,56076,4),
(4,43,56077,4),
(4,43,56078,4),
(4,43,56079,4),
(4,43,56080,4),
(4,43,56125,1),
(4,24,56134,0),
(4,24,56135,0),
(4,24,56138,0),
(4,24,56139,0),
(4,24,56141,0),
(4,24,56142,0),
(4,28,56143,1),
(4,43,56144,1),
(4,43,56145,1),
(0,8,56146,0),
(4,28,56147,1),
(4,24,56148,0),
(1,24,56149,0),
(4,43,56150,1),
(4,43,56151,1),
(4,43,56154,1),
(4,43,56155,1),
(4,43,56156,1),
(4,28,56157,1),
(1,28,56158,1),
(4,28,56159,1),
(4,48,58043,1),
(4,46,58050,0),
(4,46,58051,0),
(4,46,58052,0),
(4,46,58053,0),
(4,46,58054,0),
(4,46,58055,0),
(4,46,58056,0),
(4,46,58057,0),
(4,46,58058,0),
(4,46,58059,0),
(4,46,58060,0),
(4,46,58061,0),
(4,46,58062,0),
(4,46,58063,0),
(4,46,58064,0),
(4,46,58065,0),
(4,46,58066,0),
(4,46,58067,0),
(4,46,58068,0),
(4,46,58069,0),
(4,46,58070,0),
(4,46,58071,0),
(4,46,58072,0),
(4,46,58074,0),
(4,46,58075,0),
(4,46,58076,0),
(4,46,58077,0),
(4,46,58078,0),
(4,47,58079,0),
(4,47,58080,0),
(4,47,58081,0),
(4,47,58082,0),
(4,47,58083,0),
(4,46,58088,0),
(4,46,58089,0),
(4,46,58090,0),
(4,46,58091,0),
(4,46,58096,0),
(4,46,58097,0),
(4,46,58098,0),
(4,46,58099,0),
(4,46,58101,0),
(4,46,58102,1),
(4,46,58103,1),
(4,46,58104,1),
(4,46,58105,1),
(4,46,58106,1),
(4,46,58107,1),
(4,46,58108,1),
(4,46,58109,1),
(4,46,58112,1),
(4,46,58113,1),
(4,46,58114,1),
(4,46,58115,1),
(4,46,58118,0),
(4,46,58119,0),
(4,46,58120,0),
(4,46,58121,0),
(4,46,58122,0),
(4,46,58123,0),
(4,46,58125,1),
(4,46,58126,1),
(4,46,58127,1),
(4,46,58128,1),
(4,13,61050,0),
(4,13,61051,0),
(4,13,61053,0),
(4,13,61055,0),
(2,13,61067,0),
(4,13,61068,0),
(2,13,61070,0),
(4,13,61071,0),
(8,22,62101,0),
(8,16,62104,0),
(8,16,62105,0),
(8,16,62108,0),
(1,18,62910,1);
END;

View File

@@ -0,0 +1,391 @@
BEGIN;
INSERT INTO fpoint_items (item_type, item_id, quantity, fpoints, buyable) VALUES
(7,8895,1,500,true),
(7,8891,1,300,true),
(7,8892,1,300,true),
(7,8893,1,300,true),
(7,8894,1,300,true),
(7,8890,1,10,true),
(7,10354,1,500,true),
(7,11983,1,300,true),
(7,11984,1,300,true),
(7,11985,1,300,true),
(7,11986,1,300,true),
(7,12524,1,500,true),
(7,12470,1,300,true),
(7,12471,1,300,true),
(7,12472,1,300,true),
(7,12473,1,300,true),
(7,2158,2,1,true),
(7,14548,1,500,true),
(7,9509,1,1,true),
(7,9510,1,1,true),
(7,9511,1,1,true),
(7,9512,1,1,true),
(7,9513,1,1,true),
(7,9514,1,1,true),
(7,9515,1,1,true),
(7,10753,1,1,true),
(7,10754,1,1,true),
(7,10755,1,1,true),
(7,10756,1,1,true),
(7,10757,1,1,true),
(7,10758,1,1,true),
(7,10759,1,1,true),
(7,11296,1,1,true),
(7,11297,1,1,true),
(7,11298,1,1,true),
(7,11299,1,1,true),
(7,11300,1,1,true),
(7,12386,1,1,true),
(7,12387,1,1,true),
(7,12388,1,1,true),
(7,12389,1,1,true),
(7,12390,1,1,true),
(7,13034,1,1,true),
(7,13035,1,1,true),
(7,13036,1,1,true),
(7,13037,1,1,true),
(7,13038,1,1,true),
(7,14179,1,1,true),
(7,14180,1,1,true),
(7,14181,1,1,true),
(7,14182,1,1,true),
(7,14183,1,1,true),
(7,13422,1,1,true),
(7,13423,1,1,true),
(7,13424,1,1,true),
(7,13425,1,1,true),
(7,13426,1,1,true),
(7,13427,1,1,true),
(7,9796,1,3,false),
(7,9700,1,3,false),
(7,10380,1,3,false),
(7,10810,1,3,false),
(7,10811,1,3,false),
(7,11436,1,3,false),
(7,9509,1,1,false),
(7,9510,1,1,false),
(7,9511,1,1,false),
(7,9512,1,1,false),
(7,9513,1,1,false),
(7,9514,1,1,false),
(7,9515,1,1,false),
(7,10753,1,1,false),
(7,10754,1,1,false),
(7,10755,1,1,false),
(7,10756,1,1,false),
(7,10757,1,1,false),
(7,10758,1,1,false),
(7,10759,1,1,false),
(7,11296,1,1,false),
(7,11297,1,1,false),
(7,11298,1,1,false),
(7,11299,1,1,false),
(7,11300,1,1,false),
(7,12509,1,3,false),
(7,12386,1,1,false),
(7,12387,1,1,false),
(7,12388,1,1,false),
(7,12389,1,1,false),
(7,12390,1,1,false),
(7,12872,1,3,false),
(7,12873,1,3,false),
(7,12840,1,1,false),
(7,12841,1,1,false),
(7,12874,1,1,false),
(7,12875,1,1,false),
(7,13191,1,3,false),
(7,13177,1,3,false),
(7,13326,1,3,false),
(7,13034,1,1,false),
(7,13035,1,1,false),
(7,13036,1,1,false),
(7,13037,1,1,false),
(7,13038,1,1,false),
(7,13178,1,3,false),
(7,13453,1,3,false),
(7,13449,1,3,false),
(7,13450,1,3,false),
(7,13404,1,3,false),
(7,13422,1,1,false),
(7,13423,1,1,false),
(7,13424,1,1,false),
(7,13425,1,1,false),
(7,13426,1,1,false),
(7,13427,1,1,false),
(7,13791,1,3,false),
(7,14006,1,3,false),
(7,14031,1,3,false),
(7,14032,1,3,false),
(7,13960,1,3,false),
(7,14029,1,3,false),
(7,13956,1,1,false),
(7,13958,1,1,false),
(7,13957,1,1,false),
(7,13959,1,1,false),
(7,13790,1,3,false),
(7,14005,1,3,false),
(7,14010,1,3,false),
(7,14009,1,3,false),
(7,14008,1,3,false),
(7,13965,1,3,false),
(7,14028,1,3,false),
(7,13963,1,3,false),
(7,14026,1,3,false),
(7,13964,1,3,false),
(7,14027,1,3,false),
(7,14069,1,3,false),
(7,14124,1,3,false),
(7,14065,1,1,false),
(7,14066,1,1,false),
(7,14067,1,1,false),
(7,14068,1,1,false),
(7,13962,1,3,false),
(7,14125,1,3,false),
(7,14089,1,3,false),
(7,14090,1,3,false),
(7,14091,1,3,false),
(7,14092,1,3,false),
(7,14194,1,3,false),
(7,14191,1,3,false),
(7,14198,1,3,false),
(7,14197,1,3,false),
(7,14179,1,1,false),
(7,14180,1,1,false),
(7,14181,1,1,false),
(7,14182,1,1,false),
(7,14183,1,1,false),
(7,14196,1,3,false),
(7,14195,1,3,false),
(7,14193,1,3,false),
(7,14192,1,3,false),
(7,14407,1,3,false),
(7,14414,1,3,false),
(7,14406,1,3,false),
(7,14413,1,3,false),
(7,14416,1,3,false),
(7,14549,1,3,false),
(7,14550,1,3,false),
(7,14502,1,3,false),
(7,14507,1,3,false),
(7,14501,1,3,false),
(7,14506,1,3,false),
(7,14500,1,3,false),
(7,14505,1,3,false),
(7,14498,1,3,false),
(7,14659,1,3,false),
(7,14660,1,3,false),
(7,14657,1,1,false),
(7,14658,1,1,false),
(7,11420,1,3,false),
(7,14704,1,3,false),
(7,11288,1,1,false),
(7,11289,1,1,false),
(7,11290,1,1,false),
(7,11291,1,1,false),
(7,10750,1,3,false),
(7,14705,1,3,false),
(7,10633,1,1,false),
(7,10634,1,1,false),
(7,10635,1,1,false),
(7,10636,1,1,false),
(7,14662,1,3,false),
(7,14663,1,3,false),
(7,14665,1,3,false),
(7,14666,1,3,false),
(7,14667,1,3,false),
(7,14668,1,3,false),
(7,14669,1,3,false),
(7,14670,1,3,false),
(7,14671,1,3,false),
(7,14672,1,3,false),
(7,14673,1,3,false),
(7,14674,1,3,false),
(7,14675,1,3,false),
(7,14676,1,3,false),
(7,14677,1,3,false),
(7,14678,1,3,false),
(7,14679,1,3,false),
(7,14680,1,3,false),
(7,14681,1,3,false),
(7,14682,1,3,false),
(7,14683,1,3,false),
(7,14684,1,3,false),
(7,14685,1,3,false),
(7,14686,1,3,false),
(7,14687,1,3,false),
(7,14688,1,3,false),
(7,14689,1,3,false),
(7,14690,1,3,false),
(7,14691,1,3,false),
(7,14692,1,3,false),
(7,14693,1,3,false),
(7,14694,1,3,false),
(7,14695,1,3,false),
(7,14696,1,3,false),
(7,14697,1,3,false),
(7,14698,1,3,false),
(7,14699,1,3,false),
(7,14700,1,3,false),
(7,14314,1,3,false),
(7,14503,1,3,false),
(7,14510,1,3,false),
(7,14904,1,3,false),
(7,14906,1,3,false),
(7,14910,1,1,false),
(7,14912,1,1,false),
(7,14905,1,3,false),
(7,14907,1,3,false),
(7,14911,1,1,false),
(7,14909,1,1,false),
(7,14855,1,3,false),
(7,14894,1,3,false),
(7,14913,1,3,false),
(7,14914,1,3,false),
(7,14891,1,3,false),
(7,14895,1,3,false),
(7,15027,1,3,false),
(7,15028,1,3,false),
(7,15026,1,1,false),
(7,15025,1,1,false),
(7,15024,1,1,false),
(7,15023,1,1,false),
(7,15064,1,3,false),
(7,15065,1,3,false),
(7,15030,1,3,false),
(7,15031,1,3,false),
(7,15062,1,3,false),
(7,15063,1,3,false),
(7,15066,1,3,false),
(7,15067,1,3,false),
(7,15061,1,3,false),
(7,15060,1,3,false),
(7,1227,1,2,false),
(7,13176,1,2,false),
(7,4360,1,2,false),
(7,4358,1,1,false),
(7,15118,1,3,false),
(7,15119,1,3,false),
(7,15113,1,3,false),
(7,15114,1,3,false),
(7,15115,1,3,false),
(7,15116,1,3,false),
(7,15220,1,3,false),
(7,15221,1,3,false),
(7,14126,1,3,false),
(7,15222,1,3,false),
(7,15223,1,3,false),
(7,15224,1,3,false),
(7,15225,1,3,false),
(7,15524,1,3,false),
(7,15525,1,3,false),
(7,15507,1,3,false),
(7,15508,1,3,false),
(7,15285,1,3,false),
(7,15286,1,3,false),
(7,15281,1,1,false),
(7,15282,1,1,false),
(7,15283,1,1,false),
(7,15284,1,1,false),
(7,15776,1,3,false),
(7,15777,1,3,false),
(7,15774,1,3,false),
(7,15775,1,3,false),
(7,15823,1,3,false),
(7,15824,1,3,false),
(7,15343,1,3,false),
(7,15342,1,3,false),
(7,15341,1,3,false),
(7,15340,1,3,false),
(7,15339,1,3,false),
(7,15338,1,3,false),
(7,15337,1,3,false),
(7,15336,1,3,false),
(7,15335,1,3,false),
(7,15334,1,3,false),
(7,15333,1,3,false),
(7,15332,1,3,false),
(7,15331,1,3,false),
(7,15330,1,3,false),
(7,15329,1,3,false),
(7,15328,1,3,false),
(7,15327,1,3,false),
(7,15326,1,3,false),
(7,15325,1,3,false),
(7,15324,1,3,false),
(7,15323,1,3,false),
(7,15322,1,3,false),
(7,15321,1,3,false),
(7,15314,1,3,false),
(7,15312,1,3,false),
(7,15311,1,3,false),
(7,15306,1,3,false),
(7,15307,1,3,false),
(7,15308,1,3,false),
(7,15309,1,3,false),
(7,15310,1,3,false),
(7,15305,1,3,false),
(7,15304,1,3,false),
(7,15303,1,3,false),
(7,15302,1,3,false),
(7,15301,1,3,false),
(7,15300,1,3,false),
(7,15299,1,3,false),
(7,15298,1,3,false),
(7,15297,1,3,false),
(7,15296,1,3,false),
(7,15295,1,3,false),
(7,15293,1,3,false),
(7,15294,1,3,false),
(7,15292,1,3,false),
(7,15291,1,3,false),
(7,15290,1,3,false),
(7,15289,1,3,false),
(7,15315,1,3,false),
(7,15316,1,3,false),
(7,15317,1,3,false),
(7,15318,1,3,false),
(7,15319,1,3,false),
(7,15320,1,3,false),
(7,15819,1,3,false),
(7,15820,1,3,false),
(7,15821,1,3,false),
(7,15822,1,3,false),
(7,16450,1,3,false),
(7,16451,1,3,false),
(7,16459,1,1,false),
(7,16460,1,1,false),
(7,16461,1,1,false),
(7,16462,1,1,false),
(7,16463,1,1,false),
(7,16464,1,1,false),
(7,16465,1,1,false),
(7,16466,1,1,false),
(7,16467,1,1,false),
(7,16468,1,1,false),
(7,16469,1,1,false),
(7,16470,1,1,false),
(7,16471,1,1,false),
(7,16472,1,1,false),
(7,16454,1,3,false),
(7,16455,1,3,false),
(7,16442,1,3,false),
(7,16443,1,3,false),
(7,16342,1,3,false),
(7,16343,1,3,false),
(7,16444,1,3,false),
(7,16445,1,3,false),
(7,16344,1,3,false),
(7,16345,1,3,false),
(7,16352,1,3,false),
(7,16353,1,3,false),
(7,16446,1,3,false),
(7,16447,1,3,false),
(7,16448,1,3,false),
(7,16449,1,3,false),
(7,16348,1,3,false),
(7,16349,1,3,false);
END;

View File

@@ -0,0 +1,260 @@
BEGIN;
-- Ripped prizes
INSERT INTO public.festa_prizes
(type, tier, souls_req, item_id, num_item)
VALUES
('personal', 1, 1, 9647, 7),
('personal', 2, 1, 9647, 7),
('personal', 3, 1, 9647, 7),
('personal', 1, 200, 11284, 4),
('personal', 2, 200, 11284, 4),
('personal', 3, 200, 11284, 4),
('personal', 1, 400, 11381, 3),
('personal', 2, 400, 11381, 3),
('personal', 3, 400, 11381, 3),
('personal', 1, 600, 11284, 8),
('personal', 2, 600, 11284, 8),
('personal', 3, 600, 11284, 8),
('personal', 1, 800, 11384, 3),
('personal', 2, 800, 11384, 3),
('personal', 3, 800, 11384, 3),
('personal', 1, 1000, 11284, 12),
('personal', 2, 1000, 11284, 12),
('personal', 3, 1000, 11284, 12),
('personal', 1, 1200, 11381, 5),
('personal', 2, 1200, 11381, 5),
('personal', 3, 1200, 11381, 5),
('personal', 1, 1400, 11284, 16),
('personal', 2, 1400, 11284, 16),
('personal', 3, 1400, 11284, 16),
('personal', 1, 1700, 11384, 5),
('personal', 2, 1700, 11384, 5),
('personal', 3, 1700, 11384, 5),
('personal', 1, 2000, 11284, 16),
('personal', 2, 2000, 11284, 16),
('personal', 3, 2000, 11284, 16),
('personal', 1, 2500, 11382, 4),
('personal', 2, 2500, 11382, 4),
('personal', 3, 2500, 11382, 4),
('personal', 1, 3000, 11284, 24),
('personal', 2, 3000, 11284, 24),
('personal', 3, 3000, 11284, 24),
('personal', 1, 4000, 11385, 4),
('personal', 2, 4000, 11385, 4),
('personal', 3, 4000, 11385, 4),
('personal', 1, 5000, 11381, 11),
('personal', 2, 5000, 11381, 11),
('personal', 3, 5000, 11381, 11),
('personal', 1, 6000, 5177, 5),
('personal', 2, 6000, 5177, 5),
('personal', 3, 6000, 5177, 5),
('personal', 1, 7000, 11384, 11),
('personal', 2, 7000, 11384, 11),
('personal', 3, 7000, 11384, 11),
('personal', 1, 10000, 11382, 8),
('personal', 2, 10000, 11382, 8),
('personal', 3, 10000, 11382, 8),
('personal', 1, 15000, 11385, 4),
('personal', 2, 15000, 11385, 4),
('personal', 3, 15000, 11385, 4),
('personal', 1, 20000, 11381, 13),
('personal', 2, 20000, 11381, 13),
('personal', 3, 20000, 11381, 13),
('personal', 1, 25000, 11385, 4),
('personal', 2, 25000, 11385, 4),
('personal', 3, 25000, 11385, 4),
('personal', 1, 30000, 11383, 1),
('personal', 2, 30000, 11383, 1),
('personal', 3, 30000, 11383, 1);
INSERT INTO public.festa_prizes
(type, tier, souls_req, item_id, num_item)
VALUES
('guild', 1, 100, 7468, 5),
('guild', 2, 100, 7468, 5),
('guild', 3, 100, 7465, 5),
('guild', 1, 300, 7469, 5),
('guild', 2, 300, 7469, 5),
('guild', 3, 300, 7466, 5),
('guild', 1, 700, 7470, 5),
('guild', 2, 700, 7470, 5),
('guild', 3, 700, 7467, 5),
('guild', 1, 1500, 13405, 14),
('guild', 1, 1500, 1520, 3),
('guild', 2, 1500, 13405, 14),
('guild', 2, 1500, 1520, 3),
('guild', 3, 1500, 7011, 3),
('guild', 3, 1500, 13405, 14),
('guild', 1, 3000, 10201, 10),
('guild', 2, 3000, 10201, 10),
('guild', 3, 3000, 10201, 10),
('guild', 1, 6000, 13895, 14),
('guild', 1, 6000, 1520, 6),
('guild', 2, 6000, 13895, 14),
('guild', 2, 6000, 1520, 6),
('guild', 3, 6000, 13895, 14),
('guild', 3, 6000, 7011, 4),
('guild', 1, 12000, 13406, 14),
('guild', 1, 12000, 1520, 9),
('guild', 2, 12000, 13406, 14),
('guild', 2, 12000, 1520, 9),
('guild', 3, 12000, 13406, 14),
('guild', 3, 12000, 7011, 5),
('guild', 1, 25000, 10207, 10),
('guild', 2, 25000, 10207, 10),
('guild', 3, 25000, 10207, 10),
('guild', 1, 50000, 1520, 12),
('guild', 1, 50000, 13896, 14),
('guild', 2, 50000, 1520, 12),
('guild', 2, 50000, 13896, 14),
('guild', 3, 50000, 7011, 6),
('guild', 3, 50000, 13896, 14),
('guild', 1, 100000, 10201, 10),
('guild', 2, 100000, 10201, 10),
('guild', 3, 100000, 10201, 10),
('guild', 1, 200000, 13406, 16),
('guild', 2, 200000, 13406, 16),
('guild', 3, 200000, 13406, 16),
('guild', 1, 300000, 13896, 16),
('guild', 2, 300000, 13896, 16),
('guild', 3, 300000, 13896, 16),
('guild', 1, 400000, 10207, 10),
('guild', 2, 400000, 10207, 10),
('guild', 3, 400000, 10207, 10),
('guild', 1, 500000, 13407, 6),
('guild', 1, 500000, 13897, 6),
('guild', 2, 500000, 13407, 6),
('guild', 2, 500000, 13897, 6),
('guild', 3, 500000, 13407, 6),
('guild', 3, 500000, 13897, 6);
-- Ripped trials
INSERT INTO public.festa_trials
(objective, goal_id, times_req, locale_req, reward)
VALUES
(1,27,1,0,1),
(5,53034,0,0,400),
(5,22042,0,0,89),
(5,23397,0,0,89),
(1,28,1,0,1),
(1,68,1,0,1),
(1,6,1,0,2),
(1,38,1,0,2),
(1,20,1,0,3),
(1,39,1,0,4),
(1,48,1,0,4),
(1,67,1,0,4),
(1,93,1,0,4),
(1,22,1,0,5),
(1,52,1,0,5),
(1,101,1,0,5),
(1,1,1,0,5),
(1,37,1,0,5),
(1,15,1,0,5),
(1,45,1,0,5),
(1,74,1,0,5),
(1,78,1,0,5),
(1,103,1,0,5),
(1,51,1,0,6),
(1,17,1,0,6),
(1,21,1,0,6),
(1,92,1,0,6),
(1,47,1,0,7),
(1,46,1,0,7),
(1,26,1,0,7),
(1,14,1,0,7),
(1,11,1,0,7),
(1,44,1,0,8),
(1,43,1,0,8),
(1,49,1,0,8),
(1,40,1,0,8),
(1,76,1,0,8),
(1,89,1,0,8),
(1,94,1,0,8),
(1,96,1,0,8),
(1,75,1,0,8),
(1,91,1,0,8),
(1,53,1,0,9),
(1,80,1,0,9),
(1,42,1,0,9),
(1,79,1,0,9),
(1,81,1,0,10),
(1,41,1,0,10),
(1,82,1,0,10),
(1,90,1,0,10),
(1,149,1,0,10),
(1,85,1,0,11),
(1,95,1,0,11),
(1,121,1,0,11),
(1,142,1,0,11),
(1,141,1,0,11),
(1,146,1,0,12),
(1,147,1,0,12),
(1,148,1,0,12),
(1,151,1,0,12),
(1,152,1,0,12),
(1,159,1,0,12),
(1,153,1,0,12),
(1,162,1,0,12),
(1,111,1,0,13),
(1,110,1,0,13),
(1,112,1,0,13),
(1,109,1,0,14),
(1,169,1,0,15),
(2,33,1,0,6),
(2,104,1,0,8),
(2,119,1,0,8),
(2,120,1,0,8),
(2,54,1,0,8),
(2,59,1,0,8),
(2,64,1,0,8),
(2,65,1,0,8),
(2,99,1,0,9),
(2,83,1,0,9),
(2,84,1,0,10),
(2,77,1,0,10),
(2,106,1,0,10),
(2,55,1,0,10),
(2,58,1,0,10),
(2,7,1,0,10),
(2,50,1,0,11),
(2,131,1,0,11),
(2,129,1,0,11),
(2,140,1,0,11),
(2,122,1,0,11),
(2,126,1,0,11),
(2,127,1,0,11),
(2,128,1,0,11),
(2,130,1,0,11),
(2,139,1,0,11),
(2,144,1,0,11),
(2,150,1,0,11),
(2,158,1,0,11),
(2,164,1,0,15),
(2,165,1,0,15),
(2,2,1,7,15),
(2,36,1,0,15),
(2,71,1,0,15),
(2,108,1,0,15),
(2,116,1,0,15),
(2,107,1,0,15),
(2,154,1,0,17),
(2,166,1,0,17),
(2,170,1,0,18),
(3,31,1,0,1),
(3,8,1,0,3),
(3,123,1,0,8),
(3,105,1,0,9),
(3,125,1,0,11),
(3,115,1,0,12),
(3,114,1,0,12),
(3,161,1,0,12),
(4,670,1,0,1),
(4,671,1,0,1),
(4,672,1,0,1),
(4,675,1,0,1),
(4,673,1,0,1),
(4,674,1,0,1);
END;

View File

@@ -0,0 +1,102 @@
BEGIN;
-- Start Normal Demo
INSERT INTO gacha_shop (min_gr, min_hr, name, url_banner, url_feature, url_thumbnail, wide, recommended, gacha_type, hidden)
VALUES (0, 0, 'Normal Demo',
'http://img4.imagetitan.com/img4/QeRWNAviFD8UoTx/26/26_template_innerbanner.png',
'http://img4.imagetitan.com/img4/QeRWNAviFD8UoTx/26/26_template_feature.png',
'http://img4.imagetitan.com/img4/small/26/26_template_outerbanner.png',
false, false, 0, false);
-- Create two different 'rolls', the first rolls once for 1z, the second rolls eleven times for 10z
INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points)
VALUES
((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 0, 10, 1, 0, 0, 0, 1, 0, 0),
((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 1, 10, 10, 0, 0, 0, 11, 0, 0);
-- Creates a prize of 1z with a weighted chance of 100
INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points)
VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 100, 0, 0, 0, 0);
INSERT INTO gacha_items (entry_id, item_type, item_id, quantity)
VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 1, 0);
-- Creates a prize of 2z with a weighted chance of 70
INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points)
VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 70, 1, 0, 0, 0);
INSERT INTO gacha_items (entry_id, item_type, item_id, quantity)
VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 2, 0);
-- Creates a prize of 3z with a weighted chance of 10
INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points)
VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 10, 2, 0, 0, 0);
INSERT INTO gacha_items (entry_id, item_type, item_id, quantity)
VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 3, 0);
-- End Normal Demo
-- Start Step-Up Demo
INSERT INTO gacha_shop (min_gr, min_hr, name, url_banner, url_feature, url_thumbnail, wide, recommended, gacha_type, hidden)
VALUES (0, 0, 'Step-Up Demo', '', '', '', false, false, 1, false);
-- Create two 'steps', the first costs 1z, the second costs 2z
-- The first step has zero rolls so it will only give the prizes directly linked to the entry ID, being 1z
INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points)
VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 0, 10, 1, 0, 0, 0, 0, 0, 0);
INSERT INTO gacha_items (entry_id, item_type, item_id, quantity)
VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 1, 0);
-- The second step has one roll on the random prize list as will as the direct prize, being 3z
INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points)
VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 1, 10, 2, 0, 0, 0, 1, 0, 0);
INSERT INTO gacha_items (entry_id, item_type, item_id, quantity)
VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 3, 0);
-- Set up two random prizes, the first gives 1z, the second gives 2z
INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points)
VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 100, 0, 0, 0, 0);
INSERT INTO gacha_items (entry_id, item_type, item_id, quantity)
VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 1, 0);
INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points)
VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 90, 1, 0, 0, 0);
INSERT INTO gacha_items (entry_id, item_type, item_id, quantity)
VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 2, 0);
-- End Step-Up Demo
-- Start Box Demo
INSERT INTO gacha_shop (min_gr, min_hr, name, url_banner, url_feature, url_thumbnail, wide, recommended, gacha_type, hidden)
VALUES (0, 0, 'Box Demo', '', '', '', false, false, 4, false);
-- Create two different 'rolls', the first rolls once for 1z, the second rolls twice for 2z
INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points)
VALUES
((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 0, 10, 1, 0, 0, 0, 1, 0, 0),
((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 1, 10, 2, 0, 0, 0, 2, 0, 0);
-- Create five different 'Box' items, weight is always 0 for these
INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points)
VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO gacha_items (entry_id, item_type, item_id, quantity)
VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 1, 0);
INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points)
VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO gacha_items (entry_id, item_type, item_id, quantity)
VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 1, 0);
INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points)
VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO gacha_items (entry_id, item_type, item_id, quantity)
VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 1, 0);
INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points)
VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO gacha_items (entry_id, item_type, item_id, quantity)
VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 2, 0);
INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points)
VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO gacha_items (entry_id, item_type, item_id, quantity)
VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 3, 0);
-- End Box Demo
END;

View File

@@ -0,0 +1,15 @@
BEGIN;
TRUNCATE public.cafebonus;
INSERT INTO public.cafebonus (time_req, item_type, item_id, quantity)
VALUES
(1800, 17, 0, 50),
(3600, 17, 0, 100),
(7200, 17, 0, 200),
(10800, 17, 0, 300),
(18000, 17, 0, 350),
(28800, 17, 0, 500),
(43200, 17, 0, 500);
END;

View File

@@ -0,0 +1,48 @@
BEGIN;
INSERT INTO public.shop_items
(shop_type, shop_id, item_id, cost, quantity, min_hr, min_sr, min_gr, store_level, max_quantity, road_floors, road_fatalis)
VALUES
(5,5,16516,100,1,0,0,1,0,0,0,0),
(5,5,16517,100,1,0,0,1,0,0,0,0),
(6,5,9958,3,3,1,0,0,0,0,0,0),
(6,5,1897,3,1,1,0,0,0,0,0,0),
(6,5,8889,3,1,0,0,1,0,0,0,0),
(6,5,6176,3,6,1,0,0,0,0,0,0),
(6,5,1472,3,10,1,0,0,0,0,0,0),
(6,5,7280,3,3,0,0,1,0,0,0,0),
(6,5,8027,3,30,1,0,0,0,0,0,0),
(6,5,8028,3,30,1,0,0,0,0,0,0),
(6,5,8029,3,30,1,0,0,0,0,0,0),
(6,5,8026,3,30,1,0,0,0,0,0,0),
(6,5,8030,3,30,1,0,0,0,0,0,0),
(6,5,4353,3,30,1,0,0,0,0,0,0),
(6,5,4354,3,30,1,0,0,0,0,0,0),
(6,5,4355,3,30,1,0,0,0,0,0,0),
(6,5,4356,3,30,1,0,0,0,0,0,0),
(6,5,4357,3,30,1,0,0,0,0,0,0),
(6,5,4745,3,30,1,0,0,0,0,0,0),
(6,5,4746,3,30,1,0,0,0,0,0,0),
(6,5,4747,3,30,1,0,0,0,0,0,0),
(6,5,4748,3,30,1,0,0,0,0,0,0),
(6,5,4749,3,30,1,0,0,0,0,0,0),
(6,5,5122,3,30,1,0,0,0,0,0,0),
(6,5,5123,3,30,1,0,0,0,0,0,0),
(6,5,5124,3,30,1,0,0,0,0,0,0),
(6,5,5125,3,30,1,0,0,0,0,0,0),
(6,5,5126,3,30,1,0,0,0,0,0,0),
(6,5,5795,3,30,1,0,0,0,0,0,0),
(6,5,5796,3,30,1,0,0,0,0,0,0),
(6,5,5797,3,30,1,0,0,0,0,0,0),
(6,5,5798,3,30,1,0,0,0,0,0,0),
(6,5,5799,3,30,1,0,0,0,0,0,0),
(6,5,6168,3,30,1,0,0,0,0,0,0),
(6,5,6169,3,30,1,0,0,0,0,0,0),
(6,5,6170,3,30,1,0,0,0,0,0,0),
(6,5,6171,3,30,1,0,0,0,0,0,0),
(6,5,6172,3,30,1,0,0,0,0,0,0),
(7,0,13190,10,1,0,0,0,0,0,0,0),
(7,0,1662,10,1,0,0,0,0,0,0,0),
(7,0,10179,100,1,0,0,0,0,0,0,0);
END;

View File

@@ -0,0 +1,868 @@
BEGIN;
INSERT INTO public.shop_items
(shop_type, shop_id, item_id, cost, quantity, min_hr, min_sr, min_gr, store_level, max_quantity, road_floors, road_fatalis)
VALUES
(10,4,11664,20000,1,0,0,1,1,0,0,0),
(10,4,11665,20000,1,0,0,1,1,0,0,0),
(10,4,11666,20000,1,0,0,1,1,0,0,0),
(10,4,11667,20000,1,0,0,1,1,0,0,0),
(10,4,11668,20000,1,0,0,1,1,0,0,0),
(10,4,11669,20000,1,0,0,1,1,0,0,0),
(10,4,11670,20000,1,0,0,1,1,0,0,0),
(10,4,11671,20000,1,0,0,1,1,0,0,0),
(10,4,11672,20000,1,0,0,1,1,0,0,0),
(10,4,11673,20000,1,0,0,1,1,0,0,0),
(10,4,11674,20000,1,0,0,1,1,0,0,0),
(10,4,11675,20000,1,0,0,1,1,0,0,0),
(10,4,11676,20000,1,0,0,1,1,0,0,0),
(10,4,11677,20000,1,0,0,1,1,0,0,0),
(10,4,11678,20000,1,0,0,1,1,0,0,0),
(10,4,11679,20000,1,0,0,1,1,0,0,0),
(10,4,11680,20000,1,0,0,1,1,0,0,0),
(10,4,11681,20000,1,0,0,1,1,0,0,0),
(10,4,11682,20000,1,0,0,1,1,0,0,0),
(10,4,11683,20000,1,0,0,1,1,0,0,0),
(10,4,11684,20000,1,0,0,1,1,0,0,0),
(10,4,11685,20000,1,0,0,1,1,0,0,0),
(10,4,11686,20000,1,0,0,1,1,0,0,0),
(10,4,11687,20000,1,0,0,1,1,0,0,0),
(10,4,11688,20000,1,0,0,1,1,0,0,0),
(10,4,11689,20000,1,0,0,1,1,0,0,0),
(10,4,11690,20000,1,0,0,1,1,0,0,0),
(10,4,11691,20000,1,0,0,1,1,0,0,0),
(10,4,11692,20000,1,0,0,1,1,0,0,0),
(10,4,11693,20000,1,0,0,1,1,0,0,0),
(10,4,11694,20000,1,0,0,1,1,0,0,0),
(10,4,11695,20000,1,0,0,1,1,0,0,0),
(10,4,11696,20000,1,0,0,1,1,0,0,0),
(10,4,11697,20000,1,0,0,1,1,0,0,0),
(10,4,12893,20000,1,0,0,1,1,0,0,0),
(10,4,12894,20000,1,0,0,1,1,0,0,0),
(10,4,12895,20000,1,0,0,1,1,0,0,0),
(10,4,12896,20000,1,0,0,1,1,0,0,0),
(10,4,12897,20000,1,0,0,1,1,0,0,0),
(10,4,12898,20000,1,0,0,1,1,0,0,0),
(10,4,12899,20000,1,0,0,1,1,0,0,0),
(10,4,14337,20000,1,0,0,1,1,0,0,0),
(10,4,14338,20000,1,0,0,1,1,0,0,0),
(10,4,14339,20000,1,0,0,1,1,0,0,0),
(10,4,14340,20000,1,0,0,1,1,0,0,0),
(10,4,14341,20000,1,0,0,1,1,0,0,0),
(10,4,14342,20000,1,0,0,1,1,0,0,0),
(10,4,14343,20000,1,0,0,1,1,0,0,0),
(10,4,14344,20000,1,0,0,1,1,0,0,0),
(10,4,14345,20000,1,0,0,1,1,0,0,0),
(10,4,9254,10000,1,0,0,1,1,0,0,0),
(10,4,9255,10000,1,0,0,1,1,0,0,0),
(10,4,9256,10000,1,0,0,1,1,0,0,0),
(10,4,9257,10000,1,0,0,1,1,0,0,0),
(10,4,9258,10000,1,0,0,1,1,0,0,0),
(10,4,9259,10000,1,0,0,1,1,0,0,0),
(10,4,9260,10000,1,0,0,1,1,0,0,0),
(10,4,9261,10000,1,0,0,1,1,0,0,0),
(10,4,9262,10000,1,0,0,1,1,0,0,0),
(10,4,9263,10000,1,0,0,1,1,0,0,0),
(10,4,9264,10000,1,0,0,1,1,0,0,0),
(10,4,9265,10000,1,0,0,1,1,0,0,0),
(10,4,9266,10000,1,0,0,1,1,0,0,0),
(10,4,9267,10000,1,0,0,1,1,0,0,0),
(10,4,9268,10000,1,0,0,1,1,0,0,0),
(10,4,9269,10000,1,0,0,1,1,0,0,0),
(10,4,9270,10000,1,0,0,1,1,0,0,0),
(10,4,9271,10000,1,0,0,1,1,0,0,0),
(10,4,9272,10000,1,0,0,1,1,0,0,0),
(10,4,9273,10000,1,0,0,1,1,0,0,0),
(10,4,9274,10000,1,0,0,1,1,0,0,0),
(10,4,9275,10000,1,0,0,1,1,0,0,0),
(10,4,9276,10000,1,0,0,1,1,0,0,0),
(10,4,9277,10000,1,0,0,1,1,0,0,0),
(10,4,9278,10000,1,0,0,1,1,0,0,0),
(10,4,9279,10000,1,0,0,1,1,0,0,0),
(10,4,9280,10000,1,0,0,1,1,0,0,0),
(10,4,9281,10000,1,0,0,1,1,0,0,0),
(10,4,9282,10000,1,0,0,1,1,0,0,0),
(10,4,9283,10000,1,0,0,1,1,0,0,0),
(10,4,9284,10000,1,0,0,1,1,0,0,0),
(10,4,9285,10000,1,0,0,1,1,0,0,0),
(10,4,9286,10000,1,0,0,1,1,0,0,0),
(10,4,9287,10000,1,0,0,1,1,0,0,0),
(10,4,9288,10000,1,0,0,1,1,0,0,0),
(10,4,9289,10000,1,0,0,1,1,0,0,0),
(10,4,9290,10000,1,0,0,1,1,0,0,0),
(10,4,9291,10000,1,0,0,1,1,0,0,0),
(10,4,9292,10000,1,0,0,1,1,0,0,0),
(10,4,9293,10000,1,0,0,1,1,0,0,0),
(10,4,9294,10000,1,0,0,1,1,0,0,0),
(10,4,9295,10000,1,0,0,1,1,0,0,0),
(10,4,9296,10000,1,0,0,1,1,0,0,0),
(10,4,9297,10000,1,0,0,1,1,0,0,0),
(10,4,9298,10000,1,0,0,1,1,0,0,0),
(10,4,9299,10000,1,0,0,1,1,0,0,0),
(10,4,9300,10000,1,0,0,1,1,0,0,0),
(10,4,9301,10000,1,0,0,1,1,0,0,0),
(10,4,13196,10000,1,0,0,1,1,0,0,0),
(10,4,13197,10000,1,0,0,1,1,0,0,0),
(10,4,13198,10000,1,0,0,1,1,0,0,0),
(10,4,13199,10000,1,0,0,1,1,0,0,0),
(10,4,15542,10000,1,0,0,1,1,0,0,0),
(10,4,15543,10000,1,0,0,1,1,0,0,0),
(10,4,15544,10000,1,0,0,1,1,0,0,0),
(10,4,15545,10000,1,0,0,1,1,0,0,0),
(10,4,13640,20000,1,0,0,1,1,0,0,0),
(10,4,13641,20000,1,0,0,1,1,0,0,0),
(10,4,13642,20000,1,0,0,1,1,0,0,0),
(10,4,13643,20000,1,0,0,1,1,0,0,0),
(10,4,13644,20000,1,0,0,1,1,0,0,0),
(10,4,13645,20000,1,0,0,1,1,0,0,0),
(10,4,13646,20000,1,0,0,1,1,0,0,0),
(10,4,13647,20000,1,0,0,1,1,0,0,0),
(10,4,13648,20000,1,0,0,1,1,0,0,0),
(10,4,13649,20000,1,0,0,1,1,0,0,0),
(10,4,13650,20000,1,0,0,1,1,0,0,0),
(10,4,13651,20000,1,0,0,1,1,0,0,0),
(10,4,13652,20000,1,0,0,1,1,0,0,0),
(10,4,13653,20000,1,0,0,1,1,0,0,0),
(10,4,13654,20000,1,0,0,1,1,0,0,0),
(10,4,13655,20000,1,0,0,1,1,0,0,0),
(10,4,13656,20000,1,0,0,1,1,0,0,0),
(10,4,13657,20000,1,0,0,1,1,0,0,0),
(10,4,13658,20000,1,0,0,1,1,0,0,0),
(10,4,13659,20000,1,0,0,1,1,0,0,0),
(10,4,13660,20000,1,0,0,1,1,0,0,0),
(10,4,13661,20000,1,0,0,1,1,0,0,0),
(10,4,13662,20000,1,0,0,1,1,0,0,0),
(10,4,13663,20000,1,0,0,1,1,0,0,0),
(10,4,13664,20000,1,0,0,1,1,0,0,0),
(10,4,13665,20000,1,0,0,1,1,0,0,0),
(10,4,13666,20000,1,0,0,1,1,0,0,0),
(10,4,13667,20000,1,0,0,1,1,0,0,0),
(10,4,13668,20000,1,0,0,1,1,0,0,0),
(10,4,13669,20000,1,0,0,1,1,0,0,0),
(10,4,13670,20000,1,0,0,1,1,0,0,0),
(10,4,13671,20000,1,0,0,1,1,0,0,0),
(10,4,13672,20000,1,0,0,1,1,0,0,0),
(10,4,13673,20000,1,0,0,1,1,0,0,0),
(10,4,13674,20000,1,0,0,1,1,0,0,0),
(10,4,13675,20000,1,0,0,1,1,0,0,0),
(10,4,13676,20000,1,0,0,1,1,0,0,0),
(10,4,13677,20000,1,0,0,1,1,0,0,0),
(10,4,13678,20000,1,0,0,1,1,0,0,0),
(10,4,13679,20000,1,0,0,1,1,0,0,0),
(10,4,13680,20000,1,0,0,1,1,0,0,0),
(10,4,13681,20000,1,0,0,1,1,0,0,0),
(10,4,13682,20000,1,0,0,1,1,0,0,0),
(10,4,13683,20000,1,0,0,1,1,0,0,0),
(10,4,13684,20000,1,0,0,1,1,0,0,0),
(10,4,13685,20000,1,0,0,1,1,0,0,0),
(10,4,13686,20000,1,0,0,1,1,0,0,0),
(10,4,13687,20000,1,0,0,1,1,0,0,0),
(10,4,13688,20000,1,0,0,1,1,0,0,0),
(10,4,13689,20000,1,0,0,1,1,0,0,0),
(10,4,13690,20000,1,0,0,1,1,0,0,0),
(10,4,13691,20000,1,0,0,1,1,0,0,0),
(10,4,15546,20000,1,0,0,1,1,0,0,0),
(10,4,15547,20000,1,0,0,1,1,0,0,0),
(10,4,15548,20000,1,0,0,1,1,0,0,0),
(10,4,15549,20000,1,0,0,1,1,0,0,0),
(10,4,16162,35000,1,0,0,1,1,0,0,0),
(10,4,16163,35000,1,0,0,1,1,0,0,0),
(10,4,16164,35000,1,0,0,1,1,0,0,0),
(10,4,16165,35000,1,0,0,1,1,0,0,0),
(10,4,16166,35000,1,0,0,1,1,0,0,0),
(10,4,16167,35000,1,0,0,1,1,0,0,0),
(10,4,16168,35000,1,0,0,1,1,0,0,0),
(10,4,16169,35000,1,0,0,1,1,0,0,0),
(10,4,16172,35000,1,0,0,1,1,0,0,0),
(10,4,16173,35000,1,0,0,1,1,0,0,0),
(10,4,16174,35000,1,0,0,1,1,0,0,0),
(10,4,16175,35000,1,0,0,1,1,0,0,0),
(10,4,16176,35000,1,0,0,1,1,0,0,0),
(10,4,16177,35000,1,0,0,1,1,0,0,0),
(10,4,16178,35000,1,0,0,1,1,0,0,0),
(10,4,16179,35000,1,0,0,1,1,0,0,0),
(10,4,16182,35000,1,0,0,1,1,0,0,0),
(10,4,16183,35000,1,0,0,1,1,0,0,0),
(10,4,16184,35000,1,0,0,1,1,0,0,0),
(10,4,16185,35000,1,0,0,1,1,0,0,0),
(10,4,16186,35000,1,0,0,1,1,0,0,0),
(10,4,16187,35000,1,0,0,1,1,0,0,0),
(10,4,16188,35000,1,0,0,1,1,0,0,0),
(10,4,16189,35000,1,0,0,1,1,0,0,0),
(10,4,16192,35000,1,0,0,1,1,0,0,0),
(10,4,16193,35000,1,0,0,1,1,0,0,0),
(10,4,16194,35000,1,0,0,1,1,0,0,0),
(10,4,16195,35000,1,0,0,1,1,0,0,0),
(10,4,16196,35000,1,0,0,1,1,0,0,0),
(10,4,16197,35000,1,0,0,1,1,0,0,0),
(10,4,16198,35000,1,0,0,1,1,0,0,0),
(10,4,16199,35000,1,0,0,1,1,0,0,0),
(10,4,16202,35000,1,0,0,1,1,0,0,0),
(10,4,16203,35000,1,0,0,1,1,0,0,0),
(10,4,16204,35000,1,0,0,1,1,0,0,0),
(10,4,16205,35000,1,0,0,1,1,0,0,0),
(10,4,16206,35000,1,0,0,1,1,0,0,0),
(10,4,16207,35000,1,0,0,1,1,0,0,0),
(10,4,16208,35000,1,0,0,1,1,0,0,0),
(10,4,16209,35000,1,0,0,1,1,0,0,0),
(10,4,16212,35000,1,0,0,1,1,0,0,0),
(10,4,16213,35000,1,0,0,1,1,0,0,0),
(10,4,16214,35000,1,0,0,1,1,0,0,0),
(10,4,16215,35000,1,0,0,1,1,0,0,0),
(10,4,16216,35000,1,0,0,1,1,0,0,0),
(10,4,16217,35000,1,0,0,1,1,0,0,0),
(10,4,16218,35000,1,0,0,1,1,0,0,0),
(10,4,16219,35000,1,0,0,1,1,0,0,0),
(10,4,16222,35000,1,0,0,1,1,0,0,0),
(10,4,16223,35000,1,0,0,1,1,0,0,0),
(10,4,16224,35000,1,0,0,1,1,0,0,0),
(10,4,16225,35000,1,0,0,1,1,0,0,0),
(10,4,16226,35000,1,0,0,1,1,0,0,0),
(10,4,16227,35000,1,0,0,1,1,0,0,0),
(10,4,16228,35000,1,0,0,1,1,0,0,0),
(10,4,16229,35000,1,0,0,1,1,0,0,0),
(10,4,16232,35000,1,0,0,1,1,0,0,0),
(10,4,16233,35000,1,0,0,1,1,0,0,0),
(10,4,16234,35000,1,0,0,1,1,0,0,0),
(10,4,16235,35000,1,0,0,1,1,0,0,0),
(10,4,16236,35000,1,0,0,1,1,0,0,0),
(10,4,16237,35000,1,0,0,1,1,0,0,0),
(10,4,16238,35000,1,0,0,1,1,0,0,0),
(10,4,16239,35000,1,0,0,1,1,0,0,0),
(10,4,16242,35000,1,0,0,1,1,0,0,0),
(10,4,16243,35000,1,0,0,1,1,0,0,0),
(10,4,16244,35000,1,0,0,1,1,0,0,0),
(10,4,16245,35000,1,0,0,1,1,0,0,0),
(10,4,16246,35000,1,0,0,1,1,0,0,0),
(10,4,16247,35000,1,0,0,1,1,0,0,0),
(10,4,16248,35000,1,0,0,1,1,0,0,0),
(10,4,16249,35000,1,0,0,1,1,0,0,0),
(10,4,16252,35000,1,0,0,1,1,0,0,0),
(10,4,16253,35000,1,0,0,1,1,0,0,0),
(10,4,16254,35000,1,0,0,1,1,0,0,0),
(10,4,16255,35000,1,0,0,1,1,0,0,0),
(10,4,16256,35000,1,0,0,1,1,0,0,0),
(10,4,16257,35000,1,0,0,1,1,0,0,0),
(10,4,16258,35000,1,0,0,1,1,0,0,0),
(10,4,16259,35000,1,0,0,1,1,0,0,0),
(10,4,16262,35000,1,0,0,1,1,0,0,0),
(10,4,16263,35000,1,0,0,1,1,0,0,0),
(10,4,16264,35000,1,0,0,1,1,0,0,0),
(10,4,16265,35000,1,0,0,1,1,0,0,0),
(10,4,16266,35000,1,0,0,1,1,0,0,0),
(10,4,16267,35000,1,0,0,1,1,0,0,0),
(10,4,16268,35000,1,0,0,1,1,0,0,0),
(10,4,16269,35000,1,0,0,1,1,0,0,0),
(10,4,16272,35000,1,0,0,1,1,0,0,0),
(10,4,16273,35000,1,0,0,1,1,0,0,0),
(10,4,16274,35000,1,0,0,1,1,0,0,0),
(10,4,16275,35000,1,0,0,1,1,0,0,0),
(10,4,16276,35000,1,0,0,1,1,0,0,0),
(10,4,16277,35000,1,0,0,1,1,0,0,0),
(10,4,16278,35000,1,0,0,1,1,0,0,0),
(10,4,16279,35000,1,0,0,1,1,0,0,0),
(10,4,16282,35000,1,0,0,1,1,0,0,0),
(10,4,16283,35000,1,0,0,1,1,0,0,0),
(10,4,16284,35000,1,0,0,1,1,0,0,0),
(10,4,16285,35000,1,0,0,1,1,0,0,0),
(10,4,16286,35000,1,0,0,1,1,0,0,0),
(10,4,16287,35000,1,0,0,1,1,0,0,0),
(10,4,16288,35000,1,0,0,1,1,0,0,0),
(10,4,16289,35000,1,0,0,1,1,0,0,0),
(10,4,16292,35000,1,0,0,1,1,0,0,0),
(10,4,16293,35000,1,0,0,1,1,0,0,0),
(10,4,16294,35000,1,0,0,1,1,0,0,0),
(10,4,16295,35000,1,0,0,1,1,0,0,0),
(10,4,16296,35000,1,0,0,1,1,0,0,0),
(10,4,16297,35000,1,0,0,1,1,0,0,0),
(10,4,16298,35000,1,0,0,1,1,0,0,0),
(10,4,16299,35000,1,0,0,1,1,0,0,0),
(10,8,14136,15000,1,0,0,1,1,0,0,0),
(10,8,14137,15000,1,0,0,1,1,0,0,0),
(10,8,14138,15000,1,0,0,1,1,0,0,0),
(10,8,14139,15000,1,0,0,1,1,0,0,0),
(10,8,14140,15000,1,0,0,1,1,0,0,0),
(10,8,14141,15000,1,0,0,1,1,0,0,0),
(10,8,14142,15000,1,0,0,1,1,0,0,0),
(10,8,14143,15000,1,0,0,1,1,0,0,0),
(10,8,14144,15000,1,0,0,1,1,0,0,0),
(10,8,14145,15000,1,0,0,1,1,0,0,0),
(10,8,14454,30000,1,0,0,1,1,0,0,0),
(10,8,14455,30000,1,0,0,1,1,0,0,0),
(10,8,14456,30000,1,0,0,1,1,0,0,0),
(10,8,14457,30000,1,0,0,1,1,0,0,0),
(10,8,14458,30000,1,0,0,1,1,0,0,0),
(10,8,14459,30000,1,0,0,1,1,0,0,0),
(10,8,14460,30000,1,0,0,1,1,0,0,0),
(10,8,14461,30000,1,0,0,1,1,0,0,0),
(10,8,14462,30000,1,0,0,1,1,0,0,0),
(10,8,14463,30000,1,0,0,1,1,0,0,0),
(10,8,12724,50000,1,0,0,1,1,0,0,0),
(10,8,12725,50000,1,0,0,1,1,0,0,0),
(10,8,12726,50000,1,0,0,1,1,0,0,0),
(10,8,12727,50000,1,0,0,1,1,0,0,0),
(10,8,12728,50000,1,0,0,1,1,0,0,0),
(10,8,12729,50000,1,0,0,1,1,0,0,0),
(10,8,12730,50000,1,0,0,1,1,0,0,0),
(10,8,12731,50000,1,0,0,1,1,0,0,0),
(10,8,12732,50000,1,0,0,1,1,0,0,0),
(10,8,12733,50000,1,0,0,1,1,0,0,0),
(10,8,12734,50000,1,0,0,1,1,0,0,0),
(10,8,12735,50000,1,0,0,1,1,0,0,0),
(10,8,12736,50000,1,0,0,1,1,0,0,0),
(10,8,12737,50000,1,0,0,1,1,0,0,0),
(10,8,12738,50000,1,0,0,1,1,0,0,0),
(10,8,12739,50000,1,0,0,1,1,0,0,0),
(10,8,12740,50000,1,0,0,1,1,0,0,0),
(10,8,12741,50000,1,0,0,1,1,0,0,0),
(10,8,12742,50000,1,0,0,1,1,0,0,0),
(10,8,12743,50000,1,0,0,1,1,0,0,0),
(10,8,12744,50000,1,0,0,1,1,0,0,0),
(10,8,12745,50000,1,0,0,1,1,0,0,0),
(10,8,12746,50000,1,0,0,1,1,0,0,0),
(10,8,12747,50000,1,0,0,1,1,0,0,0),
(10,8,12748,50000,1,0,0,1,1,0,0,0),
(10,8,12749,50000,1,0,0,1,1,0,0,0),
(10,8,12750,50000,1,0,0,1,1,0,0,0),
(10,8,12751,50000,1,0,0,1,1,0,0,0),
(10,8,12752,50000,1,0,0,1,1,0,0,0),
(10,8,12753,50000,1,0,0,1,1,0,0,0),
(10,8,15070,50000,1,0,0,1,1,0,0,0),
(10,8,15071,50000,1,0,0,1,1,0,0,0),
(10,8,15072,50000,1,0,0,1,1,0,0,0),
(10,8,15073,50000,1,0,0,1,1,0,0,0),
(10,8,15074,50000,1,0,0,1,1,0,0,0),
(10,8,15075,50000,1,0,0,1,1,0,0,0),
(10,8,15076,50000,1,0,0,1,1,0,0,0),
(10,8,15077,50000,1,0,0,1,1,0,0,0),
(10,8,15078,50000,1,0,0,1,1,0,0,0),
(10,8,15079,50000,1,0,0,1,1,0,0,0),
(10,8,15567,20000,1,0,0,1,1,0,0,0),
(10,8,15568,20000,1,0,0,1,1,0,0,0),
(10,8,15569,20000,1,0,0,1,1,0,0,0),
(10,8,15570,20000,1,0,0,1,1,0,0,0),
(10,8,15571,20000,1,0,0,1,1,0,0,0),
(10,8,15572,20000,1,0,0,1,1,0,0,0),
(10,8,15573,20000,1,0,0,1,1,0,0,0),
(10,8,15574,20000,1,0,0,1,1,0,0,0),
(10,8,15575,20000,1,0,0,1,1,0,0,0),
(10,8,15576,20000,1,0,0,1,1,0,0,0),
(10,8,15577,20000,1,0,0,1,1,0,0,0),
(10,8,15578,20000,1,0,0,1,1,0,0,0),
(10,8,15579,20000,1,0,0,1,1,0,0,0),
(10,8,15580,20000,1,0,0,1,1,0,0,0),
(10,8,15581,20000,1,0,0,1,1,0,0,0),
(10,8,15582,20000,1,0,0,1,1,0,0,0),
(10,8,15583,20000,1,0,0,1,1,0,0,0),
(10,8,15584,20000,1,0,0,1,1,0,0,0),
(10,8,15585,20000,1,0,0,1,1,0,0,0),
(10,8,15586,20000,1,0,0,1,1,0,0,0),
(10,8,15587,20000,1,0,0,1,1,0,0,0),
(10,8,15588,20000,1,0,0,1,1,0,0,0),
(10,8,15589,20000,1,0,0,1,1,0,0,0),
(10,8,15590,20000,1,0,0,1,1,0,0,0),
(10,8,15591,20000,1,0,0,1,1,0,0,0),
(10,8,15592,20000,1,0,0,1,1,0,0,0),
(10,8,15593,20000,1,0,0,1,1,0,0,0),
(10,8,15594,20000,1,0,0,1,1,0,0,0),
(10,8,15595,20000,1,0,0,1,1,0,0,0),
(10,8,15596,20000,1,0,0,1,1,0,0,0),
(10,8,15597,20000,1,0,0,1,1,0,0,0),
(10,8,15598,20000,1,0,0,1,1,0,0,0),
(10,8,15599,20000,1,0,0,1,1,0,0,0),
(10,8,15600,20000,1,0,0,1,1,0,0,0),
(10,8,15601,20000,1,0,0,1,1,0,0,0),
(10,8,15602,20000,1,0,0,1,1,0,0,0),
(10,8,15603,20000,1,0,0,1,1,0,0,0),
(10,8,15604,20000,1,0,0,1,1,0,0,0),
(10,8,15605,20000,1,0,0,1,1,0,0,0),
(10,8,15606,20000,1,0,0,1,1,0,0,0),
(10,8,15607,20000,1,0,0,1,1,0,0,0),
(10,8,15608,20000,1,0,0,1,1,0,0,0),
(10,8,15609,20000,1,0,0,1,1,0,0,0),
(10,8,15610,20000,1,0,0,1,1,0,0,0),
(10,8,15611,20000,1,0,0,1,1,0,0,0),
(10,8,15612,20000,1,0,0,1,1,0,0,0),
(10,8,15613,20000,1,0,0,1,1,0,0,0),
(10,8,15614,20000,1,0,0,1,1,0,0,0),
(10,8,15615,20000,1,0,0,1,1,0,0,0),
(10,8,15616,20000,1,0,0,1,1,0,0,0),
(10,8,15617,20000,1,0,0,1,1,0,0,0),
(10,8,15618,20000,1,0,0,1,1,0,0,0),
(10,8,15619,20000,1,0,0,1,1,0,0,0),
(10,8,15620,20000,1,0,0,1,1,0,0,0),
(10,8,15621,20000,1,0,0,1,1,0,0,0),
(10,8,15622,20000,1,0,0,1,1,0,0,0),
(10,8,15623,20000,1,0,0,1,1,0,0,0),
(10,8,15624,20000,1,0,0,1,1,0,0,0),
(10,8,15625,20000,1,0,0,1,1,0,0,0),
(10,8,15626,20000,1,0,0,1,1,0,0,0),
(10,8,15627,20000,1,0,0,1,1,0,0,0),
(10,8,15628,20000,1,0,0,1,1,0,0,0),
(10,8,15629,20000,1,0,0,1,1,0,0,0),
(10,8,15630,20000,1,0,0,1,1,0,0,0),
(10,8,15631,20000,1,0,0,1,1,0,0,0),
(10,8,15632,20000,1,0,0,1,1,0,0,0),
(10,8,15633,20000,1,0,0,1,1,0,0,0),
(10,8,15634,20000,1,0,0,1,1,0,0,0),
(10,8,15635,20000,1,0,0,1,1,0,0,0),
(10,8,15636,20000,1,0,0,1,1,0,0,0),
(10,8,15637,20000,1,0,0,1,1,0,0,0),
(10,8,15638,20000,1,0,0,1,1,0,0,0),
(10,8,15639,20000,1,0,0,1,1,0,0,0),
(10,8,15640,20000,1,0,0,1,1,0,0,0),
(10,8,15641,20000,1,0,0,1,1,0,0,0),
(10,8,15642,20000,1,0,0,1,1,0,0,0),
(10,8,15643,20000,1,0,0,1,1,0,0,0),
(10,8,15644,20000,1,0,0,1,1,0,0,0),
(10,8,15645,20000,1,0,0,1,1,0,0,0),
(10,8,15646,20000,1,0,0,1,1,0,0,0),
(10,8,15647,20000,1,0,0,1,1,0,0,0),
(10,8,15648,20000,1,0,0,1,1,0,0,0),
(10,8,15649,20000,1,0,0,1,1,0,0,0),
(10,8,15650,20000,1,0,0,1,1,0,0,0),
(10,8,15651,20000,1,0,0,1,1,0,0,0),
(10,8,15652,20000,1,0,0,1,1,0,0,0),
(10,8,15653,20000,1,0,0,1,1,0,0,0),
(10,8,15654,20000,1,0,0,1,1,0,0,0),
(10,8,15655,20000,1,0,0,1,1,0,0,0),
(10,8,15656,20000,1,0,0,1,1,0,0,0),
(10,8,15657,20000,1,0,0,1,1,0,0,0),
(10,8,15658,20000,1,0,0,1,1,0,0,0),
(10,8,15659,20000,1,0,0,1,1,0,0,0),
(10,8,15660,20000,1,0,0,1,1,0,0,0),
(10,8,15661,20000,1,0,0,1,1,0,0,0),
(10,8,15662,20000,1,0,0,1,1,0,0,0),
(10,8,15663,20000,1,0,0,1,1,0,0,0),
(10,8,15664,20000,1,0,0,1,1,0,0,0),
(10,8,15665,20000,1,0,0,1,1,0,0,0),
(10,8,15666,20000,1,0,0,1,1,0,0,0),
(10,8,15667,20000,1,0,0,1,1,0,0,0),
(10,8,15668,20000,1,0,0,1,1,0,0,0),
(10,8,15669,20000,1,0,0,1,1,0,0,0),
(10,8,15670,20000,1,0,0,1,1,0,0,0),
(10,8,15671,20000,1,0,0,1,1,0,0,0),
(10,8,15672,20000,1,0,0,1,1,0,0,0),
(10,8,15673,20000,1,0,0,1,1,0,0,0),
(10,8,15674,20000,1,0,0,1,1,0,0,0),
(10,8,15675,20000,1,0,0,1,1,0,0,0),
(10,8,15676,20000,1,0,0,1,1,0,0,0),
(10,8,15677,20000,1,0,0,1,1,0,0,0),
(10,8,15678,20000,1,0,0,1,1,0,0,0),
(10,8,15679,20000,1,0,0,1,1,0,0,0),
(10,8,15680,20000,1,0,0,1,1,0,0,0),
(10,8,15681,20000,1,0,0,1,1,0,0,0),
(10,8,15682,20000,1,0,0,1,1,0,0,0),
(10,8,15683,20000,1,0,0,1,1,0,0,0),
(10,8,15684,20000,1,0,0,1,1,0,0,0),
(10,8,15685,20000,1,0,0,1,1,0,0,0),
(10,8,15686,20000,1,0,0,1,1,0,0,0),
(10,8,15687,20000,1,0,0,1,1,0,0,0),
(10,8,15688,20000,1,0,0,1,1,0,0,0),
(10,8,15689,20000,1,0,0,1,1,0,0,0),
(10,8,15690,20000,1,0,0,1,1,0,0,0),
(10,8,15691,20000,1,0,0,1,1,0,0,0),
(10,8,15692,20000,1,0,0,1,1,0,0,0),
(10,8,15693,20000,1,0,0,1,1,0,0,0),
(10,8,15694,20000,1,0,0,1,1,0,0,0),
(10,8,15695,20000,1,0,0,1,1,0,0,0),
(10,8,15696,20000,1,0,0,1,1,0,0,0),
(10,8,15697,20000,1,0,0,1,1,0,0,0),
(10,8,15698,20000,1,0,0,1,1,0,0,0),
(10,8,15699,20000,1,0,0,1,1,0,0,0),
(10,8,15700,20000,1,0,0,1,1,0,0,0),
(10,8,15701,20000,1,0,0,1,1,0,0,0),
(10,8,15702,20000,1,0,0,1,1,0,0,0),
(10,8,15703,20000,1,0,0,1,1,0,0,0),
(10,8,15704,20000,1,0,0,1,1,0,0,0),
(10,8,15705,20000,1,0,0,1,1,0,0,0),
(10,8,15706,20000,1,0,0,1,1,0,0,0),
(10,8,15707,20000,1,0,0,1,1,0,0,0),
(10,8,15708,20000,1,0,0,1,1,0,0,0),
(10,8,15709,20000,1,0,0,1,1,0,0,0),
(10,8,15710,20000,1,0,0,1,1,0,0,0),
(10,8,15711,20000,1,0,0,1,1,0,0,0),
(10,8,15712,20000,1,0,0,1,1,0,0,0),
(10,8,15713,20000,1,0,0,1,1,0,0,0),
(10,8,15714,20000,1,0,0,1,1,0,0,0),
(10,8,15715,20000,1,0,0,1,1,0,0,0),
(10,8,15716,20000,1,0,0,1,1,0,0,0),
(10,8,15717,20000,1,0,0,1,1,0,0,0),
(10,8,15718,20000,1,0,0,1,1,0,0,0),
(10,8,15719,20000,1,0,0,1,1,0,0,0),
(10,8,15720,20000,1,0,0,1,1,0,0,0),
(10,8,15721,20000,1,0,0,1,1,0,0,0),
(10,8,15722,20000,1,0,0,1,1,0,0,0),
(10,8,15723,20000,1,0,0,1,1,0,0,0),
(10,8,15724,20000,1,0,0,1,1,0,0,0),
(10,8,15725,20000,1,0,0,1,1,0,0,0),
(10,8,15726,20000,1,0,0,1,1,0,0,0),
(10,8,15727,20000,1,0,0,1,1,0,0,0),
(10,8,15728,20000,1,0,0,1,1,0,0,0),
(10,8,15729,20000,1,0,0,1,1,0,0,0),
(10,8,15730,20000,1,0,0,1,1,0,0,0),
(10,8,15731,20000,1,0,0,1,1,0,0,0),
(10,8,15732,20000,1,0,0,1,1,0,0,0),
(10,8,15733,20000,1,0,0,1,1,0,0,0),
(10,8,15734,20000,1,0,0,1,1,0,0,0),
(10,8,15735,20000,1,0,0,1,1,0,0,0),
(10,8,15736,20000,1,0,0,1,1,0,0,0),
(10,8,15737,20000,1,0,0,1,1,0,0,0),
(10,8,15738,20000,1,0,0,1,1,0,0,0),
(10,8,15739,20000,1,0,0,1,1,0,0,0),
(10,8,15740,20000,1,0,0,1,1,0,0,0),
(10,8,15741,20000,1,0,0,1,1,0,0,0),
(10,8,15742,20000,1,0,0,1,1,0,0,0),
(10,8,15743,20000,1,0,0,1,1,0,0,0),
(10,8,15744,20000,1,0,0,1,1,0,0,0),
(10,8,15745,20000,1,0,0,1,1,0,0,0),
(10,8,15746,20000,1,0,0,1,1,0,0,0),
(10,8,15747,20000,1,0,0,1,1,0,0,0),
(10,8,15748,20000,1,0,0,1,1,0,0,0),
(10,8,15749,20000,1,0,0,1,1,0,0,0),
(10,8,15750,20000,1,0,0,1,1,0,0,0),
(10,8,15751,20000,1,0,0,1,1,0,0,0),
(10,8,15752,20000,1,0,0,1,1,0,0,0),
(10,8,15753,20000,1,0,0,1,1,0,0,0),
(10,8,15754,20000,1,0,0,1,1,0,0,0),
(10,8,15755,20000,1,0,0,1,1,0,0,0),
(10,8,15756,20000,1,0,0,1,1,0,0,0),
(10,8,15757,20000,1,0,0,1,1,0,0,0),
(10,8,15758,20000,1,0,0,1,1,0,0,0),
(10,8,15759,20000,1,0,0,1,1,0,0,0),
(10,8,15760,20000,1,0,0,1,1,0,0,0),
(10,8,15761,20000,1,0,0,1,1,0,0,0),
(10,8,15762,20000,1,0,0,1,1,0,0,0),
(10,8,15763,20000,1,0,0,1,1,0,0,0),
(10,8,15764,20000,1,0,0,1,1,0,0,0),
(10,8,15765,20000,1,0,0,1,1,0,0,0),
(10,8,15766,20000,1,0,0,1,1,0,0,0),
(10,8,15919,20000,1,0,0,1,1,0,0,0),
(10,8,15920,20000,1,0,0,1,1,0,0,0),
(10,8,15921,20000,1,0,0,1,1,0,0,0),
(10,8,15922,20000,1,0,0,1,1,0,0,0),
(10,8,15923,20000,1,0,0,1,1,0,0,0),
(10,8,15924,20000,1,0,0,1,1,0,0,0),
(10,8,15925,20000,1,0,0,1,1,0,0,0),
(10,8,15926,20000,1,0,0,1,1,0,0,0),
(10,8,15927,20000,1,0,0,1,1,0,0,0),
(10,8,15928,20000,1,0,0,1,1,0,0,0),
(10,8,15929,20000,1,0,0,1,1,0,0,0),
(10,8,15930,20000,1,0,0,1,1,0,0,0),
(10,8,15931,20000,1,0,0,1,1,0,0,0),
(10,8,15932,20000,1,0,0,1,1,0,0,0),
(10,8,15933,20000,1,0,0,1,1,0,0,0),
(10,8,15934,20000,1,0,0,1,1,0,0,0),
(10,8,15935,20000,1,0,0,1,1,0,0,0),
(10,8,15936,20000,1,0,0,1,1,0,0,0),
(10,8,15937,20000,1,0,0,1,1,0,0,0),
(10,8,15938,20000,1,0,0,1,1,0,0,0),
(10,8,15939,20000,1,0,0,1,1,0,0,0),
(10,8,15940,20000,1,0,0,1,1,0,0,0),
(10,8,15941,20000,1,0,0,1,1,0,0,0),
(10,8,15942,20000,1,0,0,1,1,0,0,0),
(10,8,15943,20000,1,0,0,1,1,0,0,0),
(10,8,15944,20000,1,0,0,1,1,0,0,0),
(10,8,15945,20000,1,0,0,1,1,0,0,0),
(10,8,15946,20000,1,0,0,1,1,0,0,0),
(10,8,15947,20000,1,0,0,1,1,0,0,0),
(10,8,15948,20000,1,0,0,1,1,0,0,0),
(10,8,15949,20000,1,0,0,1,1,0,0,0),
(10,8,15950,20000,1,0,0,1,1,0,0,0),
(10,8,15951,20000,1,0,0,1,1,0,0,0),
(10,8,15952,20000,1,0,0,1,1,0,0,0),
(10,8,15953,20000,1,0,0,1,1,0,0,0),
(10,8,15954,20000,1,0,0,1,1,0,0,0),
(10,8,15955,20000,1,0,0,1,1,0,0,0),
(10,8,15956,20000,1,0,0,1,1,0,0,0),
(10,8,15957,20000,1,0,0,1,1,0,0,0),
(10,8,15958,20000,1,0,0,1,1,0,0,0),
(10,8,15959,20000,1,0,0,1,1,0,0,0),
(10,8,15960,20000,1,0,0,1,1,0,0,0),
(10,8,15961,20000,1,0,0,1,1,0,0,0),
(10,8,15962,20000,1,0,0,1,1,0,0,0),
(10,8,15963,20000,1,0,0,1,1,0,0,0),
(10,8,15964,20000,1,0,0,1,1,0,0,0),
(10,8,15965,20000,1,0,0,1,1,0,0,0),
(10,8,15966,20000,1,0,0,1,1,0,0,0),
(10,8,15967,20000,1,0,0,1,1,0,0,0),
(10,8,15968,20000,1,0,0,1,1,0,0,0),
(10,7,13506,250,1,0,0,1,1,0,50,0),
(10,7,15011,250,1,0,0,1,1,0,50,0),
(10,7,13636,250,1,0,0,1,1,0,50,0),
(10,7,15022,250,1,0,0,1,1,0,50,0),
(10,8,4407,1000,1,0,0,1,1,0,0,0),
(10,8,4408,1000,1,0,0,1,1,0,0,0),
(10,8,4409,1000,1,0,0,1,1,0,0,0),
(10,8,4410,1000,1,0,0,1,1,0,0,0),
(10,8,4411,1000,1,0,0,1,1,0,0,0),
(10,8,4412,1000,1,0,0,1,1,0,0,0),
(10,8,4413,1000,1,0,0,1,1,0,0,0),
(10,8,4414,1000,1,0,0,1,1,0,0,0),
(10,8,4823,1000,1,0,0,1,1,0,0,0),
(10,8,4824,1000,1,0,0,1,1,0,0,0),
(10,8,4825,1000,1,0,0,1,1,0,0,0),
(10,8,4826,1000,1,0,0,1,1,0,0,0),
(10,8,4827,1000,1,0,0,1,1,0,0,0),
(10,8,4828,1000,1,0,0,1,1,0,0,0),
(10,8,4829,1000,1,0,0,1,1,0,0,0),
(10,8,4830,1000,1,0,0,1,1,0,0,0),
(10,8,5194,1000,1,0,0,1,1,0,0,0),
(10,8,5195,1000,1,0,0,1,1,0,0,0),
(10,8,5196,1000,1,0,0,1,1,0,0,0),
(10,8,5197,1000,1,0,0,1,1,0,0,0),
(10,8,5198,1000,1,0,0,1,1,0,0,0),
(10,8,5199,1000,1,0,0,1,1,0,0,0),
(10,8,5200,1000,1,0,0,1,1,0,0,0),
(10,8,5201,1000,1,0,0,1,1,0,0,0),
(10,8,13630,1000,1,0,0,1,1,0,0,0),
(10,8,13631,1000,1,0,0,1,1,0,0,0),
(10,8,13632,1000,1,0,0,1,1,0,0,0),
(10,8,13633,1000,1,0,0,1,1,0,0,0),
(10,8,13634,1000,1,0,0,1,1,0,0,0),
(10,8,13635,1000,1,0,0,1,1,0,0,0),
(10,8,15103,1000,1,0,0,1,1,0,0,0),
(10,8,15104,1000,1,0,0,1,1,0,0,0),
(10,8,15105,1000,1,0,0,1,1,0,0,0),
(10,8,15106,1000,1,0,0,1,1,0,0,0),
(10,8,15107,1000,1,0,0,1,1,0,0,0),
(10,8,15108,1000,1,0,0,1,1,0,0,0),
(10,8,16459,1000,1,0,0,1,1,0,0,0),
(10,8,16460,1000,1,0,0,1,1,0,0,0),
(10,8,16461,1000,1,0,0,1,1,0,0,0),
(10,8,16462,1000,1,0,0,1,1,0,0,0),
(10,8,16463,1000,1,0,0,1,1,0,0,0),
(10,8,16464,1000,1,0,0,1,1,0,0,0),
(10,8,16465,1000,1,0,0,1,1,0,0,0),
(10,8,16466,1000,1,0,0,1,1,0,0,0),
(10,8,16467,1000,1,0,0,1,1,0,0,0),
(10,8,16468,1000,1,0,0,1,1,0,0,0),
(10,8,16469,1000,1,0,0,1,1,0,0,0),
(10,8,16470,1000,1,0,0,1,1,0,0,0),
(10,8,16471,1000,1,0,0,1,1,0,0,0),
(10,8,16472,1000,1,0,0,1,1,0,0,0),
(10,8,13416,1000,1,0,0,1,1,0,0,0),
(10,8,13417,1000,1,0,0,1,1,0,0,0),
(10,8,13418,1000,1,0,0,1,1,0,0,0),
(10,8,13419,1000,1,0,0,1,1,0,0,0),
(10,8,13420,1000,1,0,0,1,1,0,0,0),
(10,8,14283,1000,1,0,0,1,1,0,0,0),
(10,8,14284,1000,1,0,0,1,1,0,0,0),
(10,8,14285,1000,1,0,0,1,1,0,0,0),
(10,8,14286,1000,1,0,0,1,1,0,0,0),
(10,8,13182,1000,1,0,0,1,1,0,0,0),
(10,8,13507,1000,1,0,0,1,1,0,0,0),
(10,8,13981,1000,1,0,0,1,1,0,0,0),
(10,8,14744,1000,1,0,0,1,1,0,0,0),
(10,8,14893,1000,1,0,0,1,1,0,0,0),
(10,8,15785,1000,1,0,0,1,1,0,0,0),
(10,8,16419,1000,1,0,0,1,1,0,0,0),
(10,8,11470,1000,1,0,0,1,1,0,0,0),
(10,8,12512,1000,1,0,0,1,1,0,0,0),
(10,8,12884,1000,1,0,0,1,1,0,0,0),
(10,8,12513,1000,1,0,0,1,1,0,0,0),
(10,8,12514,1000,1,0,0,1,1,0,0,0),
(10,8,12515,1000,1,0,0,1,1,0,0,0),
(10,8,12516,1000,1,0,0,1,1,0,0,0),
(10,8,12517,1000,1,0,0,1,1,0,0,0),
(10,8,12518,1000,1,0,0,1,1,0,0,0),
(10,8,12519,1000,1,0,0,1,1,0,0,0),
(10,8,12520,1000,1,0,0,1,1,0,0,0),
(10,8,12521,1000,1,0,0,1,1,0,0,0),
(10,8,8179,1000,1,0,0,1,1,0,0,0),
(10,8,9704,1000,1,0,0,1,1,0,0,0),
(10,8,15448,1000,1,0,0,1,1,0,0,0),
(10,8,11162,1000,1,0,0,1,1,0,0,0),
(10,8,11163,1000,1,0,0,1,1,0,0,0),
(10,8,11164,1000,1,0,0,1,1,0,0,0),
(10,8,11165,1000,1,0,0,1,1,0,0,0),
(10,8,11661,1000,1,0,0,1,1,0,0,0),
(10,8,11662,1000,1,0,0,1,1,0,0,0),
(10,8,14639,1000,1,0,0,1,1,0,0,0),
(10,7,15774,3000,1,0,0,1,1,0,100,0),
(10,7,15775,3000,1,0,0,1,1,0,100,0),
(10,7,11420,3000,1,0,0,1,1,0,100,0),
(10,7,14704,3000,1,0,0,1,1,0,100,0),
(10,7,13177,3000,1,0,0,1,1,0,100,0),
(10,7,14191,3000,1,0,0,1,1,0,100,0),
(10,7,13449,3000,1,0,0,1,1,0,100,0),
(10,7,14192,3000,1,0,0,1,1,0,100,0),
(10,7,15772,3000,1,0,0,1,1,0,100,0),
(10,7,13791,3000,1,0,0,1,1,0,100,0),
(10,7,14006,3000,1,0,0,1,1,0,100,0),
(10,7,15768,3000,1,0,0,1,1,0,100,0),
(10,7,14069,3000,1,0,0,1,1,0,100,0),
(10,7,14124,3000,1,0,0,1,1,0,100,0),
(10,7,15507,3000,1,0,0,1,1,0,100,0),
(10,7,15508,3000,1,0,0,1,1,0,100,0),
(10,7,14855,3000,1,0,0,1,1,0,100,0),
(10,7,14894,3000,1,0,0,1,1,0,100,0),
(10,7,16444,3000,1,0,0,1,1,0,100,0),
(10,7,16445,3000,1,0,0,1,1,0,100,0),
(10,7,12509,3000,1,0,0,1,1,0,100,0),
(10,7,14126,3000,1,0,0,1,1,0,100,0),
(10,7,15062,3000,1,0,0,1,1,0,100,0),
(10,7,15063,3000,1,0,0,1,1,0,100,0),
(10,7,14891,3000,1,0,0,1,1,0,100,0),
(10,7,14895,3000,1,0,0,1,1,0,100,0),
(10,7,14091,3000,1,0,0,1,1,0,100,0),
(10,7,14092,3000,1,0,0,1,1,0,100,0),
(10,7,14501,3000,1,0,0,1,1,0,100,0),
(10,7,14506,3000,1,0,0,1,1,0,100,0),
(10,7,15285,3000,1,0,0,1,1,0,100,0),
(10,7,15286,3000,1,0,0,1,1,0,100,0),
(10,7,16442,3000,1,0,0,1,1,0,100,0),
(10,7,16443,3000,1,0,0,1,1,0,100,0),
(10,7,15027,3000,1,0,0,1,1,0,100,0),
(10,7,15028,3000,1,0,0,1,1,0,100,0),
(10,7,13453,3000,1,0,0,1,1,0,100,0),
(10,7,14193,3000,1,0,0,1,1,0,100,0),
(10,7,13178,3000,1,0,0,1,1,0,100,0),
(10,7,14194,3000,1,0,0,1,1,0,100,0),
(10,7,16454,3000,1,0,0,1,1,0,100,0),
(10,7,16455,3000,1,0,0,1,1,0,100,0),
(10,7,15030,3000,1,0,0,1,1,0,100,0),
(10,7,15031,3000,1,0,0,1,1,0,100,0),
(10,7,13790,3000,1,0,0,1,1,0,100,0),
(10,7,14005,3000,1,0,0,1,1,0,100,0),
(10,7,14406,3000,1,0,0,1,1,0,100,0),
(10,7,14413,3000,1,0,0,1,1,0,100,0),
(10,7,16448,3000,1,0,0,1,1,0,100,0),
(10,7,16449,3000,1,0,0,1,1,0,100,0),
(10,7,12872,3000,1,0,0,1,1,0,100,0),
(10,7,14187,3000,1,0,0,1,1,0,100,0),
(10,7,14125,3000,1,0,0,1,1,0,100,0),
(10,7,14500,3000,1,0,0,1,1,0,100,0),
(10,7,14505,3000,1,0,0,1,1,0,100,0),
(10,7,15118,3000,1,0,0,1,1,0,100,0),
(10,7,15119,3000,1,0,0,1,1,0,100,0),
(10,7,14662,3000,1,0,0,1,1,0,100,0),
(10,7,14663,3000,1,0,0,1,1,0,100,0),
(10,7,15771,3000,1,0,0,1,1,0,100,0),
(10,7,9700,3000,1,0,0,1,1,0,100,0),
(10,7,14498,3000,1,0,0,1,1,0,100,0),
(10,7,14913,3000,1,0,0,1,1,0,100,0),
(10,7,14914,3000,1,0,0,1,1,0,100,0),
(10,7,13508,3000,1,0,0,1,1,0,100,0),
(10,7,15115,3000,1,0,0,1,1,0,100,0),
(10,7,15116,3000,1,0,0,1,1,0,100,0),
(10,7,15113,3000,1,0,0,1,1,0,100,0),
(10,7,15114,3000,1,0,0,1,1,0,100,0),
(10,7,15222,3000,1,0,0,1,1,0,100,0),
(10,7,15223,3000,1,0,0,1,1,0,100,0),
(10,7,10750,3000,1,0,0,1,1,0,100,0),
(10,7,14705,3000,1,0,0,1,1,0,100,0),
(10,7,15027,3000,1,0,0,1,1,0,100,0),
(10,7,15028,3000,1,0,0,1,1,0,100,0),
(10,7,10380,3000,1,0,0,1,1,0,100,0),
(10,7,15060,3000,1,0,0,1,1,0,100,0),
(10,7,13963,3000,1,0,0,1,1,0,100,0),
(10,7,14026,3000,1,0,0,1,1,0,100,0),
(10,7,13964,3000,1,0,0,1,1,0,100,0),
(10,7,14027,3000,1,0,0,1,1,0,100,0),
(10,7,15064,3000,1,0,0,1,1,0,100,0),
(10,7,15065,3000,1,0,0,1,1,0,100,0),
(10,7,15524,3000,1,0,0,1,1,0,100,0),
(10,7,15525,3000,1,0,0,1,1,0,100,0),
(10,7,16450,3000,1,0,0,1,1,0,100,0),
(10,7,16451,3000,1,0,0,1,1,0,100,0),
(10,7,16344,3000,1,0,0,1,1,0,100,0),
(10,7,16345,3000,1,0,0,1,1,0,100,0),
(10,7,16342,3000,1,0,0,1,1,0,100,0),
(10,7,16343,3000,1,0,0,1,1,0,100,0),
(10,7,15220,3000,1,0,0,1,1,0,100,0),
(10,7,15221,3000,1,0,0,1,1,0,100,0),
(10,7,15066,3000,1,0,0,1,1,0,100,0),
(10,7,15067,3000,1,0,0,1,1,0,100,0),
(10,7,14089,3000,1,0,0,1,1,0,100,0),
(10,7,14090,3000,1,0,0,1,1,0,100,0),
(10,7,14195,3000,1,0,0,1,1,0,100,0),
(10,7,14196,3000,1,0,0,1,1,0,100,0),
(10,7,13965,3000,1,0,0,1,1,0,100,0),
(10,7,14028,3000,1,0,0,1,1,0,100,0),
(10,7,13508,3000,1,0,0,1,1,0,100,0),
(10,7,13962,3000,1,0,0,1,1,0,100,0),
(10,7,14314,3000,1,0,0,1,1,0,100,0),
(10,7,13404,3000,1,0,0,1,1,0,100,0),
(10,7,14188,3000,1,0,0,1,1,0,100,0),
(10,7,14032,3000,1,0,0,1,1,0,100,0),
(10,7,13960,3000,1,0,0,1,1,0,100,0),
(10,7,15819,3000,1,0,0,1,1,0,100,0),
(10,7,15820,3000,1,0,0,1,1,0,100,0),
(10,7,10750,3000,1,0,0,1,1,0,100,0),
(10,7,14705,3000,1,0,0,1,1,0,100,0),
(10,7,14407,3000,1,0,0,1,1,0,100,0),
(10,7,14414,3000,1,0,0,1,1,0,100,0),
(10,7,16352,3000,1,0,0,1,1,0,100,0),
(10,7,16353,3000,1,0,0,1,1,0,100,0),
(10,7,14502,3000,1,0,0,1,1,0,100,0),
(10,7,14507,3000,1,0,0,1,1,0,100,0),
(10,7,10811,3000,1,0,0,1,1,0,100,0),
(10,7,15061,3000,1,0,0,1,1,0,100,0),
(10,7,15823,3000,1,0,0,1,1,0,100,0),
(10,7,15824,3000,1,0,0,1,1,0,100,0),
(10,7,15224,3000,1,0,0,1,1,0,100,0),
(10,7,15225,3000,1,0,0,1,1,0,100,0),
(10,7,14503,3000,1,0,0,1,1,0,100,0),
(10,7,14510,3000,1,0,0,1,1,0,100,0),
(10,7,15776,3000,1,0,0,1,1,0,100,0),
(10,7,15777,3000,1,0,0,1,1,0,100,0),
(10,7,15821,3000,1,0,0,1,1,0,100,0),
(10,7,15822,3000,1,0,0,1,1,0,100,0),
(10,7,14198,3000,1,0,0,1,1,0,100,0),
(10,7,14197,3000,1,0,0,1,1,0,100,0),
(10,7,16446,3000,1,0,0,1,1,0,100,0),
(10,7,16447,3000,1,0,0,1,1,0,100,0),
(10,7,14905,3000,1,0,0,1,1,0,100,0),
(10,7,14907,3000,1,0,0,1,1,0,100,0),
(10,7,14904,3000,1,0,0,1,1,0,100,0),
(10,7,14906,3000,1,0,0,1,1,0,100,0),
(10,7,14659,3000,1,0,0,1,1,0,100,0),
(10,7,14660,3000,1,0,0,1,1,0,100,0),
(10,7,13326,3000,1,0,0,1,1,0,100,0),
(10,7,14416,3000,1,0,0,1,1,0,100,0),
(10,7,13450,3000,1,0,0,1,1,0,100,0),
(10,7,14031,3000,1,0,0,1,1,0,100,0),
(10,7,16492,3000,1,0,0,1,1,0,100,0),
(10,7,16493,3000,1,0,0,1,1,0,100,0),
(10,7,14299,500,1,0,0,1,1,0,20,0),
(10,7,14389,500,1,0,0,1,1,0,20,0),
(10,7,15177,500,1,0,0,1,1,0,20,0),
(10,7,14537,500,1,0,0,1,1,0,20,0),
(10,7,14758,500,1,0,0,1,1,0,20,0),
(10,7,14854,500,1,0,0,1,1,0,20,0),
(10,7,13974,500,1,0,0,1,1,0,20,0),
(10,7,15021,500,1,0,0,1,1,0,20,0),
(10,7,15111,500,1,0,0,1,1,0,20,0),
(10,7,15226,500,1,0,0,1,1,0,20,0),
(10,7,15773,500,1,0,0,1,1,0,20,0),
(10,7,15825,500,1,0,0,1,1,0,20,0),
(10,7,15827,500,1,0,0,1,1,0,20,0),
(10,7,16340,500,1,0,0,1,1,0,20,0),
(10,7,16341,500,1,0,0,1,1,0,20,0),
(10,7,16457,500,1,0,0,1,1,0,20,0),
(10,7,16458,500,1,0,0,1,1,0,20,0),
(10,7,11698,250,1,0,0,1,1,0,50,0),
(10,7,11700,250,1,0,0,1,1,0,50,0),
(10,8,9958,20,1,0,0,1,1,0,0,999),
(10,8,11284,15,1,0,0,1,1,0,0,0),
(10,8,11285,15,1,0,0,1,1,0,0,0),
(10,8,11286,15,1,0,0,1,1,0,0,0),
(10,8,10356,500,1,0,0,1,1,0,0,0),
(10,8,12511,500,1,0,0,1,1,0,0,0),
(10,8,13238,500,1,0,0,1,1,0,0,0),
(10,8,11383,10,1,0,0,1,1,0,0,0),
(10,8,11382,10,1,0,0,1,1,0,0,0),
(10,8,11381,10,1,0,0,1,1,0,0,0),
(10,7,16348,3000,1,0,0,1,1,0,100,0),
(10,8,11386,10,1,0,0,1,1,0,0,0),
(10,8,14444,10,1,0,0,1,1,0,0,0),
(10,8,14443,10,1,0,0,1,1,0,0,0),
(10,8,14445,10,1,0,0,1,1,0,0,0),
(10,8,15068,500,1,0,0,1,1,0,20,0),
(10,7,16532,1000,1,0,0,1,1,0,0,0),
(10,7,14368,3000,1,0,0,1,1,0,50,0),
(10,7,1622,3000,1,0,0,1,1,0,0,0),
(10,7,16456,500,1,0,0,1,1,0,0,0);
END;

View File

@@ -0,0 +1,178 @@
BEGIN;
INSERT INTO public.scenario_counter
(scenario_id, category_id)
VALUES
(17,0),
(93,1),
(92,1),
(81,1),
(91,1),
(90,1),
(89,1),
(88,1),
(87,1),
(86,1),
(85,1),
(84,1),
(83,1),
(82,1),
(87,3),
(88,3),
(89,3),
(90,3),
(91,3),
(92,3),
(83,3),
(86,3),
(60,3),
(58,3),
(59,3),
(27,3),
(25,3),
(26,3),
(23,3),
(2,3),
(3,3),
(4,3),
(31,3),
(32,3),
(33,3),
(34,3),
(35,3),
(36,3),
(37,3),
(40,3),
(38,3),
(39,3),
(48,3),
(12,3),
(13,3),
(30,3),
(29,3),
(46,3),
(0,4),
(1,4),
(2,4),
(3,4),
(4,4),
(5,4),
(6,4),
(7,4),
(8,4),
(9,4),
(10,4),
(11,4),
(12,4),
(13,4),
(14,4),
(50,5),
(51,5),
(52,5),
(53,5),
(54,5),
(55,5),
(56,5),
(58,5),
(63,5),
(64,5),
(65,5),
(67,5),
(71,5),
(75,5),
(61,5),
(68,5),
(66,5),
(76,5),
(70,5),
(77,5),
(72,5),
(74,5),
(73,5),
(78,5),
(69,5),
(62,5),
(79,5),
(0,6),
(1,6),
(2,6),
(3,6),
(4,6),
(5,6),
(6,6),
(7,6),
(8,6),
(9,6),
(17,6),
(10,6),
(11,6),
(12,6),
(13,6),
(14,6),
(15,6),
(16,6),
(50,7),
(53,7),
(62,7),
(52,7),
(56,7),
(51,7),
(49,7),
(54,7),
(57,7),
(55,7),
(61,7),
(58,7),
(60,7),
(59,7),
(42,7),
(48,7),
(40,7),
(39,7),
(43,7),
(46,7),
(41,7),
(44,7),
(45,7),
(47,7),
(37,7),
(34,7),
(33,7),
(32,7),
(28,7),
(26,7),
(36,7),
(38,7),
(35,7),
(27,7),
(30,7),
(31,7),
(29,7),
(24,7),
(23,7),
(22,7),
(21,7),
(25,7),
(20,7),
(7,7),
(9,7),
(13,7),
(16,7),
(12,7),
(14,7),
(15,7),
(19,7),
(10,7),
(8,7),
(11,7),
(18,7),
(17,7),
(6,7),
(5,7),
(4,7),
(3,7),
(2,7),
(1,7),
(0,7);
END;

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,14 @@
package setup
import (
"database/sql"
"embed"
"encoding/json"
"fmt"
"net/http"
"path/filepath"
"erupe-ce/server/migrations"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
"go.uber.org/zap"
)
@@ -73,16 +74,14 @@ func (ws *wizardServer) handleTestDB(w http.ResponseWriter, r *http.Request) {
// initDBRequest is the JSON body for POST /api/setup/init-db.
type initDBRequest struct {
Host string `json:"host"`
Port int `json:"port"`
User string `json:"user"`
Password string `json:"password"`
DBName string `json:"dbName"`
CreateDB bool `json:"createDB"`
ApplyInit bool `json:"applyInit"`
ApplyUpdate bool `json:"applyUpdate"`
ApplyPatch bool `json:"applyPatch"`
ApplyBundled bool `json:"applyBundled"`
Host string `json:"host"`
Port int `json:"port"`
User string `json:"user"`
Password string `json:"password"`
DBName string `json:"dbName"`
CreateDB bool `json:"createDB"`
ApplySchema bool `json:"applySchema"`
ApplyBundled bool `json:"applyBundled"`
}
func (ws *wizardServer) handleInitDB(w http.ResponseWriter, r *http.Request) {
@@ -108,23 +107,12 @@ func (ws *wizardServer) handleInitDB(w http.ResponseWriter, r *http.Request) {
addLog("Database created successfully")
}
if req.ApplyInit {
addLog("Applying init schema (pg_restore)...")
if err := applyInitSchema(req.Host, req.Port, req.User, req.Password, req.DBName); err != nil {
addLog(fmt.Sprintf("ERROR: %s", err))
writeJSON(w, http.StatusOK, map[string]interface{}{"success": false, "log": log})
return
}
addLog("Init schema applied successfully")
}
// For update/patch/bundled schemas, connect to the target DB.
if req.ApplyUpdate || req.ApplyPatch || req.ApplyBundled {
if req.ApplySchema || req.ApplyBundled {
connStr := fmt.Sprintf(
"host='%s' port='%d' user='%s' password='%s' dbname='%s' sslmode=disable",
req.Host, req.Port, req.User, req.Password, req.DBName,
)
db, err := sql.Open("postgres", connStr)
db, err := sqlx.Open("postgres", connStr)
if err != nil {
addLog(fmt.Sprintf("ERROR connecting to database: %s", err))
writeJSON(w, http.StatusOK, map[string]interface{}{"success": false, "log": log})
@@ -132,37 +120,26 @@ func (ws *wizardServer) handleInitDB(w http.ResponseWriter, r *http.Request) {
}
defer func() { _ = db.Close() }()
applyDir := func(dir, label string) bool {
addLog(fmt.Sprintf("Applying %s schemas from %s...", label, dir))
applied, err := applySQLFiles(db, filepath.Join("schemas", dir))
for _, f := range applied {
addLog(fmt.Sprintf(" Applied: %s", f))
}
if req.ApplySchema {
addLog("Running database migrations...")
applied, err := migrations.Migrate(db, ws.logger)
if err != nil {
addLog(fmt.Sprintf("ERROR: %s", err))
return false
writeJSON(w, http.StatusOK, map[string]interface{}{"success": false, "log": log})
return
}
addLog(fmt.Sprintf("%s schemas applied (%d files)", label, len(applied)))
return true
addLog(fmt.Sprintf("Schema migrations applied (%d migration(s))", applied))
}
if req.ApplyUpdate {
if !applyDir("update-schema", "update") {
writeJSON(w, http.StatusOK, map[string]interface{}{"success": false, "log": log})
return
}
}
if req.ApplyPatch {
if !applyDir("patch-schema", "patch") {
writeJSON(w, http.StatusOK, map[string]interface{}{"success": false, "log": log})
return
}
}
if req.ApplyBundled {
if !applyDir("bundled-schema", "bundled") {
addLog("Applying bundled data (shops, events, gacha)...")
applied, err := migrations.ApplySeedData(db, ws.logger)
if err != nil {
addLog(fmt.Sprintf("ERROR: %s", err))
writeJSON(w, http.StatusOK, map[string]interface{}{"success": false, "log": log})
return
}
addLog(fmt.Sprintf("Bundled data applied (%d files)", applied))
}
}

View File

@@ -6,10 +6,6 @@ import (
"fmt"
"net"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
)
// clientModes returns all supported client version strings.
@@ -373,71 +369,3 @@ func createDatabase(host string, port int, user, password, dbName string) error
return nil
}
// applyInitSchema runs pg_restore to load the init.sql (PostgreSQL custom dump format).
func applyInitSchema(host string, port int, user, password, dbName string) error {
pgRestore, err := exec.LookPath("pg_restore")
if err != nil {
return fmt.Errorf("pg_restore not found in PATH: %w (install PostgreSQL client tools)", err)
}
schemaPath := filepath.Join("schemas", "init.sql")
if _, err := os.Stat(schemaPath); err != nil {
return fmt.Errorf("schema file not found: %s", schemaPath)
}
cmd := exec.Command(pgRestore,
"--host", host,
"--port", fmt.Sprint(port),
"--username", user,
"--dbname", dbName,
"--no-owner",
"--no-privileges",
schemaPath,
)
cmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", password))
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("pg_restore failed: %w\n%s", err, string(output))
}
return nil
}
// collectSQLFiles returns sorted .sql filenames from a directory.
func collectSQLFiles(dir string) ([]string, error) {
entries, err := os.ReadDir(dir)
if err != nil {
return nil, fmt.Errorf("reading directory %s: %w", dir, err)
}
var files []string
for _, e := range entries {
if !e.IsDir() && strings.HasSuffix(e.Name(), ".sql") {
files = append(files, e.Name())
}
}
sort.Strings(files)
return files, nil
}
// applySQLFiles executes all .sql files in a directory in sorted order.
func applySQLFiles(db *sql.DB, dir string) ([]string, error) {
files, err := collectSQLFiles(dir)
if err != nil {
return nil, err
}
var applied []string
for _, f := range files {
path := filepath.Join(dir, f)
data, err := os.ReadFile(path)
if err != nil {
return applied, fmt.Errorf("reading %s: %w", f, err)
}
_, err = db.Exec(string(data))
if err != nil {
return applied, fmt.Errorf("executing %s: %w", f, err)
}
applied = append(applied, f)
}
return applied, nil
}

View File

@@ -122,9 +122,7 @@ h1{font-size:1.75rem;margin-bottom:.5rem;color:#e94560;text-align:center}
<p style="font-size:.85rem;color:#888;margin-bottom:1rem">Select which schema operations to perform.</p>
<div id="schema-options">
<label class="checkbox" id="chk-create-db-label"><input type="checkbox" id="chk-create-db" checked> Create database</label>
<label class="checkbox"><input type="checkbox" id="chk-init" checked> Apply init schema (pg_restore — required for new databases)</label>
<label class="checkbox"><input type="checkbox" id="chk-update" checked> Apply update schemas</label>
<label class="checkbox"><input type="checkbox" id="chk-patch" checked> Apply patch schemas (development patches)</label>
<label class="checkbox"><input type="checkbox" id="chk-schema" checked> Apply database schema (required for new databases)</label>
<label class="checkbox"><input type="checkbox" id="chk-bundled" checked> Apply bundled data (shops, events, gacha — recommended)</label>
</div>
<button class="btn btn-primary" id="btn-init-db" onclick="initDB()">Initialize Database</button>
@@ -208,9 +206,9 @@ function updateSchemaOptions() {
createCheck.disabled = false;
createLabel.style.opacity = '1';
}
// If tables already exist, uncheck init
// If tables already exist, uncheck schema (migrations will detect and skip)
if (dbTestResult && dbTestResult.tablesExist) {
document.getElementById('chk-init').checked = false;
document.getElementById('chk-schema').checked = false;
}
}
@@ -283,9 +281,7 @@ async function initDB() {
password: document.getElementById('db-password').value,
dbName: document.getElementById('db-name').value,
createDB: document.getElementById('chk-create-db').checked,
applyInit: document.getElementById('chk-init').checked,
applyUpdate: document.getElementById('chk-update').checked,
applyPatch: document.getElementById('chk-patch').checked,
applySchema: document.getElementById('chk-schema').checked,
applyBundled: document.getElementById('chk-bundled').checked,
})
});

View File

@@ -130,44 +130,6 @@ func TestClientModes(t *testing.T) {
}
}
func TestApplySQLFiles(t *testing.T) {
// This test doesn't need a real database — we test the file reading/sorting logic
// by verifying it returns errors when the directory doesn't exist.
_, err := applySQLFiles(nil, "/nonexistent/path")
if err == nil {
t.Error("expected error for nonexistent directory")
}
}
func TestApplySQLFilesOrdering(t *testing.T) {
// Verify that collectSQLFiles returns files in sorted order and skips non-.sql files.
dir := t.TempDir()
files := []string{"03_c.sql", "01_a.sql", "02_b.sql"}
for _, f := range files {
if err := os.WriteFile(filepath.Join(dir, f), []byte("-- "+f), 0644); err != nil {
t.Fatal(err)
}
}
// Non-SQL file should be skipped
if err := os.WriteFile(filepath.Join(dir, "readme.txt"), []byte("not sql"), 0644); err != nil {
t.Fatal(err)
}
collected, err := collectSQLFiles(dir)
if err != nil {
t.Fatalf("collectSQLFiles failed: %v", err)
}
if len(collected) != 3 {
t.Fatalf("got %d files, want 3", len(collected))
}
expected := []string{"01_a.sql", "02_b.sql", "03_c.sql"}
for i, f := range collected {
if f != expected[i] {
t.Errorf("file[%d] = %q, want %q", i, f, expected[i])
}
}
}
func TestWriteConfig(t *testing.T) {
dir := t.TempDir()
origDir, _ := os.Getwd()