commit 3cb32783abafa8e952bb48ca942aaa87b98f4a40
Author: Krzysztof Sikorski
Date: Sun Oct 27 11:58:50 2024 +0100
Save all changes
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..11d227d
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,18 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = LF
+insert_final_newline = true
+trim_trailing_whitespace = true
+indent_style = space
+indent_size = 2
+max_line_length = 80
+
+[*.php]
+# settings required by PSR-12 standard
+indent_size = 4
+max_line_length = 120
+
+[Makefile]
+indent_style = tab
diff --git a/.editorconfig-checker.json b/.editorconfig-checker.json
new file mode 100644
index 0000000..76321a0
--- /dev/null
+++ b/.editorconfig-checker.json
@@ -0,0 +1,6 @@
+{
+ "Exclude": [
+ "^.git/",
+ "^.idea/"
+ ]
+}
diff --git a/2013/daemon/.bzrignore b/2013/daemon/.bzrignore
new file mode 100644
index 0000000..d7224fd
--- /dev/null
+++ b/2013/daemon/.bzrignore
@@ -0,0 +1,6 @@
+./cfg/*
+./log/*
+./tmp/*
+./lib/PHPTAL*
+./public/google*
+./public/scyzoryk/.htaccess
diff --git a/2013/daemon/.editorconfig b/2013/daemon/.editorconfig
new file mode 100644
index 0000000..795f4da
--- /dev/null
+++ b/2013/daemon/.editorconfig
@@ -0,0 +1,17 @@
+[*]
+indent_style = tab
+max_line_length = unset
+
+[*.css]
+max_line_length = 140
+
+[*.js] # minified files
+insert_final_newline = unset
+
+[*.sql]
+indent_style = space
+
+[lib/jsmin.php] # vendored file
+insert_final_newline = unset
+indent_style = space
+indent_size = 2
diff --git a/2013/daemon/LICENSE b/2013/daemon/LICENSE
new file mode 100644
index 0000000..d10bae5
--- /dev/null
+++ b/2013/daemon/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Krzysztof Sikorski
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/2013/daemon/README.md b/2013/daemon/README.md
new file mode 100644
index 0000000..b0c6693
--- /dev/null
+++ b/2013/daemon/README.md
@@ -0,0 +1,68 @@
+INTRODUCTION
+===
+
+The game was never planned to be released in public,
+so it's designed for the LAMP stack it was originally hosted on.
+Basically the code assumes some software versions and settings,
+and will propably break on different configuration.
+
+REQUIRED SOFTWARE
+===
+
+* *Apache 2.x*, with enabled mod_rewrite and .htaccess files.
+* *PHP 5.2.x* with settings like in attached php.ini file.
+* *MySQL 5.1*, may also work on other 5.x versions.
+* *PHPTAL 1.2.1* - newer releases are propably also safe.
+* The hosting **MUST** also offer crontab or other similar services.
+
+INSTALLATION
+===
+
+1. Prepare database tables using attached SQL file.
+
+2. Configure PHP using attached INI file.
+
+3. Upload game code into server.
+
+4. Download PHPTAL library and upload it into lib subdirectory,
+you should now have `lib/PHPTAL.php`, `lib/PHPTAL/Context.php` etc.
+
+5. Enter your hosting's configuration panel and set the `public` subdir
+as a domain root, so other files won't be accessible from the Net.
+
+6. Configure crontab: set the `cron.php` file to be executed every day.
+
+7. And now the tricky part: create a config file (or files) and upload
+it into `cfg` subdirectory. It's a long and weird topic, details below.
+
+CONFIGURATION
+===
+
+The game configuration is handled by the `Daemon_Config` class
+(`lib/daemon/config.php` file), which uses it to overwrite its public
+properties. Consult the class' constructor for details.
+
+The file's content is simple, it should do nothing more than to return
+an associative array of settings. Here's an example of minimal config:
+
+ 'http://example.com/foo/bar/baz/',
+ 'applicationMail' => 'daemon@example.com',
+ 'dbHost' => 'localhost',
+ 'dbSchema' => 'daemon_db',
+ 'dbUser' => 'username',
+ 'dbPassword' => 'some_password',
+ );
+
+The tricky part is the config's filename. As you can see in the class'
+constructor, it _must_ be exactly the same as the domain on which
+the game is hosted, plus the `.php` extension.
+For example, if the game is hosted on `example.com`, then the filename
+is `example.com.php`. This is designed to prevent accidental overwrites
+with config for other machines...
+
+There is also another tricky part: if you execute a script from the
+command line instead of URL, then the script uses a special `_cron.php`
+file instead of normal config. So you should create that file too.
+Or change the `Daemon_Config`'s constructor ;)
diff --git a/2013/daemon/cron.php b/2013/daemon/cron.php
new file mode 100644
index 0000000..b086a3c
--- /dev/null
+++ b/2013/daemon/cron.php
@@ -0,0 +1,182 @@
+query($sql, array());
+unset($queries);
+
+//check for endgame
+if(!$dbCfg->rolloversEnabled)
+ return;
+
+//create rollover entry
+$sql = "INSERT INTO rollovers(date_added) VALUES (now())";
+$dbClient->query($sql);
+$rolloverId = $dbClient->lastInsertId();
+
+//give turns
+$sql = "UPDATE character_data SET turns = LEAST(:limit, turns + :delta)";
+$params = array('delta' => (int) $dbCfg->turnDelta, 'limit' => (int) $dbCfg->turnLimit);
+$dbClient->query($sql, $params);
+
+//run caern sieges
+$sql = "SELECT l.location_id FROM locations l JOIN character_data cd USING(location_id)
+ WHERE l.type='caern' AND cd.faction_id IS NOT NULL AND cd.faction_id != l.faction_id
+ GROUP BY l.location_id";
+$locations = $dbClient->selectColumn($sql);
+foreach ((array) $locations as $siegeLocationId)
+{
+ $combat = new Daemon_CaernSiege();
+ $combat->attachDbClient($dbClient);
+ $combat->execute($siegeLocationId);
+ $sql = "INSERT INTO battles(rollover_id, location_id, type, combat_log)
+ VALUES (:rolloverId, :locationId, 'caern', :combatLog)";
+ $params = array('rolloverId' => $rolloverId, 'locationId' => $siegeLocationId,
+ 'combatLog' => $combat->getCombatLog());
+ $dbClient->query($sql, $params);
+ $dbCfg->siegeLocationId = null;
+ $siegeLocationId = null;
+ unset($combat);
+}
+
+//update faction power
+$decay = (float) $dbCfg->factionDecay;
+$sql = "UPDATE factions f SET f.power = FLOOR(:decay * f.power) + COALESCE((
+ SELECT SUM(l.faction_value) FROM locations l WHERE l.type='caern' AND l.faction_id=f.faction_id
+), 0)";
+$dbClient->query($sql, array('decay' => $decay));
+
+//activate bosses
+$sql = "SELECT MAX(level) As max_level, MAX(rank_id) AS max_rank FROM character_data";
+$row = $dbClient->selectRow($sql, array());
+$unlockBosses = ($row['max_level'] >= $dbCfg->bossUnlockLevel) && ($row['max_rank'] >= $dbCfg->bossUnlockRank);
+if($unlockBosses)
+{
+ $dbClient->query("UPDATE locations SET boss_status='active' WHERE type='boss' AND boss_status != 'defeated'");
+ if(!$dbCfg->endgame)
+ $dbCfg->endgame = 1;
+}
+
+//run boss sieges
+$sql = "SELECT location_id, name FROM locations WHERE type='boss' AND boss_status = 'active'";
+$locations = $dbClient->selectAll($sql);
+if($locations)
+{
+ $factionPowers = array();
+ $sql = "SELECT faction_id, power FROM factions";
+ foreach($dbClient->selectAll($sql) as $row)
+ $factionPowers[$row['faction_id']] = $row['power'];
+ foreach($locations as $row)
+ {
+ $combat = new Daemon_BossCombat();
+ $combat->attachDbClient($dbClient);
+ $combat->execute($row['location_id'], $factionPowers);
+ $combatLog = $combat->getCombatLog();
+ if($combatLog)
+ {
+ $sql = "INSERT INTO battles(rollover_id, location_id, type, combat_log)
+ VALUES (:rolloverId, :locationId, 'boss', :combatLog)";
+ $params = array('rolloverId' => $rolloverId, 'locationId' => $row['location_id'], 'combatLog' => $combatLog);
+ $dbClient->query($sql, $params);
+ $forum->addChat(null, 'public', "Siedziba bossa \"$row[name]\" zaatakowana!");
+ }
+ }
+}
+
+
+//check for ending
+$factions = array();
+$sql = "SELECT faction_id, name FROM factions";
+foreach($dbClient->selectAll($sql) as $row)
+ $factions[$row['faction_id']] = array('name' => $row['name'], 'active' => 0, 'defeated' => 0);
+$sql = "SELECT faction_id, (boss_status!='defeated') AS active
+ FROM locations WHERE type = 'boss' GROUP BY faction_id, active";
+foreach($dbClient->selectAll($sql) as $row)
+{
+ if($row['active'])
+ $factions[$row['faction_id']]['active']++;
+ else
+ $factions[$row['faction_id']]['defeated']++;
+}
+$active = array();
+$defeated = array();
+foreach($factions as $factionId => $row)
+{
+ if($row['active'] || !$row['defeated'])
+ $active[$factionId] = $row['name'];
+ else
+ $defeated[$factionId] = $row['name'];
+}
+$endgame = (count($active) < 2);
+if($endgame)
+{
+ //final messages
+ $active = implode(', ', $active);
+ switch($active)
+ {
+ case 'blue':
+ $msg = "Rewolucja została stłumiona. Niech żyje Porządek!";
+ break;
+ case 'red':
+ $msg = "Cesarz został obalony. Niech żyje Rewolucja!";
+ break;
+ default:
+ $msg = "Wojna dobiegła końca, lecz brak w niej zwycięzców. Czas pokaże, kto zajmie miejsce dawnych potęg...";
+ }
+ $forum->addChat(null, 'public', $msg);
+ //cleanup
+ $dbCfg->globalMessage = $msg;
+ $dbCfg->rolloversEnabled = 0;
+ $dbCfg->turnDelta = 0;
+ $dbCfg->defaultRespawn = '';
+ $sql = "UPDATE character_data SET turns = 0, location_id = NULL";
+ $dbClient->query($sql);
+ $sql = "TRUNCATE TABLE character_regions";
+ $dbClient->query($sql);
+}
+
+//update rollover data
+$sql = "SELECT COUNT(1) FROM players";
+$nPlayers = $dbClient->selectValue($sql);
+$sql = "SELECT COUNT(1) FROM characters";
+$nChars = $dbClient->selectValue($sql);
+$sql = "SELECT COUNT(1) FROM clans";
+$nClans = $dbClient->selectValue($sql);
+$sql = "UPDATE rollovers SET players_total = :players, characters_total = :chars,
+ clans_total = :clans WHERE rollover_id = :id";
+$params = array('id' => $rolloverId, 'players' => $nPlayers, 'chars' => $nChars, 'clans' => $nClans);
+$dbClient->query($sql, $params);
diff --git a/2013/daemon/daemon.sql b/2013/daemon/daemon.sql
new file mode 100644
index 0000000..caa3a9e
--- /dev/null
+++ b/2013/daemon/daemon.sql
@@ -0,0 +1,525 @@
+CREATE TABLE battles (
+ battle_id int NOT NULL AUTO_INCREMENT,
+ rollover_id smallint NOT NULL,
+ location_id varchar(32) NOT NULL,
+ "type" enum('caern','boss') NOT NULL,
+ combat_log text NOT NULL,
+ PRIMARY KEY (battle_id),
+ KEY rollover_id (rollover_id,battle_id)
+);
+
+
+CREATE TABLE characters (
+ character_id int NOT NULL AUTO_INCREMENT,
+ player_id int DEFAULT NULL,
+ "name" varchar(255) NOT NULL,
+ gender enum('f','m','n') NOT NULL,
+ date_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ last_action datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ show_player tinyint(1) NOT NULL DEFAULT 0,
+ last_mail_id int NOT NULL DEFAULT 0,
+ clan_id varchar(8) DEFAULT NULL,
+ avatar_url tinytext,
+ quote text,
+ description text,
+ PRIMARY KEY (character_id),
+ UNIQUE KEY "name" ("name"),
+ KEY clan (clan_id,character_id),
+ KEY date_created (date_created,character_id),
+ KEY player_id (player_id,character_id),
+ KEY last_action (last_action)
+);
+
+
+CREATE TABLE character_data (
+ character_id int NOT NULL,
+ location_id varchar(32) DEFAULT NULL COMMENT 'current location',
+ faction_id varchar(32) DEFAULT NULL,
+ faction_points smallint NOT NULL DEFAULT 0,
+ rank_id tinyint DEFAULT NULL,
+ turns smallint NOT NULL DEFAULT 30,
+ gold_purse int NOT NULL DEFAULT 0,
+ gold_bank int NOT NULL DEFAULT 0,
+ "level" smallint NOT NULL DEFAULT 0,
+ xp_free int NOT NULL DEFAULT 29,
+ xp_used int NOT NULL DEFAULT 0,
+ deaths int NOT NULL DEFAULT 0,
+ health smallint NOT NULL DEFAULT 0,
+ health_max smallint NOT NULL DEFAULT 70,
+ mana smallint NOT NULL DEFAULT 0,
+ mana_max smallint NOT NULL DEFAULT 35,
+ mana_regen smallint NOT NULL DEFAULT 1,
+ a_str smallint NOT NULL DEFAULT 7,
+ a_dex smallint NOT NULL DEFAULT 7,
+ a_vit smallint NOT NULL DEFAULT 7,
+ a_pwr smallint NOT NULL DEFAULT 7,
+ a_wil smallint NOT NULL DEFAULT 7,
+ s_pstr smallint NOT NULL DEFAULT 0,
+ s_patk smallint NOT NULL DEFAULT 0,
+ s_pdef smallint NOT NULL DEFAULT 0,
+ s_pres smallint NOT NULL DEFAULT 0,
+ s_preg smallint NOT NULL DEFAULT 0,
+ s_mstr smallint NOT NULL DEFAULT 0,
+ s_matk smallint NOT NULL DEFAULT 0,
+ s_mdef smallint NOT NULL DEFAULT 0,
+ s_mres smallint NOT NULL DEFAULT 0,
+ s_mreg smallint NOT NULL DEFAULT 0,
+ sp_scout tinyint NOT NULL DEFAULT 0,
+ sp_identify tinyint NOT NULL DEFAULT 0,
+ sp_vchar tinyint NOT NULL DEFAULT 0,
+ sp_vmonster tinyint NOT NULL DEFAULT 0,
+ sp_vitem tinyint NOT NULL DEFAULT 0,
+ combat_unit_id varchar(32) DEFAULT NULL,
+ location_event text COMMENT 'event parameters',
+ PRIMARY KEY (character_id),
+ KEY "level" ("level",character_id),
+ KEY xp_used (xp_used,character_id),
+ KEY faction_id (faction_id,character_id),
+ KEY location_id (location_id,character_id)
+);
+
+
+CREATE TABLE character_missions (
+ character_id int NOT NULL,
+ rollover_id int NOT NULL,
+ service_id varchar(32) NOT NULL,
+ "type" enum('monster','item') NOT NULL,
+ params varchar(32) NOT NULL,
+ progress enum('active','completed','rewarded') NOT NULL DEFAULT 'active',
+ PRIMARY KEY (character_id,rollover_id)
+);
+
+
+CREATE TABLE character_regions (
+ character_id int NOT NULL,
+ region_id varchar(32) NOT NULL,
+ PRIMARY KEY (character_id,region_id)
+);
+
+
+CREATE TABLE character_statistics (
+ character_id int NOT NULL,
+ missions smallint NOT NULL DEFAULT 0,
+ duel_wins smallint NOT NULL DEFAULT 0,
+ duel_losses smallint NOT NULL DEFAULT 0,
+ kills_mob1 smallint NOT NULL DEFAULT 0,
+ kills_mob2 smallint NOT NULL DEFAULT 0,
+ kills_mob3 smallint NOT NULL DEFAULT 0,
+ kills_mob4 smallint NOT NULL DEFAULT 0,
+ PRIMARY KEY (character_id),
+ KEY duel_wins (duel_wins,character_id),
+ KEY duel_losses (duel_losses,character_id)
+);
+
+
+CREATE TABLE character_titles (
+ character_id int NOT NULL,
+ title_id varchar(32) NOT NULL,
+ PRIMARY KEY (character_id,title_id)
+);
+
+
+CREATE TABLE chat (
+ message_id int NOT NULL AUTO_INCREMENT,
+ date_added timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ channel_id varchar(255) NOT NULL,
+ sender_id int DEFAULT NULL,
+ content text NOT NULL,
+ PRIMARY KEY (message_id),
+ KEY sort (channel_id,message_id)
+);
+
+
+CREATE TABLE clans (
+ clan_id varchar(8) NOT NULL,
+ "name" varchar(255) NOT NULL,
+ date_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ leader_id int DEFAULT NULL,
+ description text,
+ PRIMARY KEY (clan_id),
+ UNIQUE KEY "name" ("name")
+);
+
+
+CREATE TABLE clan_invitations (
+ clan_id varchar(32) NOT NULL,
+ character_id int NOT NULL,
+ date_added timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ description text,
+ PRIMARY KEY (clan_id,character_id),
+ KEY search (character_id,clan_id)
+);
+
+
+CREATE TABLE combat_units (
+ combat_unit_id varchar(32) NOT NULL,
+ "name" varchar(255) NOT NULL,
+ faction_id varchar(32) DEFAULT NULL,
+ health int NOT NULL DEFAULT 70,
+ health_max int NOT NULL DEFAULT 70,
+ str1 smallint NOT NULL DEFAULT 7,
+ atk1 smallint NOT NULL DEFAULT 7,
+ type1 enum('p','m') DEFAULT 'p',
+ count1 smallint NOT NULL DEFAULT 1,
+ sp1_type varchar(32) DEFAULT NULL,
+ sp1_param smallint DEFAULT NULL,
+ str2 smallint NOT NULL DEFAULT 7,
+ atk2 smallint NOT NULL DEFAULT 7,
+ type2 enum('p','m') DEFAULT NULL,
+ count2 smallint NOT NULL DEFAULT 0,
+ sp2_type varchar(32) DEFAULT NULL,
+ sp2_param smallint DEFAULT NULL,
+ pdef smallint NOT NULL DEFAULT 7,
+ pres smallint NOT NULL DEFAULT 7,
+ mdef smallint NOT NULL DEFAULT 7,
+ mres smallint NOT NULL DEFAULT 7,
+ speed smallint NOT NULL DEFAULT 7,
+ armor smallint NOT NULL DEFAULT 0,
+ armor_sp_type varchar(32) DEFAULT NULL,
+ armor_sp_param smallint DEFAULT NULL,
+ regen float NOT NULL DEFAULT 0,
+ PRIMARY KEY (combat_unit_id)
+);
+
+
+CREATE TABLE duels (
+ duel_id int NOT NULL AUTO_INCREMENT,
+ date_added timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ rollover_id smallint DEFAULT NULL,
+ attacker_id int NOT NULL,
+ defender_id int NOT NULL,
+ "type" enum('normal','arena') NOT NULL,
+ winner enum('a','b') DEFAULT NULL,
+ combat_log text,
+ PRIMARY KEY (duel_id)
+);
+
+
+CREATE TABLE "events" (
+ event_id varchar(32) NOT NULL,
+ "name" varchar(255) NOT NULL,
+ handle varchar(255) DEFAULT NULL,
+ description text,
+ PRIMARY KEY (event_id)
+);
+
+
+CREATE TABLE factions (
+ faction_id varchar(32) NOT NULL,
+ "name" varchar(255) NOT NULL,
+ power smallint NOT NULL DEFAULT 0,
+ PRIMARY KEY (faction_id)
+);
+
+
+CREATE TABLE faction_ranks (
+ faction_id varchar(32) NOT NULL,
+ rank_id tinyint NOT NULL,
+ min_points smallint NOT NULL DEFAULT 1,
+ title_id varchar(32) DEFAULT NULL,
+ PRIMARY KEY (faction_id,rank_id)
+);
+
+
+CREATE TABLE inventory (
+ inventory_id int NOT NULL AUTO_INCREMENT,
+ character_id int NOT NULL,
+ item_id varchar(32) NOT NULL,
+ "status" enum('inventory','storage') NOT NULL DEFAULT 'inventory',
+ flags set('bound','identified') NOT NULL,
+ equipped enum('hand_a','hand_b','armor','helmet','gloves','boots','pendant','accesory_a','accesory_b') DEFAULT NULL,
+ PRIMARY KEY (inventory_id),
+ KEY sort (character_id,"status")
+);
+
+
+CREATE TABLE items (
+ item_id varchar(32) NOT NULL,
+ "name" varchar(255) NOT NULL,
+ "type" enum('weapon1h','weapon2h','armor','helmet','gloves','boots','pendant','accesory','item') NOT NULL DEFAULT 'item',
+ "value" int NOT NULL DEFAULT 0,
+ suggested_value float NOT NULL DEFAULT 0,
+ damage_type enum('p','m') DEFAULT NULL,
+ special_type varchar(32) DEFAULT NULL,
+ special_param varchar(255) DEFAULT NULL,
+ pstr_p smallint NOT NULL DEFAULT 0,
+ pstr_c smallint NOT NULL DEFAULT 0,
+ patk_p smallint NOT NULL DEFAULT 0,
+ patk_c smallint NOT NULL DEFAULT 0,
+ pdef_p smallint NOT NULL DEFAULT 0,
+ pdef_c smallint NOT NULL DEFAULT 0,
+ pres_p smallint NOT NULL DEFAULT 0,
+ pres_c smallint NOT NULL DEFAULT 0,
+ mstr_p smallint NOT NULL DEFAULT 0,
+ mstr_c smallint NOT NULL DEFAULT 0,
+ matk_p smallint NOT NULL DEFAULT 0,
+ matk_c smallint NOT NULL DEFAULT 0,
+ mdef_p smallint NOT NULL DEFAULT 0,
+ mdef_c smallint NOT NULL DEFAULT 0,
+ mres_p smallint NOT NULL DEFAULT 0,
+ mres_c smallint NOT NULL DEFAULT 0,
+ armor smallint NOT NULL DEFAULT 0,
+ speed smallint NOT NULL DEFAULT 0,
+ regen smallint NOT NULL DEFAULT 0,
+ description text,
+ PRIMARY KEY (item_id)
+);
+
+
+CREATE TABLE item_specials (
+ special_id varchar(32) NOT NULL,
+ "name" varchar(255) NOT NULL,
+ handle varchar(255) DEFAULT NULL,
+ description text,
+ PRIMARY KEY (special_id)
+);
+
+
+CREATE TABLE item_templates (
+ id varchar(32) NOT NULL,
+ "name" varchar(255) NOT NULL,
+ pstr_p_p smallint NOT NULL DEFAULT 1,
+ pstr_p_m smallint NOT NULL DEFAULT 1,
+ pstr_c_p smallint NOT NULL DEFAULT 1,
+ pstr_c_m smallint NOT NULL DEFAULT 1,
+ patk_p_p smallint NOT NULL DEFAULT 1,
+ patk_p_m smallint NOT NULL DEFAULT 1,
+ patk_c_p smallint NOT NULL DEFAULT 1,
+ patk_c_m smallint NOT NULL DEFAULT 1,
+ pdef_p_p smallint NOT NULL DEFAULT 1,
+ pdef_p_m smallint NOT NULL DEFAULT 1,
+ pdef_c_p smallint NOT NULL DEFAULT 1,
+ pdef_c_m smallint NOT NULL DEFAULT 1,
+ pres_p_p smallint NOT NULL DEFAULT 1,
+ pres_p_m smallint NOT NULL DEFAULT 1,
+ pres_c_p smallint NOT NULL DEFAULT 1,
+ pres_c_m smallint NOT NULL DEFAULT 1,
+ mstr_p_p smallint NOT NULL DEFAULT 1,
+ mstr_p_m smallint NOT NULL DEFAULT 1,
+ mstr_c_p smallint NOT NULL DEFAULT 1,
+ mstr_c_m smallint NOT NULL DEFAULT 1,
+ matk_p_p smallint NOT NULL DEFAULT 1,
+ matk_p_m smallint NOT NULL DEFAULT 1,
+ matk_c_p smallint NOT NULL DEFAULT 1,
+ matk_c_m smallint NOT NULL DEFAULT 1,
+ mdef_p_p smallint NOT NULL DEFAULT 1,
+ mdef_p_m smallint NOT NULL DEFAULT 1,
+ mdef_c_p smallint NOT NULL DEFAULT 1,
+ mdef_c_m smallint NOT NULL DEFAULT 1,
+ mres_p_p smallint NOT NULL DEFAULT 1,
+ mres_p_m smallint NOT NULL DEFAULT 1,
+ mres_c_p smallint NOT NULL DEFAULT 1,
+ mres_c_m smallint NOT NULL DEFAULT 1,
+ armor_p smallint NOT NULL DEFAULT 1,
+ armor_m smallint NOT NULL DEFAULT 1,
+ speed_p smallint NOT NULL DEFAULT 1,
+ speed_m smallint NOT NULL DEFAULT 1,
+ regen_p smallint NOT NULL DEFAULT 1,
+ regen_m smallint NOT NULL DEFAULT 1,
+ PRIMARY KEY (id)
+);
+
+
+CREATE TABLE locations (
+ location_id varchar(32) NOT NULL,
+ "name" varchar(255) NOT NULL,
+ "type" enum('normal','arena','caern','boss') NOT NULL DEFAULT 'normal',
+ chance1 smallint NOT NULL DEFAULT 1,
+ chance2 smallint NOT NULL DEFAULT 1,
+ region_id varchar(32) DEFAULT NULL,
+ faction_id varchar(32) DEFAULT NULL,
+ faction_value tinyint NOT NULL DEFAULT 1,
+ description text,
+ picture_url tinytext,
+ boss_id varchar(32) DEFAULT NULL,
+ boss_status enum('hidden','active','defeated') DEFAULT NULL,
+ PRIMARY KEY (location_id),
+ KEY region_id (region_id,location_id),
+ KEY faction_id (faction_id,location_id),
+ KEY "type" ("type",location_id)
+);
+
+
+CREATE TABLE location_events (
+ location_id varchar(32) NOT NULL,
+ event_id varchar(32) NOT NULL,
+ chance smallint NOT NULL DEFAULT 1,
+ params varchar(255) NOT NULL DEFAULT '',
+ PRIMARY KEY (location_id,event_id),
+ KEY event_id (event_id,location_id)
+);
+
+
+CREATE TABLE location_monsters (
+ location_id varchar(32) NOT NULL,
+ monster_id varchar(32) NOT NULL,
+ chance smallint NOT NULL DEFAULT 1,
+ PRIMARY KEY (location_id,monster_id),
+ KEY monster_id (monster_id,location_id)
+);
+
+
+CREATE TABLE location_paths (
+ location_id varchar(32) NOT NULL,
+ destination_id varchar(32) NOT NULL,
+ "name" varchar(255) DEFAULT NULL,
+ cost_gold int NOT NULL DEFAULT 0,
+ cost_mana smallint NOT NULL DEFAULT 0,
+ PRIMARY KEY (location_id,destination_id),
+ KEY destination_id (destination_id,location_id)
+);
+
+
+CREATE TABLE location_services (
+ location_id varchar(32) NOT NULL,
+ service_id varchar(32) NOT NULL,
+ PRIMARY KEY (location_id,service_id)
+);
+
+
+CREATE TABLE mail (
+ message_id int NOT NULL AUTO_INCREMENT,
+ date_added timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ sender_id int DEFAULT NULL,
+ recipient_id int NOT NULL,
+ content text NOT NULL,
+ PRIMARY KEY (message_id),
+ KEY sort (recipient_id,message_id)
+);
+
+
+CREATE TABLE maps (
+ map_id varchar(32) NOT NULL,
+ "name" varchar(255) NOT NULL,
+ url varchar(255) NOT NULL,
+ sort smallint NOT NULL DEFAULT 0,
+ PRIMARY KEY (map_id)
+);
+
+
+CREATE TABLE monsters (
+ monster_id varchar(32) NOT NULL,
+ "name" varchar(255) NOT NULL,
+ class smallint NOT NULL DEFAULT 1,
+ "level" smallint NOT NULL DEFAULT 1,
+ gold int NOT NULL DEFAULT 0,
+ chance1 smallint NOT NULL DEFAULT 1,
+ chance2 smallint NOT NULL DEFAULT 1,
+ title_id varchar(255) DEFAULT NULL,
+ combat_unit_id varchar(32) DEFAULT NULL,
+ PRIMARY KEY (monster_id)
+);
+
+
+CREATE TABLE monster_drops (
+ monster_id varchar(32) NOT NULL,
+ item_id varchar(32) NOT NULL,
+ chance smallint NOT NULL DEFAULT 1,
+ PRIMARY KEY (monster_id,item_id)
+);
+
+
+CREATE TABLE newsfeed (
+ id varchar(255) NOT NULL,
+ updated timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ published timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
+ title varchar(255) DEFAULT NULL,
+ author varchar(255) DEFAULT NULL,
+ content text,
+ PRIMARY KEY (id),
+ KEY published (published)
+);
+
+
+CREATE TABLE parameters (
+ "name" varchar(255) NOT NULL,
+ "value" text NOT NULL,
+ PRIMARY KEY ("name")
+);
+
+
+CREATE TABLE players (
+ player_id int NOT NULL AUTO_INCREMENT,
+ "name" varchar(255) DEFAULT NULL,
+ login varchar(255) NOT NULL,
+ "password" varchar(255) NOT NULL,
+ date_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ last_login datetime DEFAULT NULL,
+ roles set('chat','login') NOT NULL DEFAULT 'chat,login',
+ skin varchar(255) DEFAULT NULL,
+ email varchar(255) DEFAULT NULL,
+ reset_key varchar(255) DEFAULT NULL,
+ reset_until date DEFAULT NULL,
+ reset_password varchar(255) DEFAULT NULL,
+ PRIMARY KEY (player_id),
+ UNIQUE KEY login (login),
+ KEY reset_key (reset_key)
+);
+
+
+CREATE TABLE regions (
+ region_id varchar(32) NOT NULL,
+ "name" varchar(255) NOT NULL,
+ respawn_id varchar(32) DEFAULT NULL,
+ picture_url tinytext,
+ PRIMARY KEY (region_id)
+);
+
+
+CREATE TABLE rollovers (
+ rollover_id smallint NOT NULL AUTO_INCREMENT,
+ date_added timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ players_total smallint NOT NULL DEFAULT 0,
+ characters_total smallint NOT NULL DEFAULT 0,
+ clans_total smallint DEFAULT NULL,
+ PRIMARY KEY (rollover_id)
+);
+
+
+CREATE TABLE services (
+ service_id varchar(32) NOT NULL,
+ "type" enum('bank','healer','npc','shop','temple') NOT NULL,
+ "name" varchar(255) NOT NULL,
+ faction_id varchar(32) DEFAULT NULL,
+ rank_id tinyint DEFAULT NULL,
+ description text,
+ PRIMARY KEY (service_id)
+);
+
+
+CREATE TABLE service_items (
+ service_id varchar(32) NOT NULL,
+ item_id varchar(32) NOT NULL,
+ "type" enum('normal','drop') NOT NULL DEFAULT 'normal',
+ quantity smallint DEFAULT NULL,
+ PRIMARY KEY (service_id,item_id),
+ KEY item_id (item_id,service_id)
+);
+
+
+CREATE TABLE spells (
+ spell_id varchar(32) NOT NULL,
+ "name" varchar(255) NOT NULL,
+ max_level tinyint NOT NULL DEFAULT 7,
+ max_cost smallint NOT NULL DEFAULT 10,
+ min_cost smallint NOT NULL DEFAULT 1,
+ handle varchar(255) DEFAULT NULL,
+ PRIMARY KEY (spell_id)
+);
+
+INSERT INTO spells (spell_id, `name`, max_level, max_cost, min_cost, handle) VALUES
+('identify', 'Identyfikacja', 6, 45, 25, 'Identify'),
+('scout', 'Badanie Terenu', 4, 35, 20, 'Scout'),
+('vchar', 'Poznanie Postaci', 7, 60, 30, 'ScanCharacter'),
+('vitem', 'Poznanie Przedmiotu', 6, 40, 20, 'ScanItem'),
+('vmonster', 'Poznanie Potwora', 5, 40, 20, 'ScanMonster');
+
+CREATE TABLE titles (
+ title_id varchar(32) NOT NULL,
+ name_f varchar(255) NOT NULL DEFAULT '',
+ name_m varchar(255) NOT NULL DEFAULT '',
+ name_n varchar(255) NOT NULL DEFAULT '',
+ "type" enum('normal','special') NOT NULL DEFAULT 'normal',
+ PRIMARY KEY (title_id),
+ KEY "type" ("type",title_id)
+);
diff --git a/2013/daemon/lib/daemon.php b/2013/daemon/lib/daemon.php
new file mode 100644
index 0000000..3d3824c
--- /dev/null
+++ b/2013/daemon/lib/daemon.php
@@ -0,0 +1,102 @@
+dbHost, $cfg->dbSchema);
+ $params = array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8', time_zone = '+1:00'");
+ $dbh = new PDO($dsn, $cfg->dbUser, $cfg->dbPassword, $params);
+ $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+ return new Daemon_DbClient($dbh);
+ }
+
+
+ //prepares multiline text for displaying, also inserts some basic tags
+ public static function formatMessage($txt, $markup = false)
+ {
+ $txt = nl2br(htmlspecialchars($txt, ENT_QUOTES));
+ if($markup)
+ {
+ $txt = preg_replace('@\[img\](.+)\[/img\]@uU', ' ', $txt);
+ $txt = preg_replace('@\[url=(.+)\](.+)\[/url\]@uU', '$2 ', $txt);
+ $txt = preg_replace('@\[url\]([img]){0}(.+)\[/url\]@uU', '$1 ', $txt);
+ $txt = preg_replace('@(^|>|\s)(https://\S+)($|<|\s)@muU', '$1$2 $3', $txt);
+ $txt = preg_replace('@(^|>|\s)(http://\S+)($|<|\s)@muU', '$1$2 $3', $txt);
+ $txt = preg_replace('@\[b\](.+)\[/b\]@uU', '$1 ', $txt);
+ $txt = preg_replace('@\[i\](.+)\[/i\]@uU', '$1 ', $txt);
+ $txt = preg_replace('@\[u\](.+)\[/u\]@uU', '$1 ', $txt);
+ $txt = preg_replace('@\[s\](.+)\[/s\]@uU', '$1 ', $txt);
+ $txt = preg_replace('@\[sub\](.+)\[/sub\]@uU', '$1 ', $txt);
+ $txt = preg_replace('@\[sup\](.+)\[/sup\]@uU', '$1 ', $txt);
+ }
+ return $txt;
+ }
+
+
+ //returns value from array, or defaults if it doesn't exist
+ public static function getArrayValue(array $a, $name, $default = null)
+ {
+ return isset($a[$name]) ? $a[$name] : $default;
+ }
+
+
+ //implodes whitespace, optionally preserving newlines
+ public static function normalizeString($string, $preserveNewlines = false)
+ {
+ $string = str_replace(array("\r\n","\r"), "\n", $string); //unix newlines
+ if($preserveNewlines)
+ $string = preg_replace('/[^\S\n]+/', ' ', $string);
+ else $string = preg_replace('/\s+/', ' ', $string);
+ $string = trim($string);
+ return $string;
+ }
+
+
+ //generates a password hash
+ public static function passwordHash($salt, $text)
+ {
+ return sha1($salt . $text);
+ }
+
+
+ //returns random salt for password hashing
+ public static function passwordSalt()
+ {
+ $c0 = ord('0');
+ $cA = ord('a');
+ $cZ = ord('z');
+ $max = 10+$cZ-$cA;
+ $salt = '';
+ for($i = 0; $i < 8; ++$i)
+ {
+ $x = mt_rand(0, $max);
+ if($x < 10)
+ $salt .= chr($c0 + $x);
+ else $salt .= chr($cA + $x - 10);
+ }
+ return $salt;
+ }
+
+
+ //redirects to selected url
+ public static function redirect($url)
+ {
+ session_write_close(); //just in case
+ header('Content-Type: text/html; charset=UTF-8');
+ header(sprintf('Location: %s', $url), true, 303); //"See Other" status
+ printf('Redirect continue
', $url);
+ }
+}
diff --git a/2013/daemon/lib/daemon/bosscombat.php b/2013/daemon/lib/daemon/bosscombat.php
new file mode 100644
index 0000000..fd272d0
--- /dev/null
+++ b/2013/daemon/lib/daemon/bosscombat.php
@@ -0,0 +1,100 @@
+getLocation($locationId);
+ $bossFactionId = $location['faction_id'];
+ $powerMod = Daemon_Math::factionPowerMult($bossFactionId, $factionPowers);
+ //prepare units
+ $this->kickNeutrals($locationId);
+ $units = $this->getCharacterUnits($locationId);
+ //check for empty caern
+ if(empty($units))
+ return null;
+ $attackers = false;
+ foreach($units as $factionId => $faction)
+ {
+ if($factionId != $bossFactionId)
+ $attackers = true;
+ }
+ if(!$attackers)
+ return null;
+ unset($attackers, $factionId, $faction);
+ //prepare boss
+ $boss = $this->getBossUnit($location['boss_id'], $bossFactionId, $powerMod);
+ if(empty($boss))
+ return null;
+ $units[$bossFactionId][$boss->_id] = $boss;
+ //add monster support
+ $supportCount = 0;
+ foreach($units as $factionId => $faction)
+ {
+ if($factionId != $bossFactionId)
+ $supportCount += count($faction);
+ else
+ $supportCount -= count($faction);
+ }
+ if($supportCount > 0)
+ {
+ $support = $this->getLocationMonsters($locationId, $bossFactionId, $supportCount);
+ foreach($support as $unit)
+ $units[$bossFactionId][$unit->_id] = $unit;
+ }
+ unset($support, $supportCount);
+ //execute combat
+ $this->combatLog = $this->runCombat($units, $bossFactionId);
+ //save characters
+ $this->putCharacterUnits($units);
+ //find winner
+ $winnerId = $this->getWinnerFaction($units);
+ //kick losers
+ $this->kickEnemies($locationId, $winnerId);
+ //update location, send message
+ if($winnerId != $bossFactionId)
+ {
+ $sql = "UPDATE locations SET boss_status='defeated' WHERE location_id=:id";
+ $params = array('id' => $locationId);
+ $this->dbClient->query($sql, $params);
+ $msg = "Boss $boss->name z lokacji $location[name] został pokonany!";
+ $forum = new Daemon_Forum($this->dbClient);
+ $forum->addChat(null, 'public', $msg);
+ }
+ }
+
+
+ private function getBossUnit($monsterId, $factionId, $powerMod)
+ {
+ //read base stats
+ $sql = "SELECT monster_id, name, combat_unit_id
+ FROM monsters WHERE monster_id=:id";
+ $row = $this->dbClient->selectRow($sql, array('id' => $monsterId));
+ $unit = new Daemon_Combat_Unit();
+ $unit->attachDbClient($this->dbClient);
+ $unit->get(array('combat_unit_id' => $row['combat_unit_id']));
+ $unit->name = $row['name'];
+ $unit->faction_id = $factionId;
+ $unit->_id = 'boss';
+ //modify stats
+ $modified = array(
+ 'str1', 'atk1', 'str2', 'atk2',
+ 'pdef', 'pres', 'mdef', 'mres',
+ 'speed', 'armor', 'regen', 'healthMax',
+ );
+ foreach($modified as $name)
+ $unit->$name *= $powerMod;
+ $unit->health = $unit->healthMax;
+ return $unit;
+ }
+
+
+ private function getLocation($locationId)
+ {
+ $sql = "SELECT l.faction_id, l.boss_id, l.name, f.name AS faction_name
+ FROM locations l JOIN factions f USING(faction_id)
+ WHERE location_id = :id";
+ return $this->dbClient->selectRow($sql, array('id' => $locationId));
+ }
+}
diff --git a/2013/daemon/lib/daemon/caernsiege.php b/2013/daemon/lib/daemon/caernsiege.php
new file mode 100644
index 0000000..312bb43
--- /dev/null
+++ b/2013/daemon/lib/daemon/caernsiege.php
@@ -0,0 +1,270 @@
+ $faction)
+ {
+ foreach($faction as $unit)
+ {
+ $attacker = ($factionId != $locationFactionId);
+ $combat->addUnit($unit->_id, $unit, $attacker);
+ }
+ }
+ }
+
+
+ public function attachDbClient(Daemon_DbClient $dbClient)
+ {
+ $this->dbClient = $dbClient;
+ }
+
+
+ //executes the siege, generates the report
+ public function execute($locationId)
+ {
+ //prepare units
+ $this->kickNeutrals($locationId);
+ $faction = $this->getLocationFaction($locationId);
+ $caernFactionId = $faction['id'];
+ $units = $this->getCharacterUnits($locationId);
+ //check for empty caern
+ if(empty($units))
+ {
+ $this->combatLog = 'Caern utracony z braku obrońców.
';
+ $winnerId = null;
+ }
+ else
+ {
+ //add monster support
+ $supportCount = 0;
+ foreach($units as $factionId => $faction)
+ {
+ if($factionId != $caernFactionId)
+ $supportCount += count($faction);
+ else
+ $supportCount -= count($faction);
+ }
+ if($supportCount > 0)
+ {
+ $support = $this->getLocationMonsters($locationId, $caernFactionId, $supportCount);
+ foreach($support as $unit)
+ $units[$caernFactionId][$unit->_id] = $unit;
+ }
+ unset($support, $supportCount);
+ //execute combat
+ $this->combatLog = $this->runCombat($units, $caernFactionId);
+ //save characters
+ $this->putCharacterUnits($units);
+ //find winner (units modified by combat)
+ $winnerId = $this->getWinnerFaction($units);
+ if(!$winnerId)
+ $msg = 'utracony';
+ elseif($winnerId != $caernFactionId)
+ $msg = 'przejęty';
+ else
+ $msg = 'utrzymany';
+ $this->combatLog .= "Caern $msg!
";
+ }
+ //kick losers
+ $this->kickEnemies($locationId, $winnerId);
+ //update location
+ $sql = "UPDATE locations SET faction_id=:fid WHERE location_id=:id";
+ $params = array('fid' => $winnerId, 'id' => $locationId);
+ $this->dbClient->query($sql, $params);
+ }
+
+
+ protected function getCharacterUnits($locationId)
+ {
+ $units = array();
+ $sql = "SELECT cd.character_id, c.name, cd.faction_id, cd.health, cd.health_max, cd.combat_unit_id
+ FROM character_data cd JOIN characters c USING(character_id)
+ WHERE location_id=:id AND cd.faction_id IS NOT NULL ORDER BY xp_used DESC";
+ $data = $this->dbClient->selectAll($sql, array('id' => $locationId));
+ foreach($data as $row)
+ {
+ $unit = new Daemon_Combat_Unit();
+ $unit->attachDbClient($this->dbClient);
+ $unit->get(array('combat_unit_id' => $row['combat_unit_id']));
+ $unit->name = $row['name'];
+ $unit->faction_id = $row['faction_id'];
+ $unit->health = $row['health_max'];
+ $unit->health_max = $row['health_max'];
+ $unit->_id = $row['character_id'];
+ $units[$row['faction_id']][$unit->_id] = $unit;
+ }
+ return $units;
+ }
+
+
+ public function getCombatLog()
+ {
+ return $this->combatLog;
+ }
+
+
+ protected function getLocationFaction($locationId)
+ {
+ $sql = "SELECT faction_id AS id, f.name
+ FROM locations l JOIN factions f USING(faction_id)
+ WHERE location_id=:id";
+ return $this->dbClient->selectRow($sql, array('id' => $locationId));
+ }
+
+
+ protected function getLocationMonsters($locationId, $factionId, $desiredCount)
+ {
+ $result = array();
+ $sql = "SELECT m.monster_id, m.name, m.combat_unit_id
+ FROM location_monsters lm JOIN monsters m USING(monster_id)
+ WHERE location_id=:id";
+ $mobs = $this->dbClient->selectAll($sql, array('id' => $locationId));
+ if(empty($mobs))
+ return array();
+ for($i = 0; $i < $desiredCount; ++$i)
+ {
+ $row = $mobs[array_rand($mobs)];
+ $unit = new Daemon_Combat_Unit();
+ $unit->attachDbClient($this->dbClient);
+ $unit->get(array('combat_unit_id' => $row['combat_unit_id']));
+ $unit->name = $row['name'];
+ $unit->faction_id = $factionId;
+ $unit->_id = "mob_$i";
+ $result[$unit->_id] = $unit;
+ }
+ return $result;
+ }
+
+
+ protected function getWinnerFaction(array $units)
+ {
+ $survivors = array();
+ foreach($units as $factionId => $faction)
+ {
+ $survivors[$factionId] = 0;
+ foreach($faction as $unit)
+ {
+ if($unit->health > 0)
+ $survivors[$unit->faction_id] += 1;
+ }
+ }
+ $winnerId = null;
+ $winnerCount = 0;
+ foreach($survivors as $factionId => $count)
+ {
+ if($winnerCount < $count)
+ {
+ $winnerId = $factionId;
+ $winnerCount = $count;
+ }
+ }
+ return $winnerId;
+ }
+
+
+ //kicks enemies out of the caern
+ public function kickEnemies($locationId, $factionId)
+ {
+ $sql = "UPDATE character_data SET location_id=NULL WHERE location_id=:locationId";
+ $params = array('locationId' => $locationId);
+ if($factionId)
+ {
+ $sql .= " AND faction_id!=:factionId";
+ $params['factionId'] = $factionId;
+ }
+ $this->dbClient->query($sql, $params);
+ }
+
+
+ //kicks neutral characters out of the caern
+ protected function kickNeutrals($locationId)
+ {
+ $sql = "UPDATE character_data SET location_id=NULL WHERE location_id=:id AND faction_id IS NULL";
+ $this->dbClient->query($sql, array('id' => $locationId));
+ }
+
+
+ protected function putCharacterUnits(array $units)
+ {
+ $sqlLive = "UPDATE character_data SET health=:hp WHERE character_id=:id";
+ $sqlDie = "UPDATE character_data SET health=0, location_id=null WHERE character_id=:id";
+ foreach($units as $faction)
+ {
+ foreach($faction as $unit)
+ {
+ if(!is_numeric($unit->_id))
+ continue;//monsters have string IDs
+ if($unit->health > 0)
+ {
+ $params = array('id' => $unit->_id, 'hp' => $unit->health);
+ $this->dbClient->query($sqlLive, $params);
+ }
+ else
+ {
+ $params = array('id' => $unit->_id);
+ $this->dbClient->query($sqlDie, $params);
+ }
+ }
+ }
+ }
+
+
+ public function runCombat(array $units, $locationFactionId)
+ {
+ $combat = new Daemon_Combat();
+ $logger = new Daemon_Combat_Log();
+ $combat->attachLogger($logger);
+ foreach($units as $factionId => $faction)
+ {
+ foreach($faction as $unit)
+ {
+ $attacker = ($factionId != $locationFactionId);
+ $combat->addUnit($unit->_id, $unit, $attacker);
+ }
+ }
+ $combat->execute();
+ foreach($combat->units as &$unit)
+ $unit->health = max(0, ceil($unit->health));
+ //prepare summary
+ $summary = array();
+ $summary[] = '';
+ $summary[] = 'Podsumowanie bitwy ';
+ $summary[] = '';
+ $summary[] = 'Strona Postać ';
+ $summary[] = 'Wykonane ataki Otrzymane ataki ';
+ $summary[] = ' ';
+ $summary[] = '';
+ $summary[] = 'Imię Frakcja Zdrowie ';
+ $summary[] = 'Ataki Obrażenia Średnia ';
+ $summary[] = 'Ataki Obrażenia Średnia ';
+ $summary[] = ' ';
+ foreach($units as $factionId => $faction)
+ {
+ foreach($faction as $unit)
+ {
+ $attackerTxt = $unit->_attacker ? 'atak' : 'obrona';
+ $dmgTotal = $unit->_dmgDealt + $unit->_dmgTaken;
+ $health = max(0, ceil($unit->health_max - $unit->_dmgTaken));
+ $healthPercent = $unit->health_max ? round(100 * $health / $unit->health_max, 2) : 0;
+ $avgDealt = $unit->_cntDealt ? $unit->_dmgDealt / $unit->_cntDealt : null;
+ $avgTaken = $unit->_cntTaken ? $unit->_dmgTaken / $unit->_cntTaken : null;
+ $summary[] = '';
+ $summary[] = sprintf('%s %s %s %.2f%% ',
+ $attackerTxt, $unit->name, $unit->faction_id, $healthPercent);
+ $summary[] = sprintf('%d %.3f %.3f ',
+ $unit->_cntDealt, $unit->_dmgDealt, $avgDealt);
+ $summary[] = sprintf('%d %.3f %.3f ',
+ $unit->_cntTaken, $unit->_dmgTaken, $avgTaken);
+ $summary[] = ' ';
+ }
+ }
+ $summary[] = '
';
+ return implode('', $summary) . (string) $logger;
+ }
+}
diff --git a/2013/daemon/lib/daemon/combat.php b/2013/daemon/lib/daemon/combat.php
new file mode 100644
index 0000000..a1134a9
--- /dev/null
+++ b/2013/daemon/lib/daemon/combat.php
@@ -0,0 +1,164 @@
+attachLogger($logger);
+//$combat->addUnit('a', $unit1, true);
+//$combat->addUnit('b', $unit2, false);
+//$combat->execute();
+//$combatLog = (string) $logger;
+class Daemon_Combat
+{
+ public $units = array();
+ public $sideA = array();
+ public $sideB = array();
+ public $round = 0;
+ public $roundLimit = 120;
+ public $tickLimit = 1;
+ private $_logger = null;
+
+
+ public function addUnit($unitId, Daemon_Combat_Unit $unit, $attacker)
+ {
+ $unit->attachLogger($this->_logger);
+ $unit->_id = $unitId;
+ $unit->_ticks = 0;
+ $unit->_initiative = mt_rand(0, 32 * $unit->speed);
+ $unit->_target = null;
+ $unit->_threat = array();
+ $unit->_dmgDealt = 0;
+ $unit->_dmgTaken = 0;
+ $this->units[$unitId] = $unit;
+ $unit->_attacker = (bool) $attacker;
+ if($unit->_attacker)
+ {
+ $this->sideA[$unitId] = $unit;
+ $unit->_allies = &$this->sideA;
+ $unit->_enemies = &$this->sideB;
+ }
+ else
+ {
+ $this->sideB[$unitId] = $unit;
+ $unit->_allies = &$this->sideB;
+ $unit->_enemies = &$this->sideA;
+ }
+ }
+
+
+ public function attachLogger(Daemon_Combat_Log $logger)
+ {
+ $this->_logger = $logger;
+ foreach($this->units as $unit)
+ $unit->attachLogger($logger);
+ }
+
+
+ protected function callbackActive($unit)
+ {
+ return $unit->_ticks > $this->tickLimit;
+ }
+
+
+ protected function callbackSpeedSum($prev, $unit)
+ {
+ return $prev + $unit->speed;
+ }
+
+
+ protected function callbackTickCompare($unit1, $unit2)
+ {
+ if($unit1->_ticks == $unit2->_ticks)
+ return $unit1->_initiative - $unit2->_initiative;
+ else return ($unit1->_ticks < $unit2->_ticks) ? -1 : +1;
+ }
+
+
+ protected function callbackTickInc($unit, $key)
+ {
+ if($unit->health > 0)
+ $unit->_ticks += $unit->speed;
+ else $unit->_ticks = null;
+ }
+
+
+ protected function debug($round, array $units)
+ {
+ if($this->_logger)
+ {
+ $result = array("Segment $round");
+ foreach($units as $unit)
+ $result[] = (string) $unit;
+ $this->_logger->add($result);
+ }
+ }
+
+
+ public function execute($noCleanup = false)
+ {
+ if(!$this->units)
+ return;
+ $unitCount = count($this->units);
+ if ($this->_logger)
+ $this->_logger->groupCombat = ($unitCount > 2);
+ $round = 0;
+ $roundLimit = 100 + 10 * $unitCount;
+ $speedSum = array_reduce($this->units, array($this, 'callbackSpeedSum'), 0);
+ $this->tickLimit = 1 + ceil(2 * $speedSum / count($this->units));
+ while($round < $roundLimit)
+ {
+ $victory = false;
+ array_walk($this->units, array($this, 'callbackTickInc'));
+ while($actor = $this->getActiveUnit())
+ {
+ ++$round;
+ $actor->_ticks -= $this->tickLimit;
+ $actor->executeRound($round);
+ //victory check, sides should be updated by units
+ $victory = (!count($this->sideA) || !count($this->sideB));
+ if($victory)
+ break;
+ }
+ if($victory)
+ break;
+ }
+ //after-combat regen & fixes
+ if (!$noCleanup)
+ {
+ foreach($this->units as $unit)
+ {
+ if ($unit->health < 1)
+ {
+ $unit->health = 0;
+ }
+ elseif (($unit->regen > 0) && ($unit->health < $unit->health_max))
+ {
+ $unit->health = $unit->health_max;
+ if($this->_logger)
+ $this->_logger->add("$unit->name regeneruje pełnię zdrowia. ");
+ }
+ else
+ {
+ $unit->health = Daemon_Math::round($unit->health);
+ }
+ }
+ }
+ }
+
+
+ protected function getActiveUnit()
+ {
+ $active = array_filter($this->units, array($this, 'callbackActive'));
+ uasort($active, array($this, 'callbackTickCompare'));
+ return array_pop($active);
+ }
+
+
+ public function reset()
+ {
+ $this->units = array();
+ $this->sideA = array();
+ $this->sideB = array();
+ }
+}
diff --git a/2013/daemon/lib/daemon/combat/log.php b/2013/daemon/lib/daemon/combat/log.php
new file mode 100644
index 0000000..0c7708d
--- /dev/null
+++ b/2013/daemon/lib/daemon/combat/log.php
@@ -0,0 +1,117 @@
+clear();
+ }
+
+
+ public function __toString()
+ {
+ return $this->buffer;
+ }
+
+
+ public function add($text)
+ {
+ $this->buffer .= "$text\n";
+ }
+
+
+ public function clear()
+ {
+ $this->buffer = '';
+ }
+
+
+ public static function escape($str)
+ {
+ return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
+ }
+
+
+ public function txtAttackHit($name, $dmg, $magical, $critical, $poison, $shockDmg, $stun, $vampRegen)
+ {
+ $txt = $critical ? 'Trafienie krytyczne! ' : '';
+ $txt .= sprintf('%s zadaje %.2f obrażeń %s', self::escape($name),
+ $dmg, $magical ? 'magicznych' : 'fizycznych');
+ if($poison)
+ $txt .= ', zatruwając cel';
+ if($stun)
+ $txt .= ', ogłuszając cel';
+ if($vampRegen)
+ $txt .= sprintf(', regenerując %.2f HP', $vampRegen);
+ if($shockDmg)
+ $txt .= sprintf('. Otrzymuje %.2f obrażeń od porażenia', $shockDmg);
+ $txt .= '. ';
+ $this->add($txt);
+ }
+
+
+ public function txtAttackMiss($name, $magical)
+ {
+ if($magical)
+ $this->add('Cel odbił zaklęcie. ');
+ else $this->add(sprintf('%s chybił. ', self::escape($name)));
+ }
+
+
+ public function txtDeath($name, $flawlessName = null)
+ {
+ $txt = sprintf('%s umiera. ', $name);
+ if($flawlessName)
+ {
+ $atxt = array('%s ziewa.', '%s śmieje się szyderczo.');
+ $txt .= sprintf($atxt[array_rand($atxt)], self::escape($flawlessName)).' ';
+ }
+ $this->add($txt);
+ }
+
+
+ public function txtDemon($regen)
+ {
+ $this->add(sprintf('Demon w zbroi wchłonął zaklęcie. Cel regeneruje %.2f obrażeń. ', $regen));
+ }
+
+
+ public function txtPoison($name, $dmg)
+ {
+ $this->add(sprintf('%s otrzymuje %.2f obrażeń od trucizny. ', self::escape($name), $dmg));
+ }
+
+
+ public function txtRegen($name, $regen)
+ {
+ $this->add(sprintf('%s regeneruje %.2f obrażeń. ', self::escape($name), $regen));
+ }
+
+
+ public function txtRoundFooter()
+ {
+ $this->add('
');
+ }
+
+
+ public function txtRoundHeader($round)
+ {
+ $this->add(sprintf('Akcja %d ', $round));
+ }
+
+
+ public function txtTargetHeader($actorName, $targetName)
+ {
+ if($targetName)
+ {
+ if ($this->groupCombat)
+ $this->add(sprintf('%s wybiera cel: %s . ',
+ self::escape($actorName), self::escape($targetName)));
+ }
+ else $this->add(sprintf('%s nie ma już przeciwników. ', self::escape($actorName)));
+ }
+}
diff --git a/2013/daemon/lib/daemon/combat/unit.php b/2013/daemon/lib/daemon/combat/unit.php
new file mode 100644
index 0000000..37eddc2
--- /dev/null
+++ b/2013/daemon/lib/daemon/combat/unit.php
@@ -0,0 +1,261 @@
+_id, name: $this->name, ticks: $this->_ticks, health: $this->health/$this->health_max]";
+ }
+
+
+ public function attachLogger(Daemon_Combat_Log $logger = null)
+ {
+ $this->_logger = $logger;
+ }
+
+
+ protected function calculateAttack(array $params)
+ {
+ //attack count - check for swarm
+ if(self::SP_SWARM == $params['sp_type'])
+ $attackCount = ceil($params['count'] * $this->health / $this->health_max);
+ else $attackCount = $params['count'];
+ //prepare variables
+ $magical = ('m' == $params['type']);
+ if($magical)
+ {
+ $targetDef = $this->_target->mdef;
+ $targetRes = $this->_target->mres;
+ $armor = 0;
+ }
+ else
+ {
+ $targetDef = $this->_target->pdef;
+ $targetRes = $this->_target->pres;
+ $armor = $this->_target->armor;
+ if(self::SP_ETHER == $params['sp_type'])
+ $armor *= 1 - $params['sp_param']/100;
+ }
+ //calculate basic data
+ $toHit = 100 * $params['atk'] / ($params['atk'] + $targetDef);
+ $baseDmg = $params['str'] * $params['str'] / ($params['str'] + $targetRes);
+ //faction effects
+ if($this->faction_id && $this->_target->faction_id && ($this->faction_id != $this->_target->faction_id))
+ {
+ if(self::SP_FACTION == $params['sp_type'])
+ $baseDmg *= 1 + $params['sp_param']/100;
+ if(self::SP_FACTION == $this->_target->armor_sp_type)
+ $baseDmg /= 1 + $this->_target->armor_sp_param/100;
+ }
+ //execute attacks
+ for($i=0; $i < $attackCount; $i++)
+ {
+ $d100 = mt_rand(0,99);
+ //check for demon
+ $demon = $magical && (self::SP_DEMON == $this->_target->armor_sp_type);
+ if($demon && mt_rand(0,99) < $this->_target->armor_sp_param)
+ {
+ $regen = min($this->_target->health_max - $this->_target->health, $baseDmg * $this->_target->armor_sp_param / 100);
+ $this->_target->health += $regen;
+ if($this->_logger)
+ $this->_logger->txtDemon($regen);
+ }
+ //check for hit
+ elseif($d100 < $toHit)
+ {
+ //calculate damage
+ $critical = $d100>45;
+ if($critical)
+ {
+ $dmgMult = 2;
+ if(self::SP_BLOODY == $params['sp_type'])
+ $dmgMult += $params['sp_param']/100;
+ }
+ else $dmgMult = 1 + mt_rand(0,127)/256;
+ $dmg = max(0, $baseDmg * $dmgMult - $armor);
+ $this->_target->health -= $dmg;
+ //update statistics
+ $this->_target->_flawless = false;
+ $this->_target->_cntTaken += 1;
+ $this->_target->_dmgTaken += $dmg;
+ $this->_cntDealt += 1;
+ $this->_dmgDealt += $dmg;
+ //check for poison
+ if(self::SP_POISON == $params['sp_type'])
+ {
+ $poison = $dmg>0 ? $params['sp_param'] : 0;
+ if(self::SP_ANTIPOISON == $this->_target->armor_sp_type)
+ $poison *= 1 - $this->_target->armor_sp_param / 100;
+ $this->_target->_poison += $poison;
+ }
+ else $poison = 0;
+ //check for shock
+ if(self::SP_SHOCK == $this->_target->armor_sp_type)
+ {
+ $shockDmg = $dmg * $this->_target->armor_sp_param / 100;
+ $this->health -= $shockDmg;
+ }
+ else $shockDmg = 0;
+ //check for stun
+ $stun = $critical && (self::SP_STUN == $params['sp_type']);
+ if($stun)
+ $this->_target->_ticks = 0;
+ //check for vampirism
+ if(self::SP_VAMPIRE == $params['sp_type'])
+ {
+ $vampRegen = min($this->health_max - $this->health, $dmg * $params['sp_param']/100);
+ if(self::SP_ANTIVAMP == $this->_target->armor_sp_type)
+ $vampRegen *= 1 - $this->_target->armor_sp_param / 100;
+ $this->health += $vampRegen;
+ }
+ else $vampRegen = 0;
+ //print info
+ if($this->_logger)
+ {
+ $this->_logger->txtAttackHit($this->name, $dmg, $magical, $critical,
+ $poison, $shockDmg, $stun, $vampRegen);
+ }
+ }
+ else
+ {
+ if($this->_logger)
+ $this->_logger->txtAttackMiss($this->name, $magical);
+ }
+ }
+ }
+
+
+ protected function executeAttacks()
+ {
+ if(!$this->_target)
+ return;
+ $this->_target->_threat[$this->_id] = $this;
+ if($this->count1 && $this->type1)
+ {
+ $attackParams = array(
+ 'str' => $this->str1,
+ 'atk' => $this->atk1,
+ 'type' => $this->type1,
+ 'count' => $this->count1,
+ 'sp_type' => $this->sp1_type,
+ 'sp_param' => $this->sp1_param,
+ );
+ $this->calculateAttack($attackParams);
+ }
+ if($this->count2 && $this->type2)
+ {
+ $attackParams = array(
+ 'str' => $this->str2,
+ 'atk' => $this->atk2,
+ 'type' => $this->type2,
+ 'count' => $this->count2,
+ 'sp_type' => $this->sp2_type,
+ 'sp_param' => $this->sp2_param,
+ );
+ $this->calculateAttack($attackParams);
+ }
+ //check for target death
+ if($this->_target->health <= 0)
+ {
+ $this->_target->_ticks = null;
+ unset($this->_threat[$this->_target->_id]);
+ unset($this->_enemies[$this->_target->_id]);
+ if($this->_logger)
+ $this->_logger->txtDeath($this->_target->name, $this->_flawless ? $this->name : null);
+ }
+ }
+
+
+ public function executeRound($round)
+ {
+ if($this->_logger)
+ $this->_logger->txtRoundHeader($round);
+ $this->regen();
+ $this->pickTarget();
+ if($this->_target)
+ $this->executeAttacks();
+ $this->poison();
+ if($this->_logger)
+ $this->_logger->txtRoundFooter();
+ }
+
+
+ protected function pickTarget()
+ {
+ //clear old target
+ $this->_target = null;
+ //try current threat
+ while($this->_threat && !$this->_target)
+ {
+ $targetId = array_rand($this->_threat);
+ $this->_target = $this->_threat[$targetId];
+ if($this->_target->health <= 0) //killed by someone else
+ {
+ $this->_target = null;
+ unset($this->_threat[$targetId]);
+ }
+ }
+ //no threat, try other enemies
+ if($this->_enemies && !$this->_target)
+ {
+ $targetId = array_rand($this->_enemies);
+ $this->_target = $this->_enemies[$targetId];
+ }
+ //print message
+ if($this->_logger)
+ {
+ if($this->_target)
+ $this->_logger->txtTargetHeader($this->name, $this->_target->name);
+ else $this->_logger->txtTargetHeader($this->name, null);
+ }
+ }
+
+
+ protected function poison()
+ {
+ if($this->_poison)
+ {
+ $dmg = $this->_poison * $this->_poison / ($this->_poison + $this->pres);
+ $this->health -= $dmg;
+ if($this->_logger)
+ $this->_logger->txtPoison($this->name, $dmg);
+ if($this->health <= 0)
+ {
+ unset($this->_allies[$this->_id]);
+ if($this->_logger)
+ $this->_logger->txtDeath($this->name, false);
+ }
+ }
+ }
+
+
+ protected function regen()
+ {
+ if($this->regen && $this->health < $this->health_max)
+ {
+ $delta = min($this->health_max - $this->health, $this->regen);
+ $this->health += $delta;
+ if($this->_logger)
+ $this->_logger->txtRegen($this->name, $delta);
+ }
+ }
+}
diff --git a/2013/daemon/lib/daemon/config.php b/2013/daemon/lib/daemon/config.php
new file mode 100644
index 0000000..0243963
--- /dev/null
+++ b/2013/daemon/lib/daemon/config.php
@@ -0,0 +1,56 @@
+applicationRoot = (string) $applicationRoot;
+ $hostname = mb_strtolower(getenv('SERVER_NAME'));
+ if(!$hostname)
+ $hostname = '_cron';
+ $fileName = $hostname . '.php';
+ $this->loadFile($this->getFilePath('cfg', $fileName));
+ }
+
+
+ //loads config from file
+ public function loadFile($path)
+ {
+ if(is_readable($path))
+ {
+ $data = (array) include $path;
+ foreach($data as $key=>$value)
+ $this->$key = $value;
+ }
+ }
+
+
+ //implodes parameters into relative path and prepends it with root
+ public function getFilePath(/*...*/)
+ {
+ $aPath = array_filter(func_get_args());
+ array_unshift($aPath, $this->applicationRoot);
+ return implode(DIRECTORY_SEPARATOR, $aPath);
+ }
+
+
+ //generates URL from relative path
+ public function getUrl($path)
+ {
+ return $path ? "$this->applicationUrl$path" : $this->applicationUrl;
+ }
+}
diff --git a/2013/daemon/lib/daemon/controller.php b/2013/daemon/lib/daemon/controller.php
new file mode 100644
index 0000000..2a95ec6
--- /dev/null
+++ b/2013/daemon/lib/daemon/controller.php
@@ -0,0 +1,158 @@
+cfg = $cfg;
+ session_name($this->cfg->sessionName);
+ session_cache_limiter(null);
+ session_start();
+ $this->dbClient = Daemon::createDbClient($this->cfg);
+ $this->dbCfg = new Daemon_DbConfig($this->dbClient);
+ if(!$this->disablePlayer)
+ {
+ $this->player = new Daemon_DbObject_Player($this->dbClient);
+ $this->activeCharacter = $this->player->getActiveCharacter();
+ $this->activeCharacter->updateLastAction();
+ $this->characterData = $this->activeCharacter->getCharacterData();
+ $this->location = $this->characterData->getLocation();
+ }
+ $this->view = new Daemon_View($this->cfg);
+ }
+
+
+ //checks last action's timestamp
+ final private function checkActionTimestamp()
+ {
+ $lastAction = isset($_SESSION['ts']) ? $_SESSION['ts'] : 0.0;
+ $_SESSION['ts'] = microtime(true);
+ return (bool) ($_SESSION['ts'] >= $lastAction + $this->cfg->tsDelta);
+ }
+
+
+ final public function execute()
+ {
+ //prepare controller
+ $this->prepareModel();
+ $this->validatePlayer();
+ //check last action's timestamp
+ if($_POST && !$this->checkActionTimestamp())
+ {
+ Daemon_MsgQueue::add('Operacja anulowana: za duża częstość.');
+ $_POST = array();
+ }
+ //execute commands
+ $cmdExecuted = (bool) $this->runCommands();
+ //display page
+ $this->prepareView();
+ if($this->pageSubtitleUseQuery)
+ {
+ if($qs = getenv('QUERY_STRING'))
+ $this->pageSubtitleDetails = urldecode($qs);
+ }
+ $this->view->setPageTitle($this->pageSubtitle, $this->pageSubtitleDetails, $cmdExecuted);
+ if(!$this->disablePlayer)
+ {
+ $this->view->setGameHeader($this->player->getPlayerId(),
+ $this->activeCharacter, $this->characterData, $this->location);
+ $this->view->setPageSkin($this->player->skin);
+ }
+ else $this->view->setPageSkin(null);
+ if(!$this->disableMessages)
+ $messages = Daemon_MsgQueue::getAll();
+ else $messages = array();
+ if($this->dbCfg->globalMessage)
+ $messages[] = $this->dbCfg->globalMessage;
+ $this->view->setMessages($messages);
+ $this->view->display($this->pageTemplatePath, $this->pageOutputMode);
+ }
+
+
+ //page-specific
+ protected function prepareModel()
+ {
+ }
+
+
+ //page-specific
+ protected function prepareView()
+ {
+ }
+
+
+ //page-specific
+ protected function runCommands()
+ {
+ return false;
+ }
+
+
+ final private function validatePlayer()
+ {
+ if($this->disablePlayer)
+ return;
+ if($this->requireAuthentication && !$this->player->getPlayerId())
+ {
+ Daemon_MsgQueue::add('Strona dostępna tylko dla zalogowanych użytkowników.');
+ Daemon::redirect($this->cfg->getUrl(null));
+ exit;
+ }
+ if($this->requireActiveChar && !$this->player->getCharacterId())
+ {
+ Daemon_MsgQueue::add('Musisz najpierw wybrać aktywną postać.');
+ Daemon::redirect($this->cfg->getUrl('account'));
+ exit;
+ }
+ if($this->requiredRole && !$this->player->hasRole($this->requiredRole))
+ {
+ Daemon_MsgQueue::add('Nie masz uprawnień do korzystania z tej funkcji.');
+ Daemon::redirect($this->cfg->getUrl('account'));
+ exit;
+ }
+ if($this->requireLocation && !$this->location->location_id)
+ {
+ Daemon::redirect($this->cfg->getUrl('respawn'));
+ exit;
+ }
+ if($this->requireNoEvents && $this->characterData->getLocationEvent())
+ {
+ Daemon::redirect($this->cfg->getUrl('map'));
+ exit;
+ }
+ if($this->requireFactionMatch && $this->location->faction_id && $this->characterData->faction_id
+ && ($this->location->faction_id != $this->characterData->faction_id))
+ {
+ Daemon_MsgQueue::add('Odejdź! Nie przyjmujemy takich jak ty!');
+ Daemon::redirect($this->cfg->getUrl('map'));
+ exit;
+ }
+ }
+}
diff --git a/2013/daemon/lib/daemon/dbclient.php b/2013/daemon/lib/daemon/dbclient.php
new file mode 100644
index 0000000..70d49b5
--- /dev/null
+++ b/2013/daemon/lib/daemon/dbclient.php
@@ -0,0 +1,148 @@
+dbh = $dbHandle;
+ }
+
+
+ //reads maximum length of columns of selected table
+ public function getColumnMaxLength($table, $column)
+ {
+ $sql = 'SELECT CHARACTER_MAXIMUM_LENGTH FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = SCHEMA() AND TABLE_NAME = :table AND COLUMN_NAME = :column';
+ $params = array('table' => $table, 'column' => $column);
+ return $this->selectColumn($sql, $params);
+ }
+
+
+ //returns internal PDO handle
+ public function getDbHandle()
+ {
+ return $this->dbh;
+ }
+
+
+ //internal exception handler
+ private function exceptionHandler(PDOException $e, $duplicateMsg = null)
+ {
+ //prepare params
+ $sqlstate = $e->getCode();
+ $dbMessage = $e->getMessage();
+ //check error type
+ if('23000' == $sqlstate && false !== stripos($dbMessage, 'duplicate'))
+ {
+ $message = $duplicateMsg ? $duplicateMsg : 'Wybrany obiekt już istnieje.';
+ Daemon_MsgQueue::add($message);
+ }
+ else throw $e;
+ }
+
+
+ //executes a query, returns the statement resource
+ public function execute($sql, array $params = array(), $duplicateMsg = null)
+ {
+ try
+ {
+ $sth = $this->dbh->prepare($sql);
+ foreach((array)$params as $name => $value)
+ $sth->bindValue(':'.$name, $value, self::paramType($value));
+ $sth->execute();
+ return $sth;
+ }
+ catch(PDOException $e)
+ {
+ $this->exceptionHandler($e, $duplicateMsg);
+ return null;
+ }
+ }
+
+
+ //returns ID of last inserted row
+ public function lastInsertId()
+ {
+ return $this->dbh->lastInsertId();
+ }
+
+
+ //returns appriopriate PDO::PARAM_X constant
+ public static function paramType($value)
+ {
+ if(is_null($value))
+ return PDO::PARAM_NULL;
+ elseif(is_int($value))
+ return PDO::PARAM_INT;
+ else return PDO::PARAM_STR;
+ }
+
+
+ //executes a generic non-select query
+ public function query($sql, array $params = array(), $duplicateMsg = null)
+ {
+ $sth = $this->execute($sql, $params, $duplicateMsg);
+ return !is_null($sth);
+ }
+
+
+ //quotes value for safe use in query
+ public function quote($value)
+ {
+ return $this->dbh->quote($value, self::paramType($value));
+ }
+
+
+ //select multiple rows from table
+ public function selectAll($sql, array $params = array())
+ {
+ $sth = $this->execute($sql, $params);
+ if(is_null($sth))
+ return null;
+ return $sth->fetchAll(PDO::FETCH_ASSOC);
+ }
+
+
+ //select single column from table
+ public function selectColumn($sql, array $params = array())
+ {
+ $sth = $this->execute($sql, $params);
+ if(is_null($sth))
+ return null;
+ return $sth->fetchAll(PDO::FETCH_COLUMN, 0);
+ }
+
+
+ //select single row from table (as array)
+ public function selectRow($sql, array $params = array())
+ {
+ $sth = $this->execute($sql, $params);
+ if(is_null($sth))
+ return null;
+ return $sth->fetch(PDO::FETCH_ASSOC);
+ }
+
+
+ //select single row from table (as object)
+ public function selectObject($sql, array $params = array(), $className = 'stdClass')
+ {
+ $sth = $this->execute($sql, $params);
+ if(is_null($sth))
+ return null;
+ return $sth->fetchObject($className);
+ }
+
+
+ //select single value from table
+ public function selectValue($sql, array $params = array())
+ {
+ $sth = $this->execute($sql, $params);
+ if(is_null($sth))
+ return null;
+ return $sth->fetchColumn(0);
+ }
+}
diff --git a/2013/daemon/lib/daemon/dbconfig.php b/2013/daemon/lib/daemon/dbconfig.php
new file mode 100644
index 0000000..aaf4e63
--- /dev/null
+++ b/2013/daemon/lib/daemon/dbconfig.php
@@ -0,0 +1,87 @@
+dbClient = $dbClient;
+ }
+
+
+ public function __get($name)
+ {
+ return $this->get($name);
+ }
+
+
+ public function __set($name, $value)
+ {
+ return $this->set($name, $value);
+ }
+
+
+ public function get($name)
+ {
+ if(!isset($this->data[$name]))
+ {
+ $sql = "SELECT value FROM parameters WHERE name=:name";
+ $params = array('name' => $name);
+ $this->data[$name] = $this->dbClient->selectValue($sql, $params);
+ }
+ return $this->data[$name];
+ }
+
+
+ public function set($name, $value)
+ {
+ if (empty($value))
+ $value = '';
+ $sql = "INSERT INTO parameters(name, value) VALUES (:name, :value) ON DUPLICATE KEY UPDATE value=:value";
+ $params = array('name' => $name, 'value' => $value);
+ $this->dbClient->query($sql, $params);
+ $this->data[$name] = $value;
+ }
+
+
+ public function getGeneratorWeights($type)
+ {
+ $keys = array(
+ 'pstr_p', 'pstr_c', 'patk_p', 'patk_c', 'pdef_p', 'pdef_c', 'pres_p', 'pres_c',
+ 'mstr_p', 'mstr_c', 'matk_p', 'matk_c', 'mdef_p', 'mdef_c', 'mres_p', 'mres_c',
+ 'armor', 'speed', 'regen', 'special_param');
+ return $this->getGeneratorOptions("w_$type", $keys);
+ }
+
+
+ private function getGeneratorOptions($key, array $keys)
+ {
+ $result = json_decode($this->get("generator_$key"), true);
+ if (!is_array($result))
+ $result = array();
+ foreach ($keys as $key)
+ {
+ if (empty($result[$key]))
+ $result[$key] = 0;
+ }
+ return $result;
+ }
+
+
+ public function setGeneratorWeights($type, array $options)
+ {
+ $this->setGeneratorOptions("w_$type", $options);
+ }
+
+
+ private function setGeneratorOptions($key, array $options)
+ {
+ foreach ($options as &$val)
+ $val = floatval(str_replace(',', '.', $val));
+ $this->set("generator_$key", json_encode($options));
+ }
+}
diff --git a/2013/daemon/lib/daemon/dbobject.php b/2013/daemon/lib/daemon/dbobject.php
new file mode 100644
index 0000000..42d34c3
--- /dev/null
+++ b/2013/daemon/lib/daemon/dbobject.php
@@ -0,0 +1,108 @@
+import($params);
+ }
+
+
+ public function attachDbClient(Daemon_DbClient $dbClient = null)
+ {
+ $this->_dbClient = $dbClient;
+ }
+
+
+ //deletes object data from database
+ public function delete()
+ {
+ $cond = array();
+ $params = array();
+ foreach($this->_index as $col)
+ {
+ $cond[] = "$col=:$col";
+ $params[$col] = $this->$col;
+ }
+ $cond = implode(' AND ', $cond);
+ if(!$cond)
+ throw new RuntimeException('Index not specified.');
+ $sql = "DELETE FROM $this->_tableName WHERE $cond";
+ $this->_dbClient->query($sql, $params);
+ }
+
+
+ //retrieves object data from database
+ public function get(array $params, $ignoreDuplicates = false)
+ {
+ if(!$params)
+ throw new RuntimeException('Params not specified.');
+ $cond = array();
+ foreach(array_keys($params) as $key)
+ $cond[] = "$key=:$key";
+ $cond = implode(' AND ', $cond);
+ $sql = "SELECT * FROM $this->_tableName WHERE $cond ORDER BY RAND() LIMIT 2";
+ $data = $this->_dbClient->selectAll($sql, $params);
+ if(is_array($data) && isset($data[0]))
+ {
+ if(!$ignoreDuplicates && (count($data) > 1))
+ throw new RuntimeException('Multiple rows found.');
+ foreach($data[0] as $key => $val)
+ $this->$key = $val;
+ }
+ return true;
+ }
+
+
+ //copies params into object data
+ public function import($params)
+ {
+ $keys = array_keys(get_object_vars($this));
+ foreach($keys as $key)
+ {
+ if(isset($params[$key]) && ($key[0] != '_'))
+ $this->$key = $params[$key];
+ }
+ $this->validate();
+ }
+
+
+ //stores object data in the database
+ public function put()
+ {
+ $this->validate();
+ $cols = array();
+ $vals = array();
+ $mods = array();
+ $params = array();
+ foreach($this as $col => $val)
+ {
+ if($col[0] != '_')
+ {
+ $cols[] = $col;
+ $vals[] = ":$col";
+ if(!in_array($col, $this->_index))
+ $mods[] = "$col=:$col";
+ $params[$col] = $val;
+ }
+ }
+ $cols = implode(', ', $cols);
+ $vals = implode(', ', $vals);
+ $mods = implode(', ', $mods);
+ if($mods)
+ $sql = "INSERT INTO $this->_tableName ($cols) VALUES ($vals) ON DUPLICATE KEY UPDATE $mods";
+ else $sql = "REPLACE INTO $this->_tableName ($cols) VALUES ($vals)";
+ $this->_dbClient->query($sql, $params);
+ }
+
+
+ //checks object data
+ public function validate() {}
+}
diff --git a/2013/daemon/lib/daemon/dbobject/character.php b/2013/daemon/lib/daemon/dbobject/character.php
new file mode 100644
index 0000000..ffe541b
--- /dev/null
+++ b/2013/daemon/lib/daemon/dbobject/character.php
@@ -0,0 +1,165 @@
+_player = $player;
+ }
+
+
+ //checks character's inbox for new messages
+ public function checkMail()
+ {
+ if(!$this->character_id)
+ return false;
+ $sql = "SELECT COUNT(1) FROM mail WHERE message_id > COALESCE(:lastMailId, 0) AND recipient_id = :charId";
+ $params = array('lastMailId' => $this->last_mail_id, 'charId' => $this->character_id);
+ return $this->_dbClient->selectValue($sql, $params);
+ }
+
+
+ //try to create a new clan (id or name may be already taken)
+ public function createClan($clanId, $name)
+ {
+ $clanId = Daemon::normalizeString($clanId, false);
+ $name = Daemon::normalizeString($name, false);
+ $validId = $this->validateClanId($clanId);
+ $validName = $this->validateClanId($name);
+ if($validId && $validName)
+ {
+ $sql = "INSERT INTO clans(clan_id, name, leader_id) VALUES (:id, :name, :leaderId)";
+ $params = array('id' => $clanId, 'name' => $name, 'leaderId' => $this->character_id);
+ if($this->_dbClient->query($sql, $params, 'Wybrany ID lub nazwa klanu są już zajęte.'))
+ {
+ $this->clan_id = $clanId;
+ $this->put();
+ }
+ }
+ }
+
+
+ //returns DbObject_CharacterData instance
+ public function getCharacterData()
+ {
+ if(!$this->_characterData)
+ {
+ $this->_characterData = new Daemon_DbObject_CharacterData();
+ $this->_characterData->attachDbClient($this->_dbClient);
+ if($this->character_id)
+ $this->_characterData->get(array('character_id' => $this->character_id));
+ $this->_characterData->_characterName = $this->name;
+ $this->_characterData->_gender = $this->gender;
+ }
+ return $this->_characterData;
+ }
+
+
+ //returns a channel=>writeAccess array of channels allowed for character
+ public function getForumChannels()
+ {
+ $cdata = $this->getCharacterData();
+ $channels = array('public' => array('name' => 'publiczne', 'writable' => false));
+ if($this->character_id)
+ {
+ $channels['public']['writable'] = $this->_player->hasRole('chat');
+ }
+ if($cdata->faction_id)
+ {
+ $channelId = 'f/'.$cdata->faction_id;
+ $channels[$channelId] = array('name' => 'frakcyjne', 'writable' => $this->_player->hasRole('chat'));
+ }
+ if($this->clan_id)
+ {
+ $channelId = 'c/'.$this->clan_id;
+ $channels[$channelId] = array('name' => 'klanowe', 'writable' => $this->_player->hasRole('chat'));
+ }
+ return $channels;
+ }
+
+
+ //reads a list of invitations
+ public function getInvitations()
+ {
+ $sql = "SELECT i.clan_id, c.name AS clan_name, i.description
+ FROM clan_invitations i JOIN clans c USING(clan_id)
+ WHERE i.character_id=:id";
+ $params = array('id' => $this->character_id);
+ return $this->_dbClient->selectAll($sql, $params);
+ }
+
+
+ //sends invitation to specified clan
+ public function inviteClan($clanId, $description, Daemon_Forum $forum)
+ {
+ if(!$description)
+ $description = null;
+ $sql = "SELECT leader_id FROM clans WHERE clan_id=:id";
+ $leaderId = $this->_dbClient->selectValue($sql, array('id' => $clanId));
+ if($leaderId)
+ {
+ $sql = "INSERT IGNORE INTO clan_invitations(clan_id, character_id, description)
+ VALUES (:clanId, :charId, :description) ON DUPLICATE KEY UPDATE description=:description";
+ $params = array('clanId' => $clanId, 'charId' => $this->character_id,
+ 'description' => $description);
+ $this->_dbClient->query($sql, $params);
+ $msg = "Postać $this->name pragnie dołączyć do klanu.";
+ $forum->addMailById(null, $leaderId, $msg);
+ }
+ else Daemon_MsgQueue::add('Wybrany klan nie istnieje lub nie ma przywódcy.');
+ }
+
+
+ public function updateLastAction()
+ {
+ if($this->character_id)
+ {
+ $sql = "UPDATE characters SET last_action = NOW() WHERE character_id=:id";
+ $this->_dbClient->query($sql, array('id' => $this->character_id));
+ }
+ }
+
+
+ //checks clan id validity
+ private function validateClanId($input)
+ {
+ $maxLength = $this->_dbClient->getColumnMaxLength('clans', 'clan_id');
+ if(!$input)
+ Daemon_MsgQueue::add('Musisz podać ID klanu.');
+ elseif(iconv_strlen($input) > $maxLength)
+ Daemon_MsgQueue::add('Wybrany ID jest za długi.');
+ else return true;
+ return false;
+ }
+
+
+ //checks clan name validity
+ private function validateClanName($input)
+ {
+ $maxLength = $this->_dbClient->getColumnMaxLength('clans', 'name');
+ if(!$input)
+ Daemon_MsgQueue::add('Musisz podać nazwę klanu.');
+ elseif(iconv_strlen($input) > $maxLength)
+ Daemon_MsgQueue::add('Wybrana nazwa jest za długa.');
+ else return true;
+ return false;
+ }
+}
diff --git a/2013/daemon/lib/daemon/dbobject/characterdata.php b/2013/daemon/lib/daemon/dbobject/characterdata.php
new file mode 100644
index 0000000..0471327
--- /dev/null
+++ b/2013/daemon/lib/daemon/dbobject/characterdata.php
@@ -0,0 +1,609 @@
+checkTurnCosts())
+ return null;
+ $combat = new Daemon_Duel();
+ $combat->attachCharacterData($this);
+ $combat->attachDbClient($this->_dbClient);
+ $combat->execute($view, $locationType, $targetId);
+ return $combat->getCombatLog();
+ }
+
+
+ //checks of character can attack selected target
+ public function canAttack(array $target, $rolloverId, $withMessages)
+ {
+ //check Id
+ if($this->character_id == $target['character_id'])
+ {
+ if($withMessages)
+ Daemon_MsgQueue::add('Samobójstwo?');
+ return false;
+ }
+ //check location
+ if($this->location_id != $target['location_id'])
+ {
+ if($withMessages)
+ Daemon_MsgQueue::add('Cel opuścił już tą lokację.');
+ return false;
+ }
+ //check levels
+ if(4 * $this->xp_used > 5 * $target['xp_used'])
+ {
+ if($withMessages)
+ Daemon_MsgQueue::add('Cel jest za słaby.');
+ return false;
+ }
+ if(5 * $this->xp_used < 4 * $target['xp_used'])
+ {
+ if($withMessages)
+ Daemon_MsgQueue::add('Cel jest za silny.');
+ return false;
+ }
+ //check previous attacks
+ $cond = "attacker_id=:attackerId AND defender_id=:defenderId";
+ $params = array('attackerId' => $this->character_id, 'defenderId' => $target['character_id']);
+ if($rolloverId)
+ {
+ $cond .= " AND rollover_id=:rolloverId";
+ $params['rolloverId'] = $rolloverId;
+ }
+ $sql = "SELECT COUNT(duel_id) FROM duels WHERE $cond";
+ if($this->_dbClient->selectValue($sql, $params))
+ {
+ if($withMessages)
+ Daemon_MsgQueue::add('Cel już był atakowany przez ciebie w tym przeliczeniu.');
+ return false;
+ }
+ return true;
+ }
+
+
+ //updates turns, gold & mana; returns check result
+ public function checkTurnCosts($costGold = 0, $costMana = 0)
+ {
+ if($this->turns < 1)
+ {
+ Daemon_MsgQueue::add('Nie masz dostępnych tur.');
+ return false;
+ }
+ if($this->gold_purse < $costGold)
+ {
+ Daemon_MsgQueue::add('Masz za mało zlota.');
+ return false;
+ }
+ if($this->mana < $costMana)
+ {
+ Daemon_MsgQueue::add('Masz za mało zlota.');
+ return false;
+ }
+ $this->turns -= 1;
+ $this->gold_purse -= $costGold;
+ $this->mana -= $costMana;
+ return true;
+ }
+
+
+ //checks of target can be attacked, returns combat type (null for error)
+ public function getCombatType(array $target, $locationType)
+ {
+ //check location type
+ if('normal' != $locationType)
+ return 'arena';
+ //check factions
+ if($this->faction_id && ($this->faction_id == $target['faction_id']))
+ return 'arena';
+ //no restrictions, normal fight
+ return 'normal';
+ }
+
+
+ //returns Daemon_DbObject_CombatUnit instance
+ public function getCombatUnit($full = false)
+ {
+ if(!$this->_combatUnit)
+ {
+ $this->_combatUnit = $full ? new Daemon_Combat_Unit() : new Daemon_DbObject_CombatUnit();
+ $this->_combatUnit->attachDbClient($this->_dbClient);
+ if($this->character_id)
+ {
+ if(!$this->combat_unit_id)
+ $this->combat_unit_id = "character-$this->character_id";
+ $this->_combatUnit->get(array('combat_unit_id' => $this->combat_unit_id));
+ }
+ $this->_combatUnit->combat_unit_id = $this->combat_unit_id;
+ $this->_combatUnit->name = $this->_characterName;
+ $this->_combatUnit->faction_id = $this->faction_id;
+ $this->_combatUnit->health = $this->health;
+ $this->_combatUnit->health_max = $this->health_max;
+ }
+ return $this->_combatUnit;
+ }
+
+
+ //calculates "real" level from level & health
+ public function getEffectiveLevel($addFaction)
+ {
+ $factionMult = 0.1; //magic number!
+ $level = $this->level;
+ if($addFaction)
+ $level *= 1 + $factionMult * $this->rank_id;
+ if($this->health_max)
+ $level = round($level * $this->health / $this->health_max);
+ return $level;
+ }
+
+
+ //checks mission history for last mission's data
+ public function getLastMission($maxProgress)
+ {
+ $sql = "SELECT m.*, s.name AS service_name
+ FROM character_missions m LEFT JOIN services s USING(service_id)
+ WHERE character_id=:id AND progress<=:maxProgress
+ ORDER BY rollover_id DESC LIMIT 1";
+ $params = array('id' => $this->character_id, 'maxProgress' => $maxProgress);
+ if($row = $this->_dbClient->selectRow($sql, $params))
+ {
+ $row['_target'] = $this->getMissionTarget($row['type'], $row['params']);
+ $row['_name'] = $this->getMissionName($row['type'], $row['_target']);
+ $row['_statusName'] = Daemon_Dictionary::$missionProgress[$row['progress']];
+ return $row;
+ }
+ else return null;
+ }
+
+
+ private function getMissionName($type, $name)
+ {
+ switch($type)
+ {
+ case'monster':
+ return "pokonaj potwora: $name";
+ case'item':
+ return "przynieś przedmiot: $name";
+ default:
+ return null;
+ }
+ }
+
+
+ private function getMissionTarget($type, $params)
+ {
+ switch($type)
+ {
+ case'monster':
+ $sql = "SELECT name FROM monsters WHERE monster_id=:id";
+ return $this->_dbClient->selectValue($sql, array('id' => $params));
+ case'item':
+ $sql = "SELECT name FROM items WHERE item_id=:id";
+ return $this->_dbClient->selectValue($sql, array('id' => $params));
+ default:
+ return null;
+ }
+ }
+
+
+ //returns a DbObject_Location instance representing current location
+ public function getLocation()
+ {
+ $object = new Daemon_DbObject_Location();
+ $object->attachDbClient($this->_dbClient);
+ $object->attachCharacterData($this);
+ if($this->character_id)
+ $object->get(array('location_id' => $this->location_id));
+ return $object;
+ }
+
+
+ public function getLocationEvent()
+ {
+ return json_decode($this->location_event, true);
+ }
+
+
+ //fetches a list of possible respawn locations
+ public function getRespawns($defaultRespawn)
+ {
+ $sql = "SELECT location_id, name FROM locations WHERE location_id = :defaultRespawn
+ OR location_id IN (
+ SELECT r.respawn_id FROM regions r
+ JOIN character_regions cr ON cr.region_id=r.region_id AND cr.character_id=:characterId
+ )
+ OR location_id IN (
+ SELECT l.location_id FROM character_regions cr
+ JOIN locations l ON cr.region_id=l.region_id AND cr.character_id=:characterId
+ WHERE l.type='caern' AND l.faction_id=:factionId
+ )";
+ $params = array('characterId' => $this->character_id, 'defaultRespawn' => $defaultRespawn,
+ 'factionId' => $this->faction_id);
+ if($data = $this->_dbClient->selectAll($sql, $params))
+ {
+ $result = array();
+ foreach($data as $row)
+ $result[$row['location_id']] = $row['name'];
+ return $result;
+ }
+ else return array();
+ }
+
+
+ public function getSpells()
+ {
+ $sql = "SELECT spell_id, name FROM spells ORDER BY name";
+ $data = $this->_dbClient->selectAll($sql);
+ foreach($data as &$row)
+ {
+ $col = "sp_$row[spell_id]";
+ $row['_cost'] = isset($this->$col) ? $this->$col : null;
+ $row['_cast'] = ($row['_cost'] <= $this->mana);
+ }
+ return $data;
+ }
+
+
+ //increases selected attribute if there is enough xp
+ public function improveAttribute($key)
+ {
+ $col = "a_$key";
+ if(isset($this->$col))
+ {
+ $cost = $this->$col;
+ if($cost <= $this->xp_free)
+ {
+ $this->$col += 1;
+ $this->xp_used += $cost;
+ $this->xp_free -= $cost;
+ $this->resetCombatStats();
+ $this->put();
+ }
+ else Daemon_MsgQueue::add('Nie masz dość doświadczenia.');
+ }
+ else Daemon_MsgQueue::add('Wybrana cecha nie istnieje.');
+ }
+
+
+ //increases faction reputation & rank
+ public function improveReputation($factionId, $delta)
+ {
+ //join faction if needed
+ if(!$this->faction_id)
+ {
+ $sql = "SELECT name FROM factions WHERE faction_id=:id";
+ $factionName = $this->_dbClient->selectValue($sql, array('id' => $factionId));
+ $this->faction_id = $factionId;
+ Daemon_MsgQueue::add("Dołączasz do frakcji: $factionName.");
+ }
+ //raise reputation
+ $this->faction_points += $delta;
+ //check for new rank
+ $sql = "SELECT r.rank_id, r.title_id, t.name_$this->_gender AS title_name
+ FROM faction_ranks r LEFT JOIN titles t USING(title_id)
+ WHERE faction_id=:id
+ AND rank_id = (SELECT MAX(rank_id) FROM faction_ranks WHERE faction_id=:id AND min_points <= :points)";
+ $params = array('id' => $factionId, 'points' => $this->faction_points);
+ $newRank = $this->_dbClient->selectRow($sql, $params);
+ if($newRank && ($newRank['rank_id'] > (int) $this->rank_id))
+ {
+ $this->rank_id = $newRank['rank_id'];
+ if($newRank['title_id'])
+ Daemon_MsgQueue::add("Zdobywasz nową rangę: $newRank[title_name] (poziom $newRank[rank_id]).");
+ else Daemon_MsgQueue::add("Zdobywasz nową rangę (poziom $newRank[rank_id]).");
+ }
+ else Daemon_MsgQueue::add("Rośnie twoja reputacja we frakcji.");
+ }
+
+
+ //increases selected skill if there is enough xp
+ public function improveSkill($key)
+ {
+ $col = "s_$key";
+ if(isset($this->$col))
+ {
+ $cost = $this->$col;
+ if($cost > 0)
+ {
+ if($cost <= $this->xp_free)
+ {
+ $this->$col += 1;
+ $this->xp_used += $cost;
+ $this->xp_free -= $cost;
+ $this->resetCombatStats();
+ $this->put();
+ }
+ else Daemon_MsgQueue::add('Nie masz dość doświadczenia.');
+ }
+ else Daemon_MsgQueue::add('Nie znasz jeszcze tej umiejętności.');
+ }
+ else Daemon_MsgQueue::add('Wybrana umiejętność nie istnieje.');
+ }
+
+
+ //updates combat stats with equipment bonuses
+ private function loadEquipmentBonuses()
+ {
+ //prepare variables
+ $unit = $this->getCombatUnit();
+ $inventory = new Daemon_Inventory($this->_dbClient, $this);
+ $zweihander = false;
+ $attackBonusKeys = array(
+ 'pstr_p', 'pstr_c', 'patk_p', 'patk_c',
+ 'mstr_p', 'mstr_c', 'matk_p', 'matk_c',
+ );
+ $modWpn1 = array_fill_keys($attackBonusKeys, 0);
+ $modWpn2 = array_fill_keys($attackBonusKeys, 0);
+ $armorBonusKeys = array(
+ 'pdef_p', 'pdef_c', 'pres_p', 'pres_c',
+ 'mdef_p', 'mdef_c', 'mres_p', 'mres_c',
+ 'armor', 'speed', 'regen',
+ );
+ $modArmor = array_fill_keys($armorBonusKeys, 0);
+ //reset hands & armor
+ $unit->type1 = 'p';
+ $unit->count1 = 1;
+ $unit->sp1_type = null;
+ $unit->sp1_param = null;
+ $unit->type2 = 'p';
+ $unit->count2 = 1;
+ $unit->sp2_type = null;
+ $unit->sp2_param = null;
+ $unit->armor_sp_type = null;
+ $unit->armor_sp_param = null;
+ //find equipped items, calculate equipment bonuses
+ $sql = "SELECT item_id, equipped FROM inventory WHERE character_id=:id AND equipped IS NOT NULL";
+ $params = array('id' => $this->character_id);
+ foreach($this->_dbClient->selectAll($sql, $params) AS $row)
+ {
+ $item = new Daemon_DbObject_Item();
+ $item->attachDbClient($this->_dbClient);
+ $item->get(array('item_id' => $row['item_id']));
+ switch($row['equipped'])
+ {
+ case'hand_a':
+ $zweihander = ('weapon2h' == $item->type);
+ $unit->count1 = 1;
+ $unit->type1 = $item->damage_type;
+ $unit->sp1_type = $item->special_type;
+ $unit->sp1_param = $item->special_param;
+ foreach($attackBonusKeys as $name)
+ $modWpn1[$name] += $item->$name;
+ break;
+ case'hand_b':
+ $unit->count2 = 1;
+ $unit->type2 = $item->damage_type;
+ $unit->sp2_type = $item->special_type;
+ $unit->sp2_param = $item->special_param;
+ foreach($attackBonusKeys as $name)
+ $modWpn2[$name] += $item->$name;
+ break;
+ case'armor':
+ $unit->armor_sp_type = $item->special_type;
+ $unit->armor_sp_param = $item->special_param;
+ //nobreak
+ default:
+ foreach($attackBonusKeys as $name)
+ {
+ $modWpn1[$name] += $item->$name;
+ $modWpn2[$name] += $item->$name;
+ }
+ break;
+ }
+ foreach($armorBonusKeys as $name)
+ $modArmor[$name] += $item->$name;
+ }
+ $unit->count1 = 1;
+ $unit->count2 = $zweihander ? 0 : 1;
+ //first hand
+ $pstrSkill = $this->s_pstr;
+ $mstrSkill = $this->s_mstr;
+ if($zweihander)
+ {
+ $pstrSkill *= 1.7;
+ $mstrSkill *= 1.7;
+ }
+ if('m' != $unit->type1)
+ {
+ $unit->atk1 = Daemon_Math::combatStat($this->a_dex, $modWpn1['patk_p'], $modWpn1['patk_c'], $this->s_patk);
+ $unit->str1 = Daemon_Math::combatStat($this->a_str, $modWpn1['pstr_p'], $modWpn1['pstr_c'], $pstrSkill);
+ }
+ else
+ {
+ $unit->atk1 = Daemon_Math::combatStat($this->a_pwr, $modWpn1['matk_p'], $modWpn1['matk_c'], $this->s_matk);
+ $unit->str1 = Daemon_Math::combatStat($this->a_pwr, $modWpn1['mstr_p'], $modWpn1['mstr_c'], $mstrSkill);
+ }
+ //second hand
+ if('m' != $unit->type2)
+ {
+ $unit->atk2 = Daemon_Math::combatStat($this->a_dex, $modWpn2['patk_p'], $modWpn2['patk_c'], $this->s_patk);
+ $unit->str2 = Daemon_Math::combatStat($this->a_str, $modWpn2['pstr_p'], $modWpn2['pstr_c'], $this->s_pstr);
+ }
+ else
+ {
+ $unit->atk2 = Daemon_Math::combatStat($this->a_pwr, $modWpn2['matk_p'], $modWpn2['matk_c'], $this->s_matk);
+ $unit->str2 = Daemon_Math::combatStat($this->a_pwr, $modWpn2['mstr_p'], $modWpn2['mstr_c'], $this->s_mstr);
+ }
+ //physical defense
+ $unit->pdef = Daemon_Math::combatStat($this->a_dex, $modArmor['pdef_p'], $modArmor['pdef_c'], $this->s_pdef);
+ $unit->pres = Daemon_Math::combatStat($this->a_vit, $modArmor['pres_p'], $modArmor['pres_c'], $this->s_pres);
+ //magical defense
+ $unit->mdef = Daemon_Math::combatStat($this->a_wil, $modArmor['mdef_p'], $modArmor['mdef_c'], $this->s_mdef);
+ $unit->mres = Daemon_Math::combatStat($this->a_wil, $modArmor['mres_p'], $modArmor['mres_c'], $this->s_mres);
+ //armor & speed
+ $unit->speed = Daemon_Math::combatStat($this->a_dex, $modArmor['speed'], 0, 0);
+ $unit->armor = $modArmor['armor'];
+ //regen
+ $unit->regen = Daemon_Math::combatRegen($this->a_vit, $modArmor['regen'] + $this->s_preg);
+ $unit->put();
+ }
+
+
+ //try to subtract the cost from character's gold, cancel the operation if the cost is too big
+ public function payGold($cost, $bankEnabled)
+ {
+ $charGold = $this->gold_purse;
+ if($bankEnabled)
+ $charGold += $this->gold_bank;
+ if($charGold < $cost)
+ {
+ Daemon_MsgQueue::add("Wymagane $cost zł - nie masz tyle złota.");
+ return false;
+ }
+ $deltaPurse = min($cost, $this->gold_purse);
+ $this->gold_purse -= $deltaPurse;
+ $this->gold_bank -= $cost - $deltaPurse;
+ $this->put();
+ return true;
+ }
+
+
+ //regenerates one-turn-worth of health & mana
+ public function regen($resting)
+ {
+ $this->mana += $this->mana_regen;
+ if($resting)
+ {
+ $this->health += $this->a_vit;
+ $this->mana += ceil($this->a_pwr / 4);
+ }
+ if($this->health > $this->health_max)
+ $this->health = $this->health_max;
+ if($this->mana > $this->mana_max)
+ $this->mana = $this->mana_max;
+ }
+
+
+ //calculates combat stats based on attributes, skills and equipment
+ public function resetCombatStats()
+ {
+ //health
+ $old = $this->health_max;
+ $this->health_max = 3*$this->a_str + 7*$this->a_vit;
+ $this->health += $this->health_max - $old;
+ //mana
+ $old = $this->mana_max;
+ $this->mana_max = 3*$this->a_pwr + 2*$this->a_wil;
+ $this->mana += $this->mana_max - $old;
+ $this->mana_regen = Daemon_Math::manaRegen($this->a_wil, $this->s_mreg);
+ //used xp
+ $this->xp_used = 0;
+ foreach(array_keys(Daemon_Dictionary::$characterAttributes) as $key)
+ {
+ $col = "a_$key";
+ $this->xp_used += $this->$col * ($this->$col + 1) / 2;
+ }
+ foreach(array_keys(Daemon_Dictionary::$characterSkills) as $key)
+ {
+ $col = "s_$key";
+ $this->xp_used += $this->$col * ($this->$col + 1) / 2;
+ }
+ //update combat stats
+ $this->loadEquipmentBonuses();
+ }
+
+
+ //respawns in selected location
+ public function respawn($locationId, $defaultRespawn)
+ {
+ $respawns = $this->getRespawns($defaultRespawn);
+ if(!isset($respawns[$locationId]))
+ {
+ Daemon_MsgQueue::add('Wybrana lokacja nie jest dostępna.');
+ return false;
+ }
+ $this->location_id = $locationId;
+ $this->health = $this->health_max;
+ $this->mana = 4 * $this->mana_regen;
+ $this->resetCombatStats();
+ $this->put();
+ return true;
+ }
+
+
+ //executes selected event, returns event log
+ public function runEvent(Daemon_View $view)
+ {
+ $event = $this->getLocationEvent();
+ //monster attack
+ if(isset($event['monsterId']))
+ {
+ $combat = new Daemon_MonsterCombat();
+ $combat->attachCharacterData($this);
+ $combat->attachDbClient($this->_dbClient);
+ $combat->execute($view, $event['monsterId']);
+ //return log
+ return $combat->getCombatLog();
+ }
+ //special event
+ if(isset($event['eventId'], $event['params']))
+ {
+ $handler = new Daemon_Event();
+ $handler->attachCharacterData($this);
+ $handler->attachDbClient($this->_dbClient);
+ $handler->execute($view, $event['eventId'], $event['params']);
+ return $handler->getEventLog();
+ }
+ //no event
+ return null;
+ }
+
+
+ //updates character's health, location etc to represent death
+ public function setDeath($clearEquipment)
+ {
+ $this->deaths += 1;
+ $this->health = 0;
+ $this->mana = 0;
+ $this->xp_free = 0;
+ $this->location_id = null;
+ if($clearEquipment)
+ {
+ $this->gold_purse = 0;
+ $sql = "DELETE FROM inventory WHERE character_id=:id
+ AND status='inventory' AND NOT FIND_IN_SET('bound', flags)";
+ $params = array('id' => $this->character_id);
+ $this->_dbClient->query($sql, $params);
+ }
+ $this->resetCombatStats();
+ }
+
+
+ public function setLocationEvent(array $data)
+ {
+ $event = array();
+ //monster attack
+ if(isset($data['monsterId']))
+ $event['monsterId'] = $data['monsterId'];
+ //special event
+ if(isset($data['eventId'], $data['params']))
+ {
+ $event['eventId'] = $data['eventId'];
+ $event['params'] = $data['params'];
+ }
+ $this->location_event = json_encode($event);
+ }
+}
diff --git a/2013/daemon/lib/daemon/dbobject/clan.php b/2013/daemon/lib/daemon/dbobject/clan.php
new file mode 100644
index 0000000..c0dab12
--- /dev/null
+++ b/2013/daemon/lib/daemon/dbobject/clan.php
@@ -0,0 +1,91 @@
+ $this->clan_id, 'charId' => $characterId);
+ if($this->_dbClient->selectValue($sql, $params))
+ {
+ $sql = "UPDATE characters SET clan_id=:clanId WHERE character_id=:charId";
+ $params = array('clanId' => $this->clan_id, 'charId' => $characterId);
+ $this->_dbClient->query($sql, $params);
+ $sql = "DELETE FROM clan_invitations WHERE character_id=:id";
+ $this->_dbClient->query($sql, array('id' => $characterId));
+ $msg = "Podanie do klanu $this->name zostało zaakceptowane.";
+ $forum->addMailById(null, $characterId, $msg);
+ }
+ else Daemon_MsgQueue::add('Wybrane zaproszenie nie istnieje.');
+ }
+
+
+ //deletes clan and updates its members
+ public function delete()
+ {
+ //TODO
+ $params = array('id' => $this->clan_id);
+ $sql = "DELETE FROM clans WHERE clan_id=:id";
+ $this->_dbClient->query($sql, $params);
+ $sql = "DELETE FROM clan_invitations WHERE clan_id=:id";
+ $this->_dbClient->query($sql, $params);
+ $sql = "UPDATE characters SET clan_id=NULL WHERE clan_id=:id";
+ $this->_dbClient->query($sql, $params);
+ }
+
+
+ //reads a list of invitations
+ public function getInvitations()
+ {
+ $sql = "SELECT i.*, c.name AS character_name, cd.level, cd.xp_used,
+ cd.faction_id, COALESCE(cd.rank_id, 0) AS rank_id,
+ date_format(c.date_created, '%Y-%m-%d') AS date_created
+ FROM clan_invitations i JOIN characters c USING(character_id) JOIN character_data cd USING(character_id)
+ WHERE i.clan_id=:id";
+ return $this->_dbClient->selectAll($sql, array('id' => $this->clan_id));
+ }
+
+
+ //fetches leader's name
+ public function getLeaderName()
+ {
+ $sql = "SELECT name FROM characters WHERE character_id=:id";
+ return $this->_dbClient->selectValue($sql, array('id' => $this->leader_id));
+ }
+
+
+ //reads a list of members
+ public function getMembers()
+ {
+ $sql = "SELECT cd.character_id, c.name, cd.level, cd.xp_used,
+ cd.faction_id, COALESCE(cd.rank_id, 0) AS rank_id,
+ date_format(c.date_created, '%Y-%m-%d') AS date_created
+ FROM characters c JOIN character_data cd USING(character_id) WHERE c.clan_id=:id";
+ $result = $this->_dbClient->selectAll($sql, array('id' => $this->clan_id));
+ foreach($result as &$row)
+ $row['_isLeader'] = ($row['character_id'] == $this->leader_id);
+ return $result;
+ }
+
+
+ //removes member from clan
+ public function kickMember($characterId, Daemon_Forum $forum)
+ {
+ if($characterId != $this->leader_id)
+ {
+ $sql = "UPDATE characters SET clan_id = NULL WHERE character_id=:id";
+ $this->_dbClient->query($sql, array('id' => $characterId));
+ $forum->addMailById(null, $characterId, 'Wyrzucono cię z klanu.');
+ }
+ else Daemon_MsgQueue::add('Przywódca nie może odejść, jedynie rozwiązać klan.');
+ }
+}
diff --git a/2013/daemon/lib/daemon/dbobject/combatunit.php b/2013/daemon/lib/daemon/dbobject/combatunit.php
new file mode 100644
index 0000000..4497dde
--- /dev/null
+++ b/2013/daemon/lib/daemon/dbobject/combatunit.php
@@ -0,0 +1,63 @@
+type1]))
+ $this->type1 = null;
+ if (!isset($attackTypes[$this->type2]))
+ $this->type2 = null;
+ if (!isset($attackSpecials[$this->sp1_type]))
+ $this->sp1_type = null;
+ if (!isset($attackSpecials[$this->sp2_type]))
+ $this->sp2_type = null;
+ if (!isset($armorSpecials[$this->armor_sp_type]))
+ $this->armor_sp_type = null;
+ }
+}
diff --git a/2013/daemon/lib/daemon/dbobject/event.php b/2013/daemon/lib/daemon/dbobject/event.php
new file mode 100644
index 0000000..9465441
--- /dev/null
+++ b/2013/daemon/lib/daemon/dbobject/event.php
@@ -0,0 +1,11 @@
+type]))
+ {
+ if ($this->damage_type && isset($itemDamageTypes[$this->damage_type]))
+ {
+ $typeName = sprintf('broń %s (obrażenia %s)',
+ $itemWeaponTypes[$this->type], $itemDamageTypes[$this->damage_type]);
+ }
+ else
+ $typeName = 'tarcza';
+ if(isset($combatAttackSpecials[$this->special_type]))
+ $specialName = sprintf('%s (%s)', $combatAttackSpecials[$this->special_type], $this->special_param);
+ }
+ elseif (!empty($itemArmorTypes[$this->type]))
+ {
+ $typeName = $itemArmorTypes[$this->type];
+ if(isset($combatArmorSpecials[$this->special_type]))
+ $specialName = sprintf('%s (%s)', $combatArmorSpecials[$this->special_type], $this->special_param);
+ }
+ else //usables
+ {
+ $typeName = 'niezakładalny';
+ }
+ //stats
+ $stats = array();
+ if($specialName)
+ $stats[] = $specialName;
+ if('item' != $this->type)
+ {
+ if($this->pstr_p || $this->pstr_c)
+ $stats[] = $this->getStatDescription('pstr', $this->pstr_p, $this->pstr_c);
+ if($this->patk_p || $this->patk_c)
+ $stats[] = $this->getStatDescription('patk', $this->patk_p, $this->patk_c);
+ if($this->pdef_p || $this->pdef_c)
+ $stats[] = $this->getStatDescription('pdef', $this->pdef_p, $this->pdef_c);
+ if($this->pres_p || $this->pres_c)
+ $stats[] = $this->getStatDescription('pres', $this->pres_p, $this->pres_c);
+ if($this->mstr_p || $this->mstr_c)
+ $stats[] = $this->getStatDescription('mstr', $this->mstr_p, $this->mstr_c);
+ if($this->matk_p || $this->matk_c)
+ $stats[] = $this->getStatDescription('matk', $this->matk_p, $this->matk_c);
+ if($this->mdef_p || $this->mdef_c)
+ $stats[] = $this->getStatDescription('mdef', $this->mdef_p, $this->mdef_c);
+ if($this->mres_p || $this->mres_c)
+ $stats[] = $this->getStatDescription('mres', $this->mres_p, $this->mres_c);
+ if($this->armor)
+ $stats[] = sprintf('pancerz%+d', $this->armor);
+ if($this->speed)
+ $stats[] = sprintf('szybkość%+d%%', $this->speed);
+ if($this->regen)
+ $stats[] = sprintf('regen%+d', $this->regen);
+ }
+ //final concatenation
+ if($stats)
+ $desc = sprintf('%s; %s', $typeName, implode(', ', $stats));
+ else $desc = $typeName;
+ return $desc;
+ }
+
+
+ //returns a list of matching equipment slots
+ public function getSlots()
+ {
+ if ($this->type == 'weapon1h')
+ return array('hand_a', 'hand_b');
+ elseif ($this->type == 'weapon2h')
+ return array('hand_a');
+ elseif ($this->type == 'accesory')
+ return array('accesory_a', 'accesory_b');
+ elseif ($this->type != 'item')
+ return array($this->type);
+ else return array();
+ }
+
+
+ private function getStatDescription($name, $value_p = 0, $value_c = 0)
+ {
+ $result = $name;
+ if($value_p)
+ $result .= sprintf('%+d%%', $value_p);
+ if($value_c)
+ $result .= sprintf('%+d', $value_c);
+ return $result;
+ }
+
+
+ public function updateSuggestedValue(Daemon_DbConfig $dbCfg)
+ {
+ if ($this->type == 'item')
+ return;
+ $this->suggested_value = 0.0;
+ $baseValue = $dbCfg->generatorBaseValue;
+ $weights = $dbCfg->getGeneratorWeights($this->type);
+ foreach ($weights as $key => $val)
+ {
+ if (isset($this->$key))
+ $this->suggested_value += $this->$key * $val;
+ }
+ $this->suggested_value *= $baseValue;
+ }
+
+
+ public function validate()
+ {
+ if ($this->type == 'weapon1h' || $this->type == 'weapon2h')
+ {
+ $specials = Daemon_Dictionary::$combatAttackSpecials;
+ if(!isset($specials[$this->special_type]))
+ {
+ $this->special_type = null;
+ $this->special_param = null;
+ }
+ }
+ elseif ($this->type != 'item')
+ {
+ $this->damage_type = null;
+ $specials = Daemon_Dictionary::$combatArmorSpecials;
+ if(($this->type != 'armor') || !isset($specials[$this->special_type]))
+ {
+ $this->special_type = null;
+ $this->special_param = null;
+ }
+ }
+ else //usables
+ {
+ $this->damage_type = null;
+ }
+ }
+}
diff --git a/2013/daemon/lib/daemon/dbobject/itemtemplate.php b/2013/daemon/lib/daemon/dbobject/itemtemplate.php
new file mode 100644
index 0000000..4439aa7
--- /dev/null
+++ b/2013/daemon/lib/daemon/dbobject/itemtemplate.php
@@ -0,0 +1,20 @@
+_characterData->checkTurnCosts())
+ return false;
+ //update character data
+ $this->_characterData->regen(false);
+ //check for events
+ $this->checkEvents(2);
+ //save character data
+ $this->_characterData->put();
+ return true;
+ }
+
+
+ //spends one turn on resting
+ public function actionRest()
+ {
+ //check turn costs
+ if(!$this->_characterData->checkTurnCosts())
+ return false;
+ //update character data
+ $this->_characterData->regen(true);
+ //check for events
+ $this->checkEvents(1);
+ //save character data
+ $this->_characterData->put();
+ return true;
+ }
+
+
+ //spends one turn on training
+ public function actionTrain()
+ {
+ //check turn costs
+ if(!$this->_characterData->checkTurnCosts())
+ return false;
+ //update character data
+ $this->_characterData->regen(false);
+ $this->_characterData->xp_free += 1;
+ //check for events
+ $this->checkEvents(1);
+ //save character data
+ $this->_characterData->put();
+ return true;
+ }
+
+
+ //moves character to specified location
+ public function actionTravel($destinationId)
+ {
+ //read path data
+ $sql = "SELECT * FROM location_paths WHERE location_id=:id AND destination_id=:destId";
+ $params = array('id' => $this->location_id, 'destId' => $destinationId);
+ $path = $this->_dbClient->selectRow($sql, $params);
+ if(!$path)
+ {
+ Daemon_MsgQueue::add('Wybrana ścieżka jest niedostępna.');
+ return false;
+ }
+ //check turn costs
+ if(!$this->_characterData->checkTurnCosts($path['cost_gold'], $path['cost_mana']))
+ return false;
+ //update character data
+ $this->_characterData->regen(false);
+ $this->_characterData->location_id = $destinationId;
+ //load destination
+ $this->get(array('location_id' => $destinationId));
+ if($this->region_id)
+ {
+ $sql = "INSERT IGNORE INTO character_regions (character_id, region_id) VALUES (:charId, :regionId)";
+ $params = array('charId' => $this->_characterData->character_id, 'regionId' => $this->region_id);
+ $this->_dbClient->query($sql, $params);
+ }
+ //check for events
+ $this->checkEvents(1);
+ //save character data
+ $this->_characterData->put();
+ return true;
+ }
+
+
+ public function attachCharacterData(Daemon_DbObject_CharacterData $characterData)
+ {
+ $this->_characterData = $characterData;
+ }
+
+
+ //checks for events in a location
+ private function checkEvents($chanceMult)
+ {
+ $event = false;
+ $eventParams = array();
+ //check if there was any event
+ if($this->chance2)
+ {
+ $d256 = mt_rand(0, 255);
+ $failChance = 256 * (1 - $this->chance1 / $this->chance2);
+ $chance = $chanceMult ? (256 - $failChance / $chanceMult) : 0;
+ $event = ($d256 < $chance);
+ }
+ //check event type
+ if($event)
+ {
+ //read monster data
+ $sql = "SELECT * FROM location_monsters WHERE location_id=:id";
+ $monsters = $this->_dbClient->selectAll($sql, array('id' => $this->location_id));
+ //read special events
+ $sql = "SELECT * FROM location_events WHERE location_id=:id";
+ $events = $this->_dbClient->selectAll($sql, array('id' => $this->location_id));
+ //find event data
+ $chanceSum = 0;
+ foreach($monsters as $row)
+ $chanceSum += $row['chance'];
+ foreach($events as $row)
+ $chanceSum += $row['chance'];
+ $d256 = mt_rand(0, 255);
+ foreach($monsters as $row)
+ {
+ $chance = 256 * $row['chance'] / $chanceSum;
+ if($d256 < $chance)
+ {
+ $eventParams = array('monsterId' => $row['monster_id']);
+ break;
+ }
+ $d256 -= $chance;
+ }
+ foreach($events as $row)
+ {
+ $chance = 256 * $row['chance'] / $chanceSum;
+ if($d256 < $chance)
+ {
+ $eventParams = array('eventId' => $row['event_id'], 'params' => $row['params']);
+ break;
+ }
+ $d256 -= $chance;
+ }
+ }
+ //store event
+ if(!$eventParams)
+ Daemon_MsgQueue::add('Brak zdarzeń w tej turze.');
+ $this->_characterData->setLocationEvent($eventParams);
+ }
+
+
+ //counts characters present in a location
+ public function getCharacterCount($limit)
+ {
+ $sql = "SELECT COUNT(1) FROM character_data WHERE location_id=:id LIMIT :limit";
+ $params = array('id' => $this->location_id, 'limit' => $limit);
+ return $this->_dbClient->selectValue($sql, $params);
+ }
+
+
+ //gets a list of characters present in a location
+ public function getCharacters(Daemon_DbObject_CharacterData $char, $halfLimit = null)
+ {
+ if(empty($this->location_id))
+ return array();
+ $sql = "SELECT MAX(rollover_id) FROM rollovers";
+ $rolloverId = $this->_dbClient->selectValue($sql);
+ $charId = $this->_characterData->character_id;
+ $cols = "c.character_id, c.name, cp.location_id, cp.level, cp.xp_used,
+ c.clan_id, cp.faction_id, COALESCE(cp.rank_id, 0) AS rank_id, f.name AS faction_name";
+ $tables = "character_data cp
+ JOIN characters c USING(character_id)
+ LEFT JOIN factions f USING(faction_id)";
+ $params = array('id' => $this->location_id, 'charId' => $charId);
+ if($halfLimit)
+ {
+ $params['xp'] = $char->xp_used;
+ $params['halfLimit'] = $halfLimit;
+ $sql = "(
+ SELECT $cols FROM $tables
+ WHERE cp.location_id=:id AND cp.character_id!=:charId AND cp.xp_used >= :xp
+ ORDER BY xp_used ASC LIMIT $halfLimit
+ ) UNION (
+ SELECT $cols FROM $tables
+ WHERE cp.location_id=:id AND cp.character_id!=:charId AND cp.xp_used <= :xp
+ ORDER BY xp_used DESC LIMIT $halfLimit
+ ) ORDER BY xp_used DESC, name ASC";
+ }
+ else
+ {
+ $sql = "SELECT $cols FROM $tables
+ WHERE cp.location_id=:id AND cp.character_id!=:charId
+ ORDER BY cp.xp_used DESC, c.name ASC";
+ }
+ $data = $this->_dbClient->selectAll($sql, $params);
+ foreach($data as &$row)
+ {
+ $row['_canAttack'] = $char->canAttack($row, $rolloverId, false);
+ $row['_sparring'] = ('normal' != $char->getCombatType($row, $this->type));
+ }
+ return $data;
+ }
+
+
+ //gets the name of a faction owning location/caern
+ public function getFactionName()
+ {
+ if(empty($this->faction_id))
+ return null;
+ $sql = "SELECT name FROM factions WHERE faction_id=:id";
+ return $this->_dbClient->selectValue($sql, array('id' => $this->faction_id));
+ }
+
+
+ //get a full list of maps
+ public function getMaps()
+ {
+ $sql = "SELECT * FROM maps WHERE url IS NOT NULL AND url != '' ORDER BY sort, name";
+ return $this->_dbClient->selectAll($sql, array());
+ }
+
+
+ //get a list of paths starting in current location
+ public function getPaths()
+ {
+ if(empty($this->location_id))
+ return array();
+ $sql = "SELECT p.*, IF(p.name IS NULL OR p.name='', l.name, p.name) AS path_name,
+ (p.cost_gold<=:gold AND p.cost_mana<=:mana) AS _enabled
+ FROM location_paths p JOIN locations l ON p.destination_id=l.location_id
+ WHERE p.location_id=:id ORDER BY l.name, l.location_id";
+ $params = array('id' => $this->location_id,
+ 'gold' => $this->_characterData->gold_purse,
+ 'mana' => $this->_characterData->mana,
+ );
+ return $this->_dbClient->selectAll($sql, $params);
+ }
+
+
+ public function getPictureUrl()
+ {
+ if ($this->picture_url)
+ return $this->picture_url;
+ $sql = "SELECT picture_url FROM regions WHERE region_id=:id";
+ return $this->_dbClient->selectValue($sql, array('id' => $this->region_id));
+ }
+
+
+ //get name of the location's region
+ public function getRegionName()
+ {
+ if(empty($this->region_id))
+ return null;
+ $sql = "SELECT name FROM regions WHERE region_id=:id";
+ return $this->_dbClient->selectValue($sql, array('id' => $this->region_id));
+ }
+
+
+ //get a list of available services
+ public function getServices()
+ {
+ if(empty($this->location_id))
+ return array();
+ $sql = "SELECT s.*, (
+ (s.faction_id IS NULL OR :factionId IS NULL OR s.faction_id = :factionId)
+ AND (s.rank_id IS NULL OR s.rank_id <= :rankId)
+ ) AS _enabled
+ FROM location_services l JOIN services s USING(service_id)
+ WHERE l.location_id=:id ORDER BY s.name";
+ $params = array('id' => $this->location_id,
+ 'factionId' => $this->_characterData->faction_id,
+ 'rankId' => $this->_characterData->rank_id,
+ );
+ return $this->_dbClient->selectAll($sql, $params);
+ }
+
+
+ //checks object data
+ public function validate()
+ {
+ $this->chance1 = max(0, (int) $this->chance1);
+ $this->chance2 = max(1, (int) $this->chance2);
+ if($this->type != 'boss')
+ {
+ $this->boss_id = null;
+ $this->boss_status = null;
+ if ($this->type != 'caern')
+ $this->faction_id = null;
+ }
+ }
+}
diff --git a/2013/daemon/lib/daemon/dbobject/monster.php b/2013/daemon/lib/daemon/dbobject/monster.php
new file mode 100644
index 0000000..6a81f69
--- /dev/null
+++ b/2013/daemon/lib/daemon/dbobject/monster.php
@@ -0,0 +1,49 @@
+_combatUnit)
+ {
+ $this->_combatUnit = $full ? new Daemon_Combat_Unit() : new Daemon_DbObject_CombatUnit();
+ $this->_combatUnit->attachDbClient($this->_dbClient);
+ if($this->combat_unit_id)
+ $this->_combatUnit->get(array('combat_unit_id' => $this->combat_unit_id));
+ $this->_combatUnit->name = $this->name;
+ $this->_combatUnit->faction_id = null;
+ }
+ return $this->_combatUnit;
+ }
+
+
+ public function validate()
+ {
+ $this->class = max(0, (int) $this->class);
+ $this->level = max(0, (int) $this->level);
+ $this->gold = max(0, (int) $this->gold);
+ $this->chance1 = max(0, (int) $this->chance1);
+ $this->chance2 = max(1, (int) $this->chance2);
+ //set class
+ foreach (Daemon_Dictionary::$monsterClassLevels as $class => $level)
+ {
+ if ($this->level > $level)
+ $this->class = $class;
+ }
+ }
+}
diff --git a/2013/daemon/lib/daemon/dbobject/player.php b/2013/daemon/lib/daemon/dbobject/player.php
new file mode 100644
index 0000000..c60300c
--- /dev/null
+++ b/2013/daemon/lib/daemon/dbobject/player.php
@@ -0,0 +1,387 @@
+attachDbClient($dbClient);
+ $this->checkSession();
+ if($id = $this->getPlayerId())
+ parent::get(array('player_id' => $id));
+ }
+
+
+ //creates a new character
+ public function addCharacter($name, $gender, $turnDelta, $turnLimit)
+ {
+ if(!$this->getPlayerId())
+ return false;
+ $maxLength = $this->_dbClient->getColumnMaxLength('characters', 'name');
+ $name = Daemon::normalizeString($name, false);
+ $gender = Daemon::normalizeString($gender, false);
+ $validName = $this->validateName($name, $maxLength);
+ $validGender = $this->validateGender($gender);
+ if($validName && $validGender)
+ {
+ $sql = "INSERT INTO characters (player_id, name, gender, last_action) VALUES (:playerId, :name, :gender, now())";
+ $params = array(
+ 'playerId' => $this->getPlayerId(),
+ 'name' => $name, 'gender' => $gender,
+ );
+ $this->_dbClient->query($sql, $params, 'Wybrane imię jest już zajęte.');
+ if($id = $this->_dbClient->lastInsertId())
+ {
+ $turns = $this->getStartingTurns($turnDelta, $turnLimit);
+ $sql = "INSERT INTO character_data(character_id, turns) VALUES (:id, :turns)";
+ $this->_dbClient->query($sql, array('id' => $id, 'turns' => $turns));
+ $sql = "INSERT INTO character_statistics(character_id) VALUES (:id)";
+ $this->_dbClient->query($sql, array('id' => $id));
+ }
+ }
+ }
+
+
+ //checks and stores authentication data (logs in)
+ public function authenticate($login, $password)
+ {
+ $this->get(array('login' => $login));
+ if($this->player_id)
+ {
+ //check password
+ list($salt, $hash) = explode(':', $this->password.':');
+ if($hash == Daemon::passwordHash($salt, $password))
+ {
+ session_regenerate_id(true);
+ $_SESSION[self::VARNAME_PLAYER_ID] = (int) $this->player_id;
+ $_SESSION[self::VARNAME_PLAYER_ADDR] = getenv('REMOTE_ADDR');
+ $_SESSION[self::VARNAME_TIMESTAMP] = time();
+ $this->last_login = $this->_dbClient->selectValue("SELECT NOW()");
+ $this->put();
+ }
+ else $this->player_id = null;
+ }
+ if(!$this->player_id)
+ {
+ Daemon_MsgQueue::add('Nieprawidłowy login lub hasło.');
+ $this->unauthenticate();
+ }
+ }
+
+
+ //compares request data with stored auth data
+ private function checkSession()
+ {
+ $prevAddr = $currentAddr = getenv('REMOTE_ADDR');
+ $prevTime = $currentTime = time();
+ if(isset($_SESSION[self::VARNAME_PLAYER_ADDR]))
+ $prevAddr = $_SESSION[self::VARNAME_PLAYER_ADDR];
+ if(isset($_SESSION[self::VARNAME_TIMESTAMP]))
+ $prevTime = $_SESSION[self::VARNAME_TIMESTAMP];
+ $validAddr = ($currentAddr == $prevAddr);
+ $validTime = ($currentTime < $prevTime + self::SESSION_TIMEOUT);
+ if($validAddr && $validTime)
+ $_SESSION[self::VARNAME_TIMESTAMP] = $currentTime;
+ else $this->unauthenticate();
+ }
+
+
+ //resets or deletes selected character
+ public function deleteCharacter($characterId, $reset, $turnDelta, $turnLimit)
+ {
+ if(!$this->getPlayerId())
+ return false;
+ $sql = "SELECT character_id FROM characters WHERE character_id=:id AND player_id=:playerId";
+ $params = array('id' => $characterId, 'playerId' => $this->getPlayerId());
+ if($id = $this->_dbClient->selectValue($sql, $params))
+ {
+ $params = array('id' => $characterId);
+ $tables = array('character_data', 'character_missions', 'character_regions',
+ 'character_statistics', 'character_titles', 'inventory');
+ foreach($tables as $table)
+ {
+ $sql = "DELETE FROM $table WHERE character_id=:id";
+ if ($table == 'character_titles')
+ $sql .= " AND title_id NOT IN (SELECT title_id FROM titles WHERE type='special')";
+ $this->_dbClient->query($sql, $params);
+ }
+ if ($reset)
+ {
+ $turns = $this->getStartingTurns($turnDelta, $turnLimit);
+ $sql = "INSERT INTO character_data(character_id, turns) VALUES (:id, :turns)";
+ $this->_dbClient->query($sql, array('id' => $id, 'turns' => $turns));
+ $sql = "INSERT INTO character_statistics(character_id) VALUES (:id)";
+ $this->_dbClient->query($sql, array('id' => $id));
+ }
+ else
+ {
+ $sql = "DELETE FROM characters WHERE character_id=:id";
+ $this->_dbClient->query($sql, $params);
+ }
+ }
+ }
+
+
+ //returns basic data of active character
+ public function getActiveCharacter()
+ {
+ $char = new Daemon_DbObject_Character;
+ $char->attachDbClient($this->_dbClient);
+ if($id = $this->getCharacterId())
+ $char->get(array('character_id' => $id));
+ $this->setCharacterId($char->character_id);
+ $char->attachPlayer($this);
+ return $char;
+ }
+
+
+ //returns active character's ID
+ public function getCharacterId()
+ {
+ if(isset($_SESSION[self::VARNAME_CHARACTER_ID]))
+ return $_SESSION[self::VARNAME_CHARACTER_ID];
+ else return null;
+ }
+
+
+ //returns a list of player's characters
+ public function getCharacters()
+ {
+ $sql = "SELECT c.character_id, c.name,
+ cp.level, cp.turns, cp.health, cp.health_max, l.name AS location_name
+ FROM characters c
+ LEFT JOIN character_data cp USING(character_id)
+ LEFT JOIN locations l USING(location_id)
+ WHERE player_id = :playerId";
+ $params = array('playerId' => $this->getPlayerId());
+ $result = array();
+ foreach((array) $this->_dbClient->selectAll($sql, $params) as $row)
+ $result[$row['character_id']] = $row;
+ return $result;
+ }
+
+
+ //returns authenticated player's ID
+ public function getPlayerId()
+ {
+ if(isset($_SESSION[self::VARNAME_PLAYER_ID]))
+ $this->player_id = $_SESSION[self::VARNAME_PLAYER_ID];
+ else $this->player_id = null;
+ return $this->player_id;
+ }
+
+
+ //returns a list of player's access roles
+ public function getRoles()
+ {
+ if(!$id = $this->getPlayerId())
+ return array();
+ if(!is_array($this->roles))
+ {
+ $sql = "SELECT roles FROM players WHERE player_id=:playerId";
+ $params = array('playerId' => $this->getPlayerId());
+ $this->roles = explode(',', (string) $this->_dbClient->selectValue($sql, $params));
+ }
+ return $this->roles;
+ }
+
+
+ protected function getStartingTurns($turnDelta, $turnLimit)
+ {
+ $sql = "SELECT COUNT(rollover_id) FROM rollovers";
+ $n = (int) $this->_dbClient->selectValue($sql);
+ return min($turnLimit, $turnDelta * (1 + $n));
+ }
+
+
+ //checks if player has selected access role
+ public function hasRole($name)
+ {
+ return in_array($name, $this->getRoles());
+ }
+
+
+ //stores a new password and sends mail with reset key
+ public function preparePasswordReset($login, $email, $password, $passwordCopy)
+ {
+ if (!$this->validatePassword($password, $passwordCopy))
+ return false;
+ if (!$login || !$email)
+ {
+ Daemon_MsgQueue::add('Musisz podać login oraz email.');
+ return false;
+ }
+ //validate login+email
+ $sql = "SELECT player_id FROM players WHERE login=:login AND email=:email";
+ $params = array('login' => $login, 'email' => $email);
+ $playerId = $this->_dbClient->selectValue($sql, $params);
+ if (!$playerId)
+ {
+ Daemon_MsgQueue::add('Nieprawidłowy login lub hasło.');
+ return false;
+ }
+ //store password
+ $key = sha1(Daemon::passwordSalt() . $login . $email);
+ $salt = Daemon::passwordSalt();
+ $passwordSql = sprintf('%s:%s', $salt, Daemon::passwordHash($salt, $password));
+ $sql = "UPDATE players SET reset_key = :key, reset_password = :password,
+ reset_until = now() + INTERVAL 1 WEEK WHERE player_id = :id";
+ $params = array('id' => $playerId, 'key' => $key, 'password' => $passwordSql);
+ $ok = $this->_dbClient->query($sql, $params);
+ if (!$ok)
+ {
+ Daemon_MsgQueue::add('Nie udało się zapisać nowego hasła.');
+ return false;
+ }
+ //send mail
+ $url = sprintf('%sreset-password?key=%s', $GLOBALS['cfg']->applicationUrl, $key);
+ $subject = "Daemon 2: reset hasla";
+ $message = "Aby zresetowac haslo przejdz pod adres:\n$url\n";
+ $from = $GLOBALS['cfg']->applicationMail;
+ $headers = "From: $from\r\nReply-To: $from";
+ $ok = mail($email, $subject, $message, $headers);
+ if ($ok)
+ $msg = 'Na podany email wysłana została wiadomość z kluczem resetującym hasło.';
+ else
+ $msg = 'Niestety mailer nie działa, reset hasła jest chwilowo niemozliwy.';
+ Daemon_MsgQueue::add($msg);
+ return $ok;
+ }
+
+
+ //creates a new player
+ public function register($login, $password, $passwordCopy)
+ {
+ $maxLength = $this->_dbClient->getColumnMaxLength('players', 'login');
+ $validLogin = $this->validateLogin($login, $maxLength);
+ $validPassword = $this->validatePassword($password, $passwordCopy);
+ if($validLogin && $validPassword)
+ {
+ $salt = Daemon::passwordSalt();
+ $passwordSql = sprintf('%s:%s', $salt, Daemon::passwordHash($salt, $password));
+ $sql = "INSERT INTO players (login, password, roles) VALUES (:login, :password, 'chat')";
+ $params = array('login' => $login, 'password' => $passwordSql);
+ $ok = $this->_dbClient->query($sql, $params, 'Wybrany login jest już zajęty.');
+ Daemon_MsgQueue::add(sprintf('Rejestracja zakończona %s.', $ok ? 'powodzeniem' : 'niepowodzeniem'));
+ return $ok;
+ }
+ return false;
+ }
+
+
+ //resets password based on a hash key
+ public function resetPassword($key)
+ {
+ $sql = "SELECT player_id FROM players WHERE reset_key = :key AND reset_until >= current_date";
+ $params = array('key' => $key);
+ $playerId = $this->_dbClient->selectValue($sql, $params);
+ if ($playerId)
+ {
+ $sql = "UPDATE players SET password = reset_password, reset_password = null,
+ reset_key = null, reset_until = null WHERE player_id = :id";
+ $params = array('id' => $playerId);
+ $ok = $this->_dbClient->query($sql, $params);
+ Daemon_MsgQueue::add(sprintf('Zmiana hasła zakończona %s.', $ok ? 'powodzeniem' : 'niepowodzeniem'));
+ }
+ else
+ Daemon_MsgQueue::add('Podany kod jest nieprawidłowy lub nieaktualny.');
+ }
+
+
+ //stores selected character's ID
+ public function setCharacterId($id)
+ {
+ $_SESSION[self::VARNAME_CHARACTER_ID] = (int) $id;
+ }
+
+
+ //updates password
+ public function setPassword($password, $passwordCopy)
+ {
+ if(!$password && !$passwordCopy)
+ return;
+ if($this->validatePassword($password, $passwordCopy))
+ {
+ $salt = Daemon::passwordSalt();
+ $this->password = sprintf('%s:%s', $salt, Daemon::passwordHash($salt, $password));
+ $this->put();
+ Daemon_MsgQueue::add('Hasło zostało zmienione.');
+ }
+ }
+
+
+ //deletes stored authentication data (logs out)
+ public function unauthenticate()
+ {
+ unset($_SESSION[self::VARNAME_CHARACTER_ID]);
+ unset($_SESSION[self::VARNAME_PLAYER_ID]);
+ unset($_SESSION[self::VARNAME_PLAYER_ADDR]);
+ unset($_SESSION[self::VARNAME_TIMESTAMP]);
+ }
+
+
+ //checks login validity
+ private function validateLogin($input, $maxLength)
+ {
+ if(!$input)
+ Daemon_MsgQueue::add('Musisz podać login.');
+ elseif(iconv_strlen($input) > $maxLength)
+ Daemon_MsgQueue::add('Wybrany login jest za długi.');
+ else return true;
+ return false;
+ }
+
+
+ //checks gender validity
+ private function validateGender($input)
+ {
+ if(!in_array($input, array_keys(Daemon_Dictionary::$genders)))
+ Daemon_MsgQueue::add('Wybrana płeć nie jest dostępna.');
+ else return true;
+ return false;
+ }
+
+
+ //checks name validity
+ private function validateName($input, $maxLength)
+ {
+ if(!$input)
+ Daemon_MsgQueue::add('Musisz podać imię.');
+ elseif(iconv_strlen($input) > $maxLength)
+ Daemon_MsgQueue::add('Wybrane imię jest za długie.');
+ else return true;
+ return false;
+ }
+
+
+ //checks password validity
+ private function validatePassword($input, $inputCopy)
+ {
+ if(!$input)
+ Daemon_MsgQueue::add('Musisz podać hasło.');
+ elseif($input != $inputCopy)
+ Daemon_MsgQueue::add('Źle powtórzone hasło.');
+ else return true;
+ return false;
+ }
+}
diff --git a/2013/daemon/lib/daemon/dictionary.php b/2013/daemon/lib/daemon/dictionary.php
new file mode 100644
index 0000000..597b7a8
--- /dev/null
+++ b/2013/daemon/lib/daemon/dictionary.php
@@ -0,0 +1,85 @@
+ 'ukryty', 'active' => 'aktywny', 'defeated' => 'pokonany');
+
+ public static $characterAttributes = array(
+ 'str' => 'Siła', 'dex' => 'Zręczność', 'vit' => 'Wytrzymałość', 'pwr' => 'Moc', 'wil' => 'Siła Woli');
+
+ public static $characterSkills = array(
+ 'pstr' => 'Silny Cios', 'patk' => 'Przycelowanie',
+ 'pdef' => 'Unik', 'pres' => 'Twardziel', 'preg' => 'Regeneracja',
+ 'mstr' => 'Koncentracja', 'matk' => 'Magia Bojowa',
+ 'mdef' => 'Kontrzaklęcie', 'mres' => 'Antymagia', 'mreg' => 'Medytacja');
+
+ public static $combatAttackTypes = array('p' => 'fizyczny', 'm' => 'magiczny');
+
+ public static $combatAttackSpecials = array(
+ Daemon_DbObject_CombatUnit::SP_POISON => 'trucizna',
+ Daemon_DbObject_CombatUnit::SP_VAMPIRE => 'wampiryzm',
+ Daemon_DbObject_CombatUnit::SP_ETHER => 'eteryczny',
+ Daemon_DbObject_CombatUnit::SP_BLOODY => 'krwawy',
+ Daemon_DbObject_CombatUnit::SP_STUN => 'ogłuszenie',
+ Daemon_DbObject_CombatUnit::SP_FACTION => 'nienawiść',
+ Daemon_DbObject_CombatUnit::SP_SWARM => 'stado',
+ );
+
+ public static $combatArmorSpecials = array(
+ Daemon_DbObject_CombatUnit::SP_DEMON => 'demon',
+ Daemon_DbObject_CombatUnit::SP_ANTIPOISON => 'odporność na trucizny',
+ Daemon_DbObject_CombatUnit::SP_ANTIVAMP => 'odporność na wampiryzm',
+ Daemon_DbObject_CombatUnit::SP_SHOCK => 'porażenie',
+ Daemon_DbObject_CombatUnit::SP_FACTION => 'fanatyzm',
+ );
+
+ public static $equipmentButtons = array('use' => 'użyj', 'equip' => 'załóż', 'unequip' => 'zdejmij');
+
+ public static $equipmentFlags = array('bound' => 'przypisany', 'identified' => 'zidentyfikowany');
+
+ public static $equipmentGroups = array(
+ 'weapon1h' => 'BROŃ 1R i TARCZE', 'weapon2h' => 'BROŃ 2R',
+ 'armor' => 'PANCERZE', 'helmet' => 'HEŁMY', 'gloves' => 'RĘKAWICE',
+ 'boots' => 'BUTY', 'pendant' => 'NASZYJNIKI', 'accesory' => 'DODATKI',
+ 'item' => 'INNE PRZEDMIOTY');
+
+ public static $equipmentSlots = array(
+ 'hand_a' => 'główna ręka', 'hand_b' => 'druga ręka',
+ 'armor' => 'pancerz', 'helmet' => 'hełm', 'gloves' => 'rękawice', 'boots' => 'buty',
+ 'pendant' => 'naszyjnik', 'accesory_a' => 'dodatek A', 'accesory_b' => 'dodatek B');
+
+ public static $genders = array('f' => 'kobieta', 'm' => 'mężczyzna', 'n' => 'nieokreślona');
+
+ public static $generatorItemTypes = array(
+ 'weapon1h' => 'broń 1R', 'weapon2h' => 'broń 2R',
+ 'armor' => 'pancerz', 'helmet' => 'hełm', 'gloves' => 'rękawice',
+ 'boots' => 'buty', 'pendant' => 'naszyjnik', 'accesory' => 'dodatek');
+
+ public static $itemTypes = array(
+ 'weapon1h' => 'broń 1R', 'weapon2h' =>'broń 2R',
+ 'armor' => 'pancerz', 'helmet' => 'hełm', 'gloves' => 'rękawice',
+ 'boots' => 'buty', 'pendant' => 'naszyjnik', 'accesory' => 'dodatek',
+ 'item' => 'niezakładalny');
+
+ public static $itemDamageTypes = array('' => 'brak', 'p' => 'fizyczne', 'm' => 'magiczne');
+
+ public static $itemWeaponTypes = array('weapon1h' => 'jednoręczna', 'weapon2h' =>'dwuręczna');
+
+ public static $itemArmorTypes = array(
+ 'armor' => 'pancerz', 'helmet' => 'hełm', 'gloves' => 'rękawice',
+ 'boots' => 'buty', 'pendant' => 'naszyjnik', 'accesory' => 'dodatek');
+
+ public static $locationTypes = array('normal' => 'zwykła', 'arena'=>'arena', 'caern'=>'caern', 'boss' => 'boss');
+
+ public static $missionProgress = array(
+ 'active' => 'aktywna', 'completed' => 'ukończona', 'rewarded' => 'nagrodzona');
+
+ public static $monsterClasses = array(1 => 'słaby', 2 => 'średni', 3 => 'silny', 4 => 'epicki');
+
+ public static $monsterClassLevels = array(1 => 0, 2 => 20, 3 => 45, 4 => 70);
+
+ public static $serviceTypes = array(
+ 'bank'=>'bank', 'healer' => 'uzdrowiciel', 'shop' => 'sklep', 'temple'=>'świątynia');
+
+ public static $skinDirUrls = array('Ciemny' => 'static/dark', 'Jasny' => 'static/light');
+}
diff --git a/2013/daemon/lib/daemon/duel.php b/2013/daemon/lib/daemon/duel.php
new file mode 100644
index 0000000..52c6e72
--- /dev/null
+++ b/2013/daemon/lib/daemon/duel.php
@@ -0,0 +1,182 @@
+characterData = $characterData;
+ }
+
+
+ public function attachDbClient(Daemon_DbClient $dbClient)
+ {
+ $this->dbClient = $dbClient;
+ }
+
+
+ public function getCombatLog()
+ {
+ return $this->combatLog;
+ }
+
+
+ //returns target character's object
+ private function getTarget($targetId)
+ {
+ $params = array('character_id' => $targetId);
+ $cdata = new Daemon_DbObject_CharacterData();
+ $cdata->attachDbClient($this->dbClient);
+ $cdata->get($params);
+ $sql = "SELECT name FROM characters WHERE character_id=:character_id";
+ $cdata->_characterName = $this->dbClient->selectValue($sql, $params);
+ return $cdata;
+ }
+
+
+ public function execute(Daemon_View $view, $locationType, $targetId)
+ {
+ $levelMultiplier = 1.2; //magic number!
+ $attacker = $this->characterData;
+ $defender = $this->getTarget($targetId);
+ $winner = null;
+ $winnerName = null;
+ $winnerXp = 0;
+ $winnerLevel = null;
+ $loserName = null;
+ $loserLevel = 0;
+ $sql = "SELECT MAX(rollover_id) FROM rollovers";
+ $rolloverId = $this->dbClient->selectValue($sql);
+ //check if combat is possibile
+ if(!$attacker->canAttack((array) $defender, $rolloverId, true))
+ return null;
+ //check combat type
+ $combatType = $attacker->getCombatType((array) $defender, $locationType);
+ if(!$combatType)
+ {
+ Daemon_MsgQueue::add('Nie możesz zaatakować tej postaci.');
+ return false;
+ }
+ $arena = ('arena' == $combatType);
+ //pre-calculate xp rewards (depends on health, which changes in combat)
+ $factionBonus = ($attacker->faction_id && $defender->faction_id
+ && ($attacker->faction_id != $defender->faction_id));
+ $attackerLevel = $attacker->getEffectiveLevel($factionBonus);
+ $defenderLevel = $defender->getEffectiveLevel($factionBonus);
+ //execute combat
+ $winner = $this->runCombat($defender, $combatType);
+ //update winner
+ if(self::WINNER_ACTOR == $winner)
+ {
+ $winnerChar = $attacker;
+ $loserChar = $defender;
+ $winnerXp = Daemon_Math::round($levelMultiplier * $defenderLevel);
+ }
+ elseif(self::WINNER_TARGET == $winner)
+ {
+ $winnerChar = $defender;
+ $loserChar = $attacker;
+ $winnerXp = Daemon_Math::round($levelMultiplier * $attackerLevel);
+ }
+ else
+ {
+ $winnerChar = null;
+ $loserChar = null;
+ }
+ if($winnerChar && $loserChar)
+ {
+ $winnerName = $winnerChar->_characterName;
+ $loserName = $loserChar->_characterName;
+ $winnerChar->xp_free += $winnerXp;
+ $sql = "UPDATE character_statistics SET duel_wins=duel_wins+1 WHERE character_id=:id";
+ $this->dbClient->query($sql, array('id' => $winnerChar->character_id));
+ $sql = "UPDATE character_statistics SET duel_losses=duel_losses+1 WHERE character_id=:id";
+ $this->dbClient->query($sql, array('id' => $loserChar->character_id));
+ }
+ //save characters
+ $attacker->put();
+ $defender->put();
+ //log duel
+ $sql = "INSERT INTO duels(rollover_id, attacker_id, defender_id, type, winner, combat_log)
+ VALUES (:rolloverId, :attackerId, :defenderId, :type, :winner, :combatLog)";
+ $params = array('rolloverId' => $rolloverId,
+ 'attackerId' => $attacker->character_id, 'defenderId' => $defender->character_id,
+ 'type' => $combatType, 'winner' => $winner, 'combatLog' => $this->combatLog);
+ $this->dbClient->query($sql, $params);
+ //generate report
+ $view->arena = $arena;
+ $view->combatLog = $this->combatLog;
+ $view->attackerName = $attacker->_characterName;
+ $view->defenderName = $defender->_characterName;
+ $view->winner = $winner;
+ $view->winnerName = $winnerName;
+ $view->winnerXp = $winnerXp;
+ $view->winnerLevel = $winnerLevel;
+ $view->loserName = $loserName;
+ ob_start();
+ $view->display('duelcombat.xml');
+ $this->combatLog = ob_get_clean();
+ return true;
+ }
+
+
+ //executes combat, returns winner flag
+ private function runCombat(Daemon_DbObject_CharacterData $target, $combatType)
+ {
+ $combat = new Daemon_Combat();
+ $logger = new Daemon_Combat_Log();
+ $combat->attachLogger($logger);
+ //prepare units
+ $attackerUnit = $this->characterData->getCombatUnit(true);
+ $defenderUnit = $target->getCombatUnit(true);
+ if('arena' == $combatType)
+ {
+ $attackerUnit->health = $attackerUnit->health_max;
+ $defenderUnit->health = $defenderUnit->health_max;
+ }
+ //execute combat
+ $combat->addUnit('a', $attackerUnit, true);
+ $combat->addUnit('b', $defenderUnit, false);
+ $combat->execute();
+ $this->combatLog = (string) $logger;
+ //check deaths
+ $deathA = ($attackerUnit->health < 1);
+ $deathB = ($defenderUnit->health < 1);
+ //update characters health, gold & equipment, return winner
+ if('arena' != $combatType)
+ {
+ $attackerUnit->put();
+ $this->characterData->health = floor($attackerUnit->health);
+ $defenderUnit->put();
+ $target->health = floor($defenderUnit->health);
+ }
+ if($deathA && $deathB)
+ {
+ if('arena' != $combatType)
+ {
+ $this->characterData->setDeath(true);
+ $target->setDeath(true, null);
+ }
+ return null;//double KO
+ }
+ elseif($deathA && !$deathB)
+ {
+ if('arena' != $combatType)
+ $this->characterData->setDeath(true);
+ return self::WINNER_TARGET;
+ }
+ elseif(!$deathA && $deathB)
+ {
+ if('arena' != $combatType)
+ $target->setDeath(true);
+ return self::WINNER_ACTOR;
+ }
+ else return null;//draw
+ }
+}
diff --git a/2013/daemon/lib/daemon/email.php b/2013/daemon/lib/daemon/email.php
new file mode 100644
index 0000000..b59569f
--- /dev/null
+++ b/2013/daemon/lib/daemon/email.php
@@ -0,0 +1,28 @@
+from = sprintf('no-reply@%s', getenv('SERVER_NAME'));
+ }
+
+
+ public function send()
+ {
+ $headers = implode("\r\n", array(
+ sprintf('From: %s', $this->from),
+ 'Content-Type:text/plain;charset=UTF-8',
+ ));
+ echo "mail($this->to, $this->subject, $this->message, $headers);";
+ exit;
+ }
+}
diff --git a/2013/daemon/lib/daemon/errorhandler.php b/2013/daemon/lib/daemon/errorhandler.php
new file mode 100644
index 0000000..2454d31
--- /dev/null
+++ b/2013/daemon/lib/daemon/errorhandler.php
@@ -0,0 +1,47 @@
+getMessage(), $ex->getCode(), $ex->getFile(), $ex->getLine(), $ex->getTraceAsString());
+ $path = sprintf('%s/exception.%s.log', self::$logDir, date('Ymd.His'));
+ self::logError($path, $data);
+ }
+
+
+ public static function logError($path, $data)
+ {
+ $stored = @file_put_contents($path, $data);
+ if(!headers_sent())
+ header('Content-Type:text/html;charset=UTF-8');
+ echo'
500 Internal Server Error ';
+ echo'Wystąpił błąd ';
+ echo'Kod gry zrobił Aaarghhh! i przestał działać. Albo zdechła baza danych. Albo cokolwiek.
';
+ if($stored)
+ {
+ echo 'Na szczęście nie zawiodło automatyczne logowanie błędów,'
+ .' więc nie musisz nic robić poza szturchnięciem admina że jego badziew znow nie działa ;)
';
+ }
+ else
+ {
+ echo 'Na dokładkę zawiodło też automatyczne logowanie błędów,'
+ .' więc to do Ciebie należy ciężkie zadanie powiadomienia o nim admina.'
+ .' Pamiętaj żeby podać wszystkie możliwe informacje o błędzie,'
+ .' ułatwi to lub w ogóle umożliwi jego wytropienie.
';
+ }
+ exit;
+ }
+}
diff --git a/2013/daemon/lib/daemon/event.php b/2013/daemon/lib/daemon/event.php
new file mode 100644
index 0000000..43a2547
--- /dev/null
+++ b/2013/daemon/lib/daemon/event.php
@@ -0,0 +1,50 @@
+characterData = $characterData;
+ }
+
+
+ public function attachDbClient(Daemon_DbClient $dbClient)
+ {
+ $this->dbClient = $dbClient;
+ }
+
+
+ public function getEventLog()
+ {
+ return $this->eventLog;
+ }
+
+
+ public function execute(Daemon_View $view, $eventId, $params)
+ {
+ //fetch event info
+ $sql = "SELECT name, handle FROM events WHERE event_id=:id";
+ $event = $this->dbClient->selectRow($sql, array('id' => $eventId));
+ if(!$event)
+ $event = array('name' => '???', 'handle' => null);
+ //check if event is implemented
+ $className = "Daemon_Event_$event[handle]";
+ if(class_exists($className, true) && is_subclass_of($className, 'Daemon_EventInterface'))
+ {
+ //valid event, execute it (may update character)
+ $handler = new $className($this->dbClient, $this->characterData, $view);
+ $this->eventLog = $handler->execute($params);
+ }
+ else
+ {
+ //no event, update character
+ Daemon_MsgQueue::add("Nieznane zdarzenie: $event[name]");
+ $this->characterData->setLocationEvent(array());
+ $this->characterData->put();
+ }
+ }
+}
diff --git a/2013/daemon/lib/daemon/event/deadend.php b/2013/daemon/lib/daemon/event/deadend.php
new file mode 100644
index 0000000..8264846
--- /dev/null
+++ b/2013/daemon/lib/daemon/event/deadend.php
@@ -0,0 +1,14 @@
+clearEvent();
+ ob_start();
+ $this->view->display('event/deadend.xml');
+ return ob_get_clean();
+ }
+}
diff --git a/2013/daemon/lib/daemon/event/help.php b/2013/daemon/lib/daemon/event/help.php
new file mode 100644
index 0000000..f2af808
--- /dev/null
+++ b/2013/daemon/lib/daemon/event/help.php
@@ -0,0 +1,12 @@
+clearEvent();
+ return 'Aaarghhh! ';
+ }
+}
diff --git a/2013/daemon/lib/daemon/event/intro.php b/2013/daemon/lib/daemon/event/intro.php
new file mode 100644
index 0000000..46aaf21
--- /dev/null
+++ b/2013/daemon/lib/daemon/event/intro.php
@@ -0,0 +1,31 @@
+clearEvent();
+ //check title
+ $sql = "SELECT 1 FROM character_titles WHERE character_id=:id AND title_id='cultist'";
+ $hasTitle = (bool) $this->dbClient->selectValue($sql, array('id' => $this->characterData->character_id));
+ if(!$hasTitle)
+ {
+ //run combat
+ $combat = new Daemon_MonsterCombat();
+ $combat->attachCharacterData($this->characterData);
+ $combat->attachDbClient($this->dbClient);
+ $combat->execute($this->view, 'cultist', true);
+ $combatLog = $combat->getCombatLog();
+ unset($combat);
+ }
+ else $combatLog = null;
+ //display log
+ ob_start();
+ $this->view->combatLog = $combatLog;
+ $this->view->hasTitle = $hasTitle;
+ $this->view->display('event/intro.xml');
+ return ob_get_clean();
+ }
+}
diff --git a/2013/daemon/lib/daemon/eventinterface.php b/2013/daemon/lib/daemon/eventinterface.php
new file mode 100644
index 0000000..9a9df3f
--- /dev/null
+++ b/2013/daemon/lib/daemon/eventinterface.php
@@ -0,0 +1,27 @@
+dbClient = $dbClient;
+ $this->characterData = $characterData;
+ $this->view = $view;
+ }
+
+
+ final protected function clearEvent()
+ {
+ $this->characterData->setLocationEvent(array());
+ $this->characterData->put();
+ }
+
+
+ abstract public function execute($params);
+}
diff --git a/2013/daemon/lib/daemon/forum.php b/2013/daemon/lib/daemon/forum.php
new file mode 100644
index 0000000..c77d52e
--- /dev/null
+++ b/2013/daemon/lib/daemon/forum.php
@@ -0,0 +1,119 @@
+dbClient = $dbClient;
+ }
+
+
+ //adds new mail message
+ public function addChat($senderId, $channelId, $content)
+ {
+ $content = Daemon::normalizeString($content, true);
+ if($content)
+ {
+ $sql = "INSERT INTO chat (sender_id, channel_id, content) VALUES (:senderId, :channelId, :content)";
+ $params = array('senderId' => $senderId, 'channelId' => $channelId, 'content' => $content);
+ $this->dbClient->query($sql, $params);
+ }
+ else Daemon_MsgQueue::add('Podaj treść wiadomości.');
+ }
+
+
+ //adds new mail message
+ public function addMail($senderId, $recipientName, $content)
+ {
+ if($recipientId = $this->getCharacterIdByName($recipientName))
+ $this->addMailById($senderId, $recipientId, $content);
+ else Daemon_MsgQueue::add('Wybrany adresat nie istnieje.');
+ }
+
+
+ //adds new mail message
+ public function addMailById($senderId, $recipientId, $content)
+ {
+ $content = Daemon::normalizeString($content, true);
+ if($content)
+ {
+ $sql = "INSERT INTO mail (sender_id, recipient_id, content) VALUES (:senderId, :recipientId, :content)";
+ $params = array('senderId' => $senderId, 'recipientId' => $recipientId, 'content' => $content);
+ $this->dbClient->query($sql, $params);
+ }
+ else Daemon_MsgQueue::add('Podaj treść wiadomości.');
+ }
+
+
+ //updates message with "reply" link
+ private static function callbackReplyLink(&$row, $key, $characterId)
+ {
+ if($row['sender_id'] && ($row['sender_id'] != $characterId))
+ $row['replyUrl'] = sprintf('?to=%s', urlencode($row['sender_name']));
+ }
+
+
+ //finds character Id by its name
+ private function getCharacterIdByName($name)
+ {
+ $sql = "SELECT character_id FROM characters WHERE name = :name";
+ return $this->dbClient->selectValue($sql, array('name' => Daemon::normalizeString($name)));
+ }
+
+
+ //fetches messages from selected channel
+ public function getChat($limit, $from, $channelId)
+ {
+ $params = array('limit' => $limit + 1, 'channelId' => $channelId);
+ $cond = 'channel_id = :channelId';
+ if($from)
+ {
+ $cond .= ' AND message_id <= :from';
+ $params['from'] = (int) $from;
+ }
+ $sql = "SELECT m.*, s.name AS sender_name
+ FROM chat m LEFT JOIN characters s ON s.character_id = m.sender_id
+ WHERE $cond ORDER BY message_id DESC LIMIT :limit";
+ $list = $this->dbClient->selectAll($sql, $params);
+ if(count($list) > $limit)
+ {
+ $next = array_pop($list);
+ $next = $next['message_id'];
+ }
+ else $next = null;
+ return array('list' => $list, 'next' => $next);
+ }
+
+
+ //fetches character's mailbox
+ public function getMail($limit, $from, $characterId)
+ {
+ $params = array('limit' => $limit + 1, 'cid1' => $characterId, 'cid2' => $characterId);
+ $cond = '(sender_id = :cid1 OR recipient_id = :cid2)';
+ if($from)
+ {
+ $cond .= ' AND message_id <= :from';
+ $params['from'] = (int) $from;
+ }
+ $sql = "SELECT m.*, s.name AS sender_name, r.name AS recipient_name
+ FROM mail m
+ LEFT JOIN characters s ON s.character_id = m.sender_id
+ LEFT JOIN characters r ON r.character_id = m.recipient_id
+ WHERE $cond ORDER BY message_id DESC LIMIT :limit";
+
+ $list = $this->dbClient->selectAll($sql, $params);
+ if(count($list) > $limit)
+ {
+ $next = array_pop($list);
+ $next = $next['message_id'];
+ }
+ else $next = null;
+ if($list)
+ array_walk($list, array(get_class($this), 'callbackReplyLink'), $characterId);
+ return array('list' => $list, 'next' => $next);
+ }
+}
diff --git a/2013/daemon/lib/daemon/inventory.php b/2013/daemon/lib/daemon/inventory.php
new file mode 100644
index 0000000..b169bfb
--- /dev/null
+++ b/2013/daemon/lib/daemon/inventory.php
@@ -0,0 +1,154 @@
+dbClient = $dbClient;
+ $this->characterData = $characterData;
+ }
+
+
+ //equips selected item
+ public function equip($inventoryId, $slot)
+ {
+ //check item
+ $sql = "SELECT item_id FROM inventory WHERE inventory_id=:id AND character_id=:charId";
+ $params = array('id' => $inventoryId, 'charId' => $this->characterData->character_id);
+ $id = $this->dbClient->selectValue($sql, $params);
+ $item = new Daemon_DbObject_Item();
+ $item->attachDbClient($this->dbClient);
+ $item->get(array('item_id' => $id));
+ $slots = $item->getSlots();
+ //check slot
+ if(!in_array($slot, $slots))
+ {
+ Daemon_MsgQueue::add('Nie możesz załozyć tego przedmiotu.');
+ return false;
+ }
+ //check for 2h weapon equipped
+ $sql = "SELECT 'weapon2h'=i.type FROM inventory inv JOIN items i USING(item_id)
+ WHERE character_id=:charId AND equipped='hand_a'";
+ $params = array('charId' => $this->characterData->character_id);
+ $zweihander = (bool) $this->dbClient->selectValue($sql, $params);
+ //equip item, unequip previous item(s)
+ if( ('weapon2h' == $item->type) || (('weapon1h' == $item->type) && $zweihander) )//2h equipping or equipped
+ $unequipSlots = "'hand_a','hand_b'";
+ else $unequipSlots = "'$slot'";
+ $sql = "UPDATE inventory SET equipped = IF(inventory_id=:id, :slot, null)
+ WHERE character_id=:charId AND (inventory_id=:id OR equipped IN ($unequipSlots))";
+ $params = array('id' => $inventoryId, 'charId' => $this->characterData->character_id, 'slot' => $slot);
+ $this->dbClient->query($sql, $params);
+ }
+
+
+ //creates equipment array based on items list
+ public function getEquipment(array $items)
+ {
+ $result = array();
+ foreach(Daemon_Dictionary::$equipmentSlots as $slot => $name)
+ $result[$slot] = array('slotName' => $name, 'inventoryId' => null, 'flags' => null, 'item' => null);
+ foreach($items as $row)
+ {
+ if(isset($result[$row['equipped']]))
+ {
+ $result[$row['equipped']]['inventoryId'] = $row['inventory_id'];
+ $result[$row['equipped']]['flags'] = $row['flags'];
+ $result[$row['equipped']]['item'] = $row['item'];
+ }
+ }
+ return $result;
+ }
+
+
+ //fetches a detailed list of character's items
+ public function getItems($status, $withoutEquipment = false)
+ {
+ $cond = "inv.character_id=:characterId";
+ if($status)
+ $cond .= " AND inv.status=:status";
+ if($withoutEquipment)
+ $cond .= " AND equipped IS NULL";
+ $sql = "SELECT inv.inventory_id, inv.item_id, inv.status, inv.flags, inv.equipped
+ FROM inventory inv JOIN items i USING(item_id)
+ WHERE $cond ORDER BY i.type, i.name, inv.inventory_id";
+ $params = array('characterId' => $this->characterData->character_id);
+ if($status)
+ $params['status'] = $status;
+ if($data = $this->dbClient->selectAll($sql, $params))
+ {
+ $result = array();
+ foreach($data as $row)
+ {
+ $row['_equipped'] = false;
+ if($row['flags'])
+ $row['flags'] = array_fill_keys(explode(',', $row['flags']), true);
+ else $row['flags'] = array();
+ $row['item'] = new Daemon_DbObject_Item();
+ $row['item']->attachDbClient($this->dbClient);
+ $row['item']->get(array('item_id' => $row['item_id']));
+ $result[$row['inventory_id']] = $row;
+ }
+ return $result;
+ }
+ else return array();
+ }
+
+
+ //groups items by status (equipped/inventory/storage)
+ public function groupItemsByStatus(array $items)
+ {
+ $result = array();
+ foreach($items as $id => $row)
+ {
+ $status = $row['status'];
+ if(('inventory' == $status) && $row['equipped'])
+ $status = 'equipment';
+ $result[$status]['items'][$id] = $row;
+ }
+ $groupNames = array('equipment' => 'Ekwipunek', 'inventory' => 'Plecak', 'storage' => 'Schowek');
+ foreach(array_keys($result) as $key)
+ {
+ if(isset($groupNames[$key]))
+ $result[$key]['name'] = $groupNames[$key];
+ else unset($groupNames[$key]);
+ }
+ return $result;
+ }
+
+
+ //groups items by type
+ public function groupItemsByType(array $items)
+ {
+ $result = array();
+ $groupNames = Daemon_Dictionary::$equipmentGroups;
+ foreach ($groupNames as $key => $name)
+ $result[$key] = array('name' => $name, 'items' => array());
+ foreach($items as $id => $row)
+ {
+ $type = $row['item']->type;
+ $result[$type]['items'][$id] = $row;
+ }
+ foreach(array_keys($result) as $key)
+ {
+ if (empty($result[$key]['items']))
+ unset($result[$key]);
+ elseif (empty($result[$key]['name']))
+ $result[$key]['name'] = '???';
+ }
+ return $result;
+ }
+
+
+ //unequips selected item
+ public function unequip($inventoryId)
+ {
+ $sql = "UPDATE inventory SET equipped=null WHERE inventory_id=:id AND character_id=:charId";
+ $params = array('id' => $inventoryId, 'charId' => $this->characterData->character_id);
+ $this->dbClient->query($sql, $params);
+ }
+}
diff --git a/2013/daemon/lib/daemon/item.php b/2013/daemon/lib/daemon/item.php
new file mode 100644
index 0000000..bcea5dc
--- /dev/null
+++ b/2013/daemon/lib/daemon/item.php
@@ -0,0 +1,54 @@
+characterData = $characterData;
+ }
+
+
+ public function attachDbClient(Daemon_DbClient $dbClient)
+ {
+ $this->dbClient = $dbClient;
+ }
+
+
+ public function getUsageLog()
+ {
+ return $this->usageLog;
+ }
+
+
+ public function execute(Daemon_View $view, $inventoryId)
+ {
+ //fetch item data
+ $sql = "SELECT s.handle, i.special_param AS params
+ FROM inventory inv JOIN items i USING(item_id)
+ LEFT JOIN item_specials s ON s.special_id = i.special_type
+ WHERE inv.character_id=:charId AND inv.inventory_id=:id AND i.type='item'";
+ $params = array('charId' => $this->characterData->character_id, 'id' => $inventoryId);
+ $item = $this->dbClient->selectRow($sql, $params);
+ if(!$item)
+ $item = array('handle' => null, 'params' => null);
+ //check if handler is implemented
+ $className = "Daemon_Item_$item[handle]";
+ if(class_exists($className, true) && is_subclass_of($className, 'Daemon_ItemInterface'))
+ {
+ //valid event, execute it (may update character)
+ $handler = new $className($this->dbClient, $this->characterData, $view);
+ $this->usageLog = $handler->execute($inventoryId, $item['params']);
+ return true;
+ }
+ else
+ {
+ //no effect
+ Daemon_MsgQueue::add('Nie masz pojęcia do czego to może służyć.');
+ return false;
+ }
+ }
+}
diff --git a/2013/daemon/lib/daemon/item/givespell.php b/2013/daemon/lib/daemon/item/givespell.php
new file mode 100644
index 0000000..d9997be
--- /dev/null
+++ b/2013/daemon/lib/daemon/item/givespell.php
@@ -0,0 +1,33 @@
+characterData;
+ //get spell data
+ $sql = "SELECT * FROM spells WHERE spell_id=:id";
+ $spell = $this->dbClient->selectRow($sql, array('id' => $spellId));
+ if(!$spell)
+ return 'Takie zaklęcie nie istnieje.';
+ //give spell to character
+ $colName = "sp_$spellId";
+ if(($char->$colName > 0) && ($char->$colName <= $spell['min_cost']))
+ return "Zaklęcie $spell[name] znasz już na poziomie mistrzowskim.";
+ if($char->$colName < 1)
+ {
+ $msg = "Poznajesz nowe zaklęcie: $spell[name].";
+ $char->$colName = $spell['max_cost'];
+ }
+ elseif($char->$colName > $spell['min_cost'])
+ {
+ $msg = "Lepiej poznajesz zaklęcie $spell[name] - potrzebujesz mniej many by je rzucić.";
+ $char->$colName -= round(($spell['max_cost'] - $spell['min_cost']) / ($spell['max_level'] - 1));
+ }
+ $char->put();
+ $this->deleteItem($inventoryId);
+ return $msg;
+ }
+}
diff --git a/2013/daemon/lib/daemon/item/heal.php b/2013/daemon/lib/daemon/item/heal.php
new file mode 100644
index 0000000..5b6ae6d
--- /dev/null
+++ b/2013/daemon/lib/daemon/item/heal.php
@@ -0,0 +1,32 @@
+characterData;
+ $params = explode(',', $params);
+ $deltaHealth = isset($params[0]) ? (int) $params[0] : 0;
+ $deltaMana = isset($params[1]) ? (int) $params[1] : 0;
+ if($deltaHealth)
+ {
+ $oldValue = $char->health;
+ $char->health = min($char->health_max, $char->health + $deltaHealth);
+ $deltaHealth = $char->health - $oldValue;
+ $msg[] = "zdrowie: +$deltaHealth";
+ }
+ if($deltaMana)
+ {
+ $oldValue = $char->mana;
+ $char->mana = min($char->mana_max, $char->mana + $deltaMana);
+ $deltaMana = $char->mana - $oldValue;
+ $msg[] = "mana: +$deltaMana";
+ }
+ $char->put();
+ $this->deleteItem($inventoryId);
+ return implode(', ', $msg);
+ }
+}
diff --git a/2013/daemon/lib/daemon/item/teleport.php b/2013/daemon/lib/daemon/item/teleport.php
new file mode 100644
index 0000000..71d6434
--- /dev/null
+++ b/2013/daemon/lib/daemon/item/teleport.php
@@ -0,0 +1,15 @@
+characterData->location_id = $locationId;
+ $this->characterData->put();
+ $this->deleteItem($inventoryId);
+ return "Nagle znajdujesz się zupełnie gdzieindziej...";
+ }
+}
+
diff --git a/2013/daemon/lib/daemon/iteminterface.php b/2013/daemon/lib/daemon/iteminterface.php
new file mode 100644
index 0000000..c15acf0
--- /dev/null
+++ b/2013/daemon/lib/daemon/iteminterface.php
@@ -0,0 +1,28 @@
+dbClient = $dbClient;
+ $this->characterData = $characterData;
+ $this->view = $view;
+ }
+
+
+ final protected function deleteItem($inventoryId)
+ {
+ $sql = "DELETE FROM inventory WHERE character_id=:charId AND inventory_id=:id";
+ $params = array('charId' => $this->characterData->character_id, 'id' => $inventoryId);
+ $this->dbClient->query($sql, $params);
+ }
+
+
+ abstract public function execute($inventoryId, $params);
+}
diff --git a/2013/daemon/lib/daemon/math.php b/2013/daemon/lib/daemon/math.php
new file mode 100644
index 0000000..7ce63b1
--- /dev/null
+++ b/2013/daemon/lib/daemon/math.php
@@ -0,0 +1,57 @@
+characterData = $characterData;
+ }
+
+
+ public function attachDbClient(Daemon_DbClient $dbClient)
+ {
+ $this->dbClient = $dbClient;
+ }
+
+
+ public function getCombatLog()
+ {
+ return $this->combatLog;
+ }
+
+
+ public function execute(Daemon_View $view, $monsterId, $fromEvent = false)
+ {
+ $char = $this->characterData;
+ $winner = null;
+ $winnerXp = 0;
+ $winnerGold = null;
+ $winnerLevel = null;
+ $winnerDrop = null;
+ $winnerMission = null;
+ //load monster
+ $monster = new Daemon_DbObject_Monster();
+ $monster->attachDbClient($this->dbClient);
+ $monster->get(array('monster_id' => $monsterId));
+ //execute combat
+ $winner = $this->runCombat($monster);
+ //check for winner, modify character
+ if(self::WINNER_ACTOR == $winner)
+ {
+ //experience
+ $winnerXp = $monster->level;
+ $this->characterData->xp_free += $winnerXp;
+ //gold
+ $winnerGold = $monster->gold;
+ $this->characterData->gold_purse += $winnerGold;
+ //level
+ if($monster->level > $this->characterData->level)
+ {
+ $winnerLevel = $monster->level;
+ $this->characterData->level = $winnerLevel;
+ }
+ else $winnerLevel = null;
+ //statistics
+ if(($monster->class >=1) && ($monster->class<=4))
+ {
+ $colname = "kills_mob{$monster->class}";
+ $sql = "UPDATE character_statistics SET $colname=$colname+1 WHERE character_id=:id";
+ $this->dbClient->query($sql, array('id' => $this->characterData->character_id));
+ }
+ //drop
+ $winnerDrop = $this->rollDrop($monster);
+ //title
+ if($monster->title_id)
+ {
+ $sql = "INSERT IGNORE INTO character_titles(character_id, title_id) VALUES(:charId, :titleId)";
+ $params = array(
+ 'charId' => $this->characterData->character_id,
+ 'titleId' => $monster->title_id);
+ $this->dbClient->query($sql, $params);
+ }
+ //mission
+ $mission = $this->characterData->getLastMission('active');
+ if(('monster' == $mission['type']) && ($monster->monster_id == $mission['params']))
+ {
+ $sql = "UPDATE character_missions SET progress='completed'
+ WHERE character_id=:cid AND rollover_id=:rid";
+ $params = array('cid' => $this->characterData->character_id, 'rid' => $mission['rollover_id']);
+ $this->dbClient->query($sql, $params);
+ $winnerMission = true;
+ }
+ }
+ elseif(self::WINNER_MONSTER == $winner)
+ $this->characterData->setDeath(true);
+ //update character
+ $this->characterData->setLocationEvent(array());
+ $this->characterData->put();
+ //generate report
+ $view->combatLog = $this->combatLog;
+ $view->fromEvent = $fromEvent;
+ $view->monsterName = $monster->name;
+ $view->winner = $winner;
+ $view->winnerXp = $winnerXp;
+ $view->winnerGold = $winnerGold;
+ $view->winnerLevel = $winnerLevel;
+ $view->winnerDrop = $winnerDrop;
+ $view->winnerMission = $winnerMission;
+ ob_start();
+ $view->display('monstercombat.xml');
+ $this->combatLog = ob_get_clean();
+ }
+
+
+ //rolls for monster drops, return array of item names
+ private function rollDrop(Daemon_DbObject_Monster $monster)
+ {
+ $itemId = null;
+ $itemName = null;
+ //check if there was any drop
+ if($monster->chance2)
+ {
+ $d256 = mt_rand(0, 255);
+ $chance = 256 * $monster->chance1 / $monster->chance2;
+ $itemId = ($d256 < $chance);
+ }
+ if($itemId)
+ {
+ $itemId = null;
+ //read drops
+ $sql = "SELECT item_id, chance, name FROM monster_drops JOIN items USING(item_id) WHERE monster_id=:id";
+ $drops = $this->dbClient->selectAll($sql, array('id' => $monster->monster_id));
+ //roll drop
+ $chanceSum = 0;
+ foreach($drops as $row)
+ $chanceSum += $row['chance'];
+ $d256 = mt_rand(0, 255);
+ foreach($drops as $row)
+ {
+ $chance = 256 * $row['chance'] / $chanceSum;
+ if($d256 < $chance)
+ {
+ $itemId = $row['item_id'];
+ $itemName = $row['name'];
+ break;
+ }
+ $d256 -= $chance;
+ }
+ //give drop
+ if($itemId)
+ {
+ $sql = "INSERT INTO inventory(character_id, item_id) VALUES (:charId, :itemId)";
+ $params = array('charId' => $this->characterData->character_id, 'itemId' => $itemId);
+ $this->dbClient->query($sql, $params);
+ }
+ }
+ return $itemName;
+ }
+
+
+ //executes combat, returns winner flag
+ private function runCombat(Daemon_DbObject_Monster $monster)
+ {
+ $combat = new Daemon_Combat();
+ $logger = new Daemon_Combat_Log();
+ $combat->attachLogger($logger);
+ //prepare units
+ $characterUnit = $this->characterData->getCombatUnit(true);
+ $monsterUnit = $monster->getCombatUnit(true);
+ $monsterUnit->health = $monsterUnit->health_max;
+ //add units
+ $combat->addUnit('a', $characterUnit, true);
+ $combat->addUnit('b', $monsterUnit, false);
+ //execute combat
+ $combat->execute();
+ $this->combatLog = (string) $logger;
+ //update character
+ $characterUnit->put();
+ $this->characterData->health = floor($characterUnit->health);
+ //check winner
+ if($this->characterData->health < 1)
+ return self::WINNER_MONSTER;
+ if($monsterUnit->health < 1)
+ return self::WINNER_ACTOR;
+ return null;
+ }
+}
diff --git a/2013/daemon/lib/daemon/msgqueue.php b/2013/daemon/lib/daemon/msgqueue.php
new file mode 100644
index 0000000..f9043bf
--- /dev/null
+++ b/2013/daemon/lib/daemon/msgqueue.php
@@ -0,0 +1,27 @@
+dbClient = $dbClient;
+ }
+
+
+ protected function callbackFormatDates(&$row)
+ {
+ $row['published'] = date(DATE_ATOM, $row['published_ts']);
+ $row['updated'] = date(DATE_ATOM, $row['updated_ts']);
+ }
+
+
+ //deletes entry by ID
+ public function deleteEntry($id)
+ {
+ $sql = "DELETE FROM newsfeed WHERE id=:id";
+ $this->dbClient->query($sql, array('id' => $id));
+ }
+
+
+ //generates an ID for a new entry
+ public function generateId($domain, $title)
+ {
+ $suffix = preg_replace('/\W+/', '-', $title);
+ return sprintf('tag:%s,%s:%s', $domain, date('Y-m-d'), $suffix);
+ }
+
+
+ //fetches last entry's update time
+ public function getLastUpdated()
+ {
+ $sql = "SELECT UNIX_TIMESTAMP(MAX(updated)) FROM newsfeed";
+ return date(DATE_ATOM, (int) $this->dbClient->selectValue($sql, array()));
+ }
+
+
+ //fetches a list of last entries
+ public function getEntries($limit, $format = false)
+ {
+ $params = array();
+ $sql = "SELECT *, UNIX_TIMESTAMP(published) AS published_ts, UNIX_TIMESTAMP(updated) AS updated_ts
+ FROM newsfeed ORDER BY published DESC";
+ if($limit)
+ {
+ $params = array('limit' => $limit);
+ $sql .= " LIMIT :limit";
+ }
+ $data = $this->dbClient->selectAll($sql, $params);
+ if($format && $data)
+ array_walk($data, array($this, 'callbackFormatDates'));
+ return $data;
+ }
+
+
+ //creates or updates a feed entry
+ public function updateEntry($id, $title, $author, $content)
+ {
+ $sql = "INSERT INTO newsfeed (id, published, title, author, content)
+ VALUES (:id, NOW(), :title, :author, :content)
+ ON DUPLICATE KEY UPDATE updated=NOW(), title=:title, author=:author, content=:content";
+ $params = array('id' => $id, 'title' => $title, 'author' => $author, 'content' => $content);
+ $this->dbClient->query($sql, $params);
+ }
+}
diff --git a/2013/daemon/lib/daemon/scyzoryk.php b/2013/daemon/lib/daemon/scyzoryk.php
new file mode 100644
index 0000000..d3db7ed
--- /dev/null
+++ b/2013/daemon/lib/daemon/scyzoryk.php
@@ -0,0 +1,73 @@
+dbClient = $dbClient;
+ }
+
+
+ public function deleteRows($tableName, $indexCol, array $ids)
+ {
+ $sql = "DELETE FROM $tableName WHERE $indexCol=:id";
+ foreach($ids as $id)
+ $this->dbClient->query($sql, array('id' => $id));
+ }
+
+
+ public function selectRow($className, $id, $id2 = null)
+ {
+ $tableName = constant("$className::TABLE_NAME");
+ $indexCol = constant("$className::INDEX_COL");
+ $indexCol2 = constant("$className::INDEX_COL2");
+ if(!$tableName || !$indexCol)
+ throw new InvalidArgumentException('Unsupported class name!');
+ $cond = array("$indexCol=:id");
+ $params = array('id' => $id);
+ if($indexCol2 && $id2)
+ {
+ $cond[] = "$indexCol2=:id2";
+ $params['id2'] = $id2;
+ }
+ $cond = implode(' AND ', $cond);
+ $sql = "SELECT * FROM $tableName WHERE $cond";
+ return $this->dbClient->selectObject($sql, $params, $className);
+ }
+
+
+ public function updateRow(Daemon_Scyzoryk_DbRow $row)
+ {
+ $row->validate();
+ $className = get_class($row);
+ $tableName = constant("$className::TABLE_NAME");
+ $indexCol = constant("$className::INDEX_COL");
+ $indexCol2 = constant("$className::INDEX_COL2");
+ if(!$tableName || !$indexCol)
+ throw new InvalidArgumentException('This table must be edited manually!');
+ $cols = array();
+ $vals = array();
+ $mods = array();
+ $params = array();
+ $ignore = array($indexCol, $indexCol2);
+ foreach($row as $col => $val)
+ {
+ $cols[] = $col;
+ $vals[] = ":$col";
+ if(!in_array($col, $ignore))
+ $mods[] = "$col=:$col";
+ $params[$col] = $val;
+ }
+ $cols = implode(', ', $cols);
+ $vals = implode(', ', $vals);
+ $mods = implode(', ', $mods);
+ if($mods)
+ $sql = "INSERT INTO $tableName ($cols) VALUES ($vals) ON DUPLICATE KEY UPDATE $mods";
+ else $sql = "REPLACE INTO $tableName ($cols) VALUES ($vals)";
+ $this->dbClient->query($sql, $params);
+ }
+}
diff --git a/2013/daemon/lib/daemon/scyzoryk/browser.php b/2013/daemon/lib/daemon/scyzoryk/browser.php
new file mode 100644
index 0000000..5ec4cfd
--- /dev/null
+++ b/2013/daemon/lib/daemon/scyzoryk/browser.php
@@ -0,0 +1,235 @@
+ $id, 'name' => $name);
+ return $this->dbClient->selectAll($sql, $params);
+ }
+
+
+ public function getCombatUnits(Daemon_Scyzoryk_Filter $filter = null)
+ {
+ $cond = array();
+ $params = array();
+ if($filter instanceof Daemon_Scyzoryk_Filter)
+ {
+ if($filter->id)
+ {
+ $cond[] = "combat_unit_id LIKE CONCAT('%', :id, '%')";
+ $params['id'] = $filter->id;
+ }
+ if($filter->name)
+ {
+ $cond[] = "name LIKE CONCAT('%', :name, '%')";
+ $params['name'] = $filter->name;
+ }
+ }
+ $cond = $cond ? 'WHERE '.implode(' AND ', $cond) : null;
+ $sql = "SELECT *, (combat_unit_id LIKE 'character-%') AS _character
+ FROM combat_units $cond ORDER BY _character, combat_unit_id";
+ return $this->dbClient->selectAll($sql, $params);
+ }
+
+
+ public function getFactionRanks($factionId)
+ {
+ $sql = "SELECT * FROM faction_ranks r LEFT JOIN titles USING(title_id) WHERE r.faction_id=:id ORDER BY rank_id";
+ return $this->dbClient->selectAll($sql, array('id' => $factionId));
+ }
+
+
+ public function getFactions()
+ {
+ $sql = "SELECT * FROM factions ORDER BY faction_id";
+ return $this->dbClient->selectAll($sql, array());
+ }
+
+
+ public function getItems(Daemon_Scyzoryk_Filter $filter)
+ {
+ $cond = array();
+ $params = array();
+ if($filter->id)
+ {
+ $cond[] = "item_id LIKE CONCAT('%', :id, '%')";
+ $params['id'] = $filter->id;
+ }
+ if($filter->name)
+ {
+ $cond[] = "name LIKE CONCAT('%', :name, '%')";
+ $params['name'] = $filter->name;
+ }
+ if($filter->type)
+ {
+ $cond[] = 'type = :type';
+ $params['type'] = $filter->type;
+ }
+ $cond = $cond ? 'WHERE '.implode(' AND ', $cond) : null;
+ $sql = "SELECT * FROM items $cond
+ ORDER BY type, damage_type, suggested_value, value, item_id";
+ return $this->dbClient->selectAll($sql, $params);
+ }
+
+
+ public function getItemTemplates()
+ {
+ $sql = "SELECT * FROM item_templates ORDER BY id";
+ return $this->dbClient->selectAll($sql, array());
+ }
+
+
+ public function getLocationEvents($locationId)
+ {
+ $sql = "SELECT * FROM location_events
+ WHERE location_id=:id ORDER BY event_id";
+ return $this->dbClient->selectAll($sql, array('id' => $locationId));
+ }
+
+
+ public function getLocationMonsters($locationId)
+ {
+ $sql = "SELECT l.*, m.name AS monster_name
+ FROM location_monsters l
+ LEFT JOIN monsters m USING(monster_id)
+ WHERE l.location_id=:id ORDER BY l.monster_id";
+ return $this->dbClient->selectAll($sql, array('id' => $locationId));
+ }
+
+
+ public function getLocationPaths($locationId)
+ {
+ $sql = "SELECT p.*, loc.name AS destination_name
+ FROM location_paths p
+ LEFT JOIN locations loc ON p.destination_id = loc.location_id
+ WHERE p.location_id=:id ORDER BY p.destination_id";
+ return $this->dbClient->selectAll($sql, array('id' => $locationId));
+ }
+
+
+ public function getLocationServices($locationId)
+ {
+ $sql = "SELECT l.*, s.name AS service_name, s.type AS service_type
+ FROM location_services l
+ LEFT JOIN services s USING(service_id)
+ WHERE l.location_id=:id ORDER BY s.service_id";
+ return $this->dbClient->selectAll($sql, array('id' => $locationId));
+ }
+
+
+ public function getLocations(Daemon_Scyzoryk_Filter $filter)
+ {
+ $cond = array();
+ $params = array();
+ if($filter->id)
+ {
+ $cond[] = "l.location_id LIKE CONCAT('%', :id, '%')";
+ $params['id'] = $filter->id;
+ }
+ if($filter->name)
+ {
+ $cond[] = "l.name LIKE CONCAT('%', :name, '%')";
+ $params['name'] = $filter->name;
+ }
+ if($filter->region_id)
+ {
+ $cond[] = 'l.region_id = :region_id';
+ $params['region_id'] = $filter->region_id;
+ }
+ $cond = $cond ? 'WHERE '.implode(' AND ', $cond) : null;
+ $sql = "SELECT l.*, r.name AS region_name,
+ ( SELECT GROUP_CONCAT(lp.destination_id SEPARATOR ',')
+ FROM location_paths lp WHERE lp.location_id=l.location_id ) AS paths,
+ ( SELECT GROUP_CONCAT(lm.monster_id SEPARATOR ',')
+ FROM location_monsters lm WHERE lm.location_id=l.location_id ) AS monsters
+ FROM locations l LEFT JOIN regions r USING(region_id) $cond ORDER BY l.region_id, l.location_id";
+ $data = $this->dbClient->selectAll($sql, $params);
+ foreach ($data as &$row)
+ {
+ $row['paths'] = explode(',', $row['paths']);
+ $row['monsters'] = explode(',', $row['monsters']);
+ }
+ return $data;
+ }
+
+
+ public function getMaps()
+ {
+ $sql = "SELECT * FROM maps ORDER BY sort, map_id";
+ return $this->dbClient->selectAll($sql, array());
+ }
+
+
+ public function getMonsterDrops($monsterId)
+ {
+ $sql = "SELECT m.*, i.name FROM monster_drops m LEFT JOIN items i USING(item_id) WHERE m.monster_id=:id";
+ return $this->dbClient->selectAll($sql, array('id' => $monsterId));
+ }
+
+
+ public function getMonsters(Daemon_Scyzoryk_Filter $filter)
+ {
+ $cond = array();
+ $params = array();
+ if($filter->id)
+ {
+ $cond[] = "m.monster_id LIKE CONCAT('%', :id, '%')";
+ $params['id'] = $filter->id;
+ }
+ if($filter->name)
+ {
+ $cond[] = "m.name LIKE CONCAT('%', :name, '%')";
+ $params['name'] = $filter->name;
+ }
+ if($filter->class)
+ {
+ $cond[] = "m.class = :class";
+ $params['class'] = $filter->class;
+ }
+ $cond = $cond ? 'WHERE '.implode(' AND ', $cond) : null;
+ $sql = "SELECT m.*, ( SELECT GROUP_CONCAT(md.item_id SEPARATOR ', ')
+ FROM monster_drops md WHERE md.monster_id=m.monster_id ) AS drops
+ FROM monsters m $cond ORDER BY m.level, m.monster_id";
+ $data = $this->dbClient->selectAll($sql, $params);
+ foreach ($data as &$row)
+ $row['drops'] = explode(',', $row['drops']);
+ return $data;
+ }
+
+
+ public function getRegions()
+ {
+ $sql = "SELECT r.*, l.name AS respawn_name
+ FROM regions r LEFT JOIN locations l ON l.location_id = r.respawn_id
+ ORDER BY r.region_id";
+ return $this->dbClient->selectAll($sql, array());
+ }
+
+
+ public function getServiceItems($serviceId)
+ {
+ $sql = "SELECT s.*, i.name, s.type='drop' AS _drop
+ FROM service_items s LEFT JOIN items i USING(item_id)
+ WHERE s.service_id=:id ORDER BY type, item_id";
+ return $this->dbClient->selectAll($sql, array('id' => $serviceId));
+ }
+
+
+ public function getServices()
+ {
+ $sql = "SELECT * FROM services ORDER BY service_id";
+ return $this->dbClient->selectAll($sql, array());
+ }
+
+
+ public function getTitles()
+ {
+ $sql = "SELECT * FROM titles ORDER BY title_id";
+ return $this->dbClient->selectAll($sql, array());
+ }
+}
diff --git a/2013/daemon/lib/daemon/scyzoryk/controller.php b/2013/daemon/lib/daemon/scyzoryk/controller.php
new file mode 100644
index 0000000..0baccb7
--- /dev/null
+++ b/2013/daemon/lib/daemon/scyzoryk/controller.php
@@ -0,0 +1,81 @@
+cfg = $cfg;
+ session_name($this->cfg->sessionName);
+ session_cache_limiter(null);
+ session_start();
+ $this->dbClient = Daemon::createDbClient($this->cfg);
+ $this->browser = new Daemon_Scyzoryk_Browser($this->dbClient);
+ $this->editor = new Daemon_Scyzoryk_Editor($this->dbClient);
+ $this->view = new Daemon_View($this->cfg);
+ $this->editId = isset($_GET['id']) ? $_GET['id'] : null;
+ $this->editId2 = isset($_GET['id2']) ? $_GET['id2'] : null;
+ }
+
+
+ //checks last action's timestamp
+ final private function checkActionTimestamp()
+ {
+ $lastAction = isset($_SESSION['ts']) ? $_SESSION['ts'] : 0.0;
+ $_SESSION['ts'] = microtime(true);
+ return (bool) ($_SESSION['ts'] >= $lastAction + $this->cfg->tsDelta);
+ }
+
+
+ final public function execute()
+ {
+ //prepare controller
+ $this->prepareModel();
+ //check last action's timestamp
+ if($_POST && !$this->checkActionTimestamp())
+ {
+ Daemon_MsgQueue::add('Operacja anulowana: za duża częstość.');
+ $_POST = array();
+ }
+ //execute commands
+ $cmdExecuted = (bool) $this->runCommands();
+ //display page
+ $this->prepareView();
+ $this->view->setPageTitle($this->pageSubtitle, $this->pageSubtitleDetails, $cmdExecuted);
+ $this->view->setMessages(Daemon_MsgQueue::getAll());
+ $this->view->display($this->pageTemplatePath, Daemon_View::MODE_HTML);
+ }
+
+
+ //page-specific
+ protected function prepareModel()
+ {
+ }
+
+
+ //page-specific
+ protected function prepareView()
+ {
+ }
+
+
+ //page-specific
+ protected function runCommands()
+ {
+ return false;
+ }
+}
diff --git a/2013/daemon/lib/daemon/scyzoryk/dbrow.php b/2013/daemon/lib/daemon/scyzoryk/dbrow.php
new file mode 100644
index 0000000..f271ff9
--- /dev/null
+++ b/2013/daemon/lib/daemon/scyzoryk/dbrow.php
@@ -0,0 +1,151 @@
+ $value)
+ if(property_exists($this, $name))
+ $this->$name = Daemon::normalizeString($value, true);
+ $this->validate();
+ }
+ public function validate() {}
+}
+
+
+class Daemon_Scyzoryk_DbRowFaction extends Daemon_Scyzoryk_DbRow
+{
+ const TABLE_NAME = 'factions';
+ const INDEX_COL = 'faction_id';
+ public $faction_id;
+ public $name;
+}
+
+
+class Daemon_Scyzoryk_DbRowFactionRank extends Daemon_Scyzoryk_DbRow
+{
+ const TABLE_NAME = 'faction_ranks';
+ const INDEX_COL = 'faction_id';
+ const INDEX_COL2 = 'rank_id';
+ public $faction_id;
+ public $rank_id;
+ public $min_points = 1;
+ public $title_id = null;
+}
+
+
+class Daemon_Scyzoryk_DbRowLocationEvent extends Daemon_Scyzoryk_DbRow
+{
+ const TABLE_NAME = 'location_events';
+ const INDEX_COL = 'location_id';
+ const INDEX_COL2 = 'event_id';
+ public $location_id;
+ public $event_id;
+ public $chance = 1;
+ public $params = '';
+}
+
+
+class Daemon_Scyzoryk_DbRowLocationMonster extends Daemon_Scyzoryk_DbRow
+{
+ const TABLE_NAME = 'location_monsters';
+ const INDEX_COL = 'location_id';
+ const INDEX_COL2 = 'monster_id';
+ public $location_id;
+ public $monster_id;
+ public $chance = 1;
+}
+
+
+class Daemon_Scyzoryk_DbRowLocationPath extends Daemon_Scyzoryk_DbRow
+{
+ const TABLE_NAME = 'location_paths';
+ const INDEX_COL = 'location_id';
+ const INDEX_COL2 = 'destination_id';
+ public $location_id;
+ public $destination_id;
+ public $name = null;
+ public $cost_gold = 0;
+ public $cost_mana = 0;
+}
+
+
+class Daemon_Scyzoryk_DbRowLocationService extends Daemon_Scyzoryk_DbRow
+{
+ const TABLE_NAME = 'location_services';
+ const INDEX_COL = 'location_id';
+ const INDEX_COL2 = 'service_id';
+ public $location_id;
+ public $service_id;
+}
+
+
+class Daemon_Scyzoryk_DbRowMap extends Daemon_Scyzoryk_DbRow
+{
+ const TABLE_NAME = 'maps';
+ const INDEX_COL = 'map_id';
+ public $map_id;
+ public $name;
+ public $url = '';
+}
+
+
+class Daemon_Scyzoryk_DbRowMonsterDrop extends Daemon_Scyzoryk_DbRow
+{
+ const TABLE_NAME = 'monster_drops';
+ const INDEX_COL = 'monster_id';
+ const INDEX_COL2 = 'item_id';
+ public $monster_id;
+ public $item_id;
+ public $chance = 1;
+}
+
+
+class Daemon_Scyzoryk_DbRowRegion extends Daemon_Scyzoryk_DbRow
+{
+ const TABLE_NAME = 'regions';
+ const INDEX_COL = 'region_id';
+ public $region_id;
+ public $name;
+ public $respawn_id = null;
+ public $picture_url = null;
+}
+
+
+class Daemon_Scyzoryk_DbRowService extends Daemon_Scyzoryk_DbRow
+{
+ const TABLE_NAME = 'services';
+ const INDEX_COL = 'service_id';
+ public $service_id;
+ public $name;
+ public $type = 'npc';
+ public $faction_id;
+ public $rank_id;
+ public $description = null;
+}
+
+
+class Daemon_Scyzoryk_DbRowServiceItem extends Daemon_Scyzoryk_DbRow
+{
+ const TABLE_NAME = 'service_items';
+ const INDEX_COL = 'service_id';
+ const INDEX_COL2 = 'item_id';
+ public $service_id;
+ public $item_id;
+ public $type = 'normal';
+ public $quantity = null;
+}
+
+
+class Daemon_Scyzoryk_DbRowTitle extends Daemon_Scyzoryk_DbRow
+{
+ const TABLE_NAME = 'titles';
+ const INDEX_COL = 'title_id';
+ public $title_id;
+ public $name_f = '';
+ public $name_m = '';
+ public $name_n = '';
+}
diff --git a/2013/daemon/lib/daemon/scyzoryk/editor.php b/2013/daemon/lib/daemon/scyzoryk/editor.php
new file mode 100644
index 0000000..1b5adba
--- /dev/null
+++ b/2013/daemon/lib/daemon/scyzoryk/editor.php
@@ -0,0 +1,139 @@
+deleteRows('combat_units', 'combat_unit_id', $ids);
+ }
+
+
+ public function deleteFactionRanks($factionId, array $ids)
+ {
+ $sql = "DELETE FROM faction_ranks WHERE faction_id=:factionId AND rank_id=:id";
+ foreach($ids as $id)
+ $this->dbClient->query($sql, array('factionId' => $factionId, 'id' => $id));
+ }
+
+
+ public function deleteFactions(array $ids)
+ {
+ $this->deleteRows('factions', 'faction_id', $ids);
+ $this->deleteRows('faction_ranks', 'faction_id', $ids);
+ }
+
+
+ public function deleteItems(array $ids)
+ {
+ $this->deleteRows('items', 'item_id', $ids);
+ $this->deleteRows('service_items', 'item_id', $ids);
+ $this->deleteRows('monster_drops', 'item_id', $ids);
+ }
+
+
+ public function deleteItemTemplates(array $ids)
+ {
+ $this->deleteRows('item_templates', 'id', $ids);
+ }
+
+
+ public function deleteLocationEvents($locationId, array $ids)
+ {
+ $sql = "DELETE FROM location_events WHERE location_id=:locationId AND event_id=:id";
+ foreach($ids as $id)
+ $this->dbClient->query($sql, array('locationId' => $locationId, 'id' => $id));
+ }
+
+
+ public function deleteLocationMonsters($locationId, array $ids)
+ {
+ $sql = "DELETE FROM location_monsters WHERE location_id=:locationId AND monster_id=:id";
+ foreach($ids as $id)
+ $this->dbClient->query($sql, array('locationId' => $locationId, 'id' => $id));
+ }
+
+
+ public function deleteLocationPaths($srcId, array $dst, array $rev = array())
+ {
+ $sql = "DELETE FROM location_paths WHERE location_id=:src AND destination_id=:dst";
+ foreach($dst as $key => $id)
+ {
+ $this->dbClient->query($sql, array('src' => $srcId, 'dst' => $id));
+ if(!empty($rev[$key]))
+ $this->dbClient->query($sql, array('src' => $id, 'dst' => $srcId));
+ }
+ }
+
+
+ public function deleteLocationServices($locationId, array $ids)
+ {
+ $sql = "DELETE FROM location_services WHERE location_id=:locationId AND service_id=:id";
+ foreach($ids as $id)
+ $this->dbClient->query($sql, array('locationId' => $locationId, 'id' => $id));
+ }
+
+
+ public function deleteLocations(array $ids)
+ {
+ $this->deleteRows('locations', 'location_id', $ids);
+ $this->deleteRows('location_events', 'location_id', $ids);
+ $this->deleteRows('location_monsters', 'location_id', $ids);
+ $this->deleteRows('location_paths', 'location_id', $ids);
+ $this->deleteRows('location_paths', 'destination_id', $ids);
+ $this->deleteRows('location_services', 'location_id', $ids);
+ }
+
+
+ public function deleteMaps(array $ids)
+ {
+ $this->deleteRows('maps', 'map_id', $ids);
+ }
+
+
+ public function deleteMonsterDrops($monsterId, array $ids)
+ {
+ $sql = "DELETE FROM monster_drops WHERE monster_id=:monsterId AND item_id=:id";
+ foreach($ids as $id)
+ $this->dbClient->query($sql, array('monsterId' => $monsterId, 'id' => $id));
+ }
+
+
+ public function deleteMonsters(array $ids)
+ {
+ $this->deleteRows('monsters', 'monster_id', $ids);
+ $this->deleteRows('monster_drops', 'monster_id', $ids);
+ $this->deleteRows('location_monsters', 'monster_id', $ids);
+ }
+
+
+ public function deleteRegions(array $ids)
+ {
+ $this->deleteRows('regions', 'region_id', $ids);
+ $sql = "UPDATE locations SET region_id = null WHERE region_id=:id";
+ foreach($ids as $id)
+ $this->dbClient->query($sql, array('id' => $id));
+ }
+
+
+ public function deleteServiceItems($serviceId, array $ids)
+ {
+ $sql = "DELETE FROM service_items WHERE service_id=:serviceId AND item_id=:id";
+ foreach($ids as $id)
+ $this->dbClient->query($sql, array('serviceId' => $serviceId, 'id' => $id));
+ }
+
+
+ public function deleteServices(array $ids)
+ {
+ $this->deleteRows('services', 'service_id', $ids);
+ $this->deleteRows('service_items', 'service_id', $ids);
+ }
+
+
+ public function deleteTitles(array $ids)
+ {
+ $this->deleteRows('titles', 'title_id', $ids);
+ }
+}
diff --git a/2013/daemon/lib/daemon/scyzoryk/filter.php b/2013/daemon/lib/daemon/scyzoryk/filter.php
new file mode 100644
index 0000000..3dafddf
--- /dev/null
+++ b/2013/daemon/lib/daemon/scyzoryk/filter.php
@@ -0,0 +1,43 @@
+cols = array_merge(array('id', 'name'), (array) $extraCols);
+ if(!isset($_SESSION[self::SESSION_VARNAME][$name]))
+ $_SESSION[self::SESSION_VARNAME][$name] = array();
+ if(!$noSession)
+ $this->data = & $_SESSION[self::SESSION_VARNAME][$name];
+ else $this->data = array();
+ }
+
+
+ public function __get($name)
+ {
+ return isset($this->data[$name]) ? $this->data[$name] : null;
+ }
+
+
+ public function __isset($name)
+ {
+ return in_array($name, $this->cols) ? true : isset($this->data[$name]);
+ }
+
+
+ public function __set($name, $value)
+ {
+ $this->data[$name] = $value;
+ }
+
+
+ public function __unset($name)
+ {
+ unset($this->data[$name]);
+ }
+}
diff --git a/2013/daemon/lib/daemon/service.php b/2013/daemon/lib/daemon/service.php
new file mode 100644
index 0000000..0ea66a7
--- /dev/null
+++ b/2013/daemon/lib/daemon/service.php
@@ -0,0 +1,47 @@
+dbClient = $dbClient;
+ $this->characterData = $characterData;
+ $this->view = $view;
+ $this->serviceData = $serviceData;
+ $this->bankEnabled = $bankEnabled;
+ $this->templeEnabled = $templeEnabled;
+ }
+
+
+ final protected function clearEvent()
+ {
+ $this->characterData->setLocationEvent(array());
+ $this->characterData->put();
+ }
+
+
+ final public function getEventLog()
+ {
+ return $this->eventLog;
+ }
+
+
+ final public function isCommand()
+ {
+ return $this->isCommand;
+ }
+
+
+ abstract public function execute($params);
+}
diff --git a/2013/daemon/lib/daemon/service/bank.php b/2013/daemon/lib/daemon/service/bank.php
new file mode 100644
index 0000000..c78a826
--- /dev/null
+++ b/2013/daemon/lib/daemon/service/bank.php
@@ -0,0 +1,95 @@
+dbClient, $this->characterData);
+ //run commands
+ $this->isCommand = $this->runCommands($params);
+ //generate output
+ $items = $inventory->getItems('inventory', true);
+ $storage = $inventory->getItems('storage');
+ $storageLimit = $this->getStorageLimit();
+ $this->view->goldBank = $this->characterData->gold_bank;
+ $this->view->goldPurse = $this->characterData->gold_purse;
+ $this->view->inventory = $items;
+ $this->view->storage = $storage;
+ $this->view->storageLimit = $storageLimit;
+ $this->view->storageFull = (count($storage) >= $storageLimit);
+ ob_start();
+ $this->view->display('service/bank.xml');
+ $this->eventLog = ob_get_clean();
+ }
+
+
+ private function runCommands($params)
+ {
+ //gold operations
+ if(isset($params['getGold'], $params['putGold']))
+ {
+ $this->goldOperations($params['getGold'], $params['putGold']);
+ return true;
+ }
+ //item operations
+ if(isset($params['getItem']))
+ {
+ $this->getItem($params['getItem']);
+ return true;
+ }
+ if(isset($params['putItem']))
+ {
+ $this->putItem($params['putItem']);
+ return true;
+ }
+ return false;
+ }
+
+
+ //fetches item from storage
+ private function getItem($inventoryId)
+ {
+ $sql = "UPDATE inventory SET status='inventory' WHERE inventory_id=:id AND character_id=:charId";
+ $params = array('id' => $inventoryId, 'charId' => $this->characterData->character_id);
+ $this->dbClient->query($sql, $params);
+ }
+
+
+ private function getStorageLimit()
+ {
+ return self::STORAGE_LIMIT + max(0, floor(log($this->characterData->level)));
+ }
+
+
+ //puts item into storage
+ private function putItem($inventoryId)
+ {
+ $sql = "SELECT COUNT(1) FROM inventory WHERE character_id=:charId AND status='storage'";
+ $n = $this->dbClient->selectValue($sql, array('charId' => $this->characterData->character_id));
+ if($n < $this->getStorageLimit())
+ {
+ $sql = "UPDATE inventory SET status='storage' WHERE inventory_id=:id AND character_id=:charId AND equipped IS NULL";
+ $params = array('id' => $inventoryId, 'charId' => $this->characterData->character_id);
+ $this->dbClient->query($sql, $params);
+ }
+ else Daemon_MsgQueue::add('Twój schowek jest pełny.');
+ }
+
+
+ private function goldOperations($getGold, $putGold)
+ {
+ //get gold
+ $delta = max(0, min((int) $getGold, $this->characterData->gold_bank));
+ $this->characterData->gold_purse += $delta;
+ $this->characterData->gold_bank -= $delta;
+ //put gold
+ $delta = max(0, min((int) $putGold, $this->characterData->gold_purse));
+ $this->characterData->gold_bank += $delta;
+ $this->characterData->gold_purse -= $delta;
+ //store mods
+ $this->characterData->put();
+ }
+}
diff --git a/2013/daemon/lib/daemon/service/healer.php b/2013/daemon/lib/daemon/service/healer.php
new file mode 100644
index 0000000..38ad744
--- /dev/null
+++ b/2013/daemon/lib/daemon/service/healer.php
@@ -0,0 +1,86 @@
+setParams();
+ //run commands
+ $this->isCommand = $this->runCommands($params);
+ //generate output
+ ob_start();
+ $this->view->characterData = $this->characterData;
+ $this->view->bankEnabled = $this->bankEnabled;
+ $this->view->deltaHealthMin = $this->deltaHealthMin;
+ $this->view->deltaHealthMax = $this->deltaHealthMax;
+ $this->view->deltaManaMin = $this->deltaManaMin;
+ $this->view->deltaManaMax = $this->deltaManaMax;
+ $this->view->display('service/healer.xml');
+ $this->eventLog = ob_get_clean();
+ }
+
+
+ private function runCommands($params)
+ {
+ if(isset($params['heal']))
+ {
+ $this->heal($params['heal'], $this->bankEnabled);
+ return true;
+ }
+ if(isset($params['rest']))
+ {
+ $this->rest();
+ return true;
+ }
+ return false;
+ }
+
+
+ //heals a random amount of health and mana
+ public function heal($gold, $bankEnabled)
+ {
+ if (!$this->characterData->payGold($gold, $bankEnabled))
+ return false;
+ $this->characterData->health += mt_rand($gold * $this->deltaHealthMin, $gold * $this->deltaHealthMax);
+ $this->characterData->mana += mt_rand($gold * $this->deltaManaMin, $gold * $this->deltaManaMax);
+ if($this->characterData->health > $this->characterData->health_max)
+ $this->characterData->health = $this->characterData->health_max;
+ if($this->characterData->mana > $this->characterData->mana_max)
+ $this->characterData->mana = $this->characterData->mana_max;
+ $this->characterData->put();
+ return true;
+ }
+
+
+ public function setParams()
+ {
+ $dbCfg = new Daemon_DbConfig($this->dbClient);
+ $params = $dbCfg->healer;
+ if(is_scalar($params))
+ $params = explode(',', $params);
+ if(isset($params[0], $params[1], $params[2], $params[3]))
+ {
+ $this->deltaHealthMin = (int) $params[0];
+ $this->deltaHealthMax = (int) $params[1];
+ $this->deltaManaMin = (int) $params[2];
+ $this->deltaManaMax = (int) $params[3];
+ }
+ }
+
+
+ //rests one turn without events
+ public function rest()
+ {
+ if(!$this->characterData->checkTurnCosts())
+ return false;
+ $this->characterData->regen(true);
+ $this->characterData->put();
+ return true;
+ }
+}
diff --git a/2013/daemon/lib/daemon/service/shop.php b/2013/daemon/lib/daemon/service/shop.php
new file mode 100644
index 0000000..9f351a3
--- /dev/null
+++ b/2013/daemon/lib/daemon/service/shop.php
@@ -0,0 +1,202 @@
+dbClient, $this->characterData);
+ //run commands
+ $this->isCommand = $this->runCommands($params);
+ //generate output
+ $equipment = array();
+ $inventory = array();
+ $items = $inventoryObj->getItems('inventory');
+ foreach($items as $key => $row)
+ {
+ $row['_price'] = ceil($row['item']->value / 2);
+ if($row['equipped'])
+ $equipment[$key] = $row;
+ else $inventory[$key] = $row;
+ }
+ $storage = $this->bankEnabled ? $inventoryObj->getItems('storage') : array();
+ foreach($storage as &$row)
+ $row['_price'] = ceil($row['item']->value / 2);
+ $this->view->shopName = $this->serviceData['name'];
+ $this->view->shopDescription = $this->serviceData['description'];
+ $this->view->goldBank = $this->characterData->gold_bank;
+ $this->view->goldPurse = $this->characterData->gold_purse;
+ $this->view->bankEnabled = $this->bankEnabled;
+ $this->view->equipment = $equipment;
+ $this->view->inventory = $inventory;
+ $this->view->storage = $storage;
+ $this->view->hasItems = ($equipment || $inventory || $storage);
+ $this->view->shopItems = $this->getItems();
+ ob_start();
+ $this->view->display('service/shop.xml');
+ $this->eventLog = ob_get_clean();
+ }
+
+
+ private function runCommands($params)
+ {
+ //sell item
+ if(isset($params['sell']))
+ {
+ $this->buyFromCharacter($params['sell']);
+ return true;
+ }
+ //buy item(s)
+ if(isset($params['buy'], $params['amount']))
+ {
+ $this->sellToCharacter($params['buy'], $params['amount'], !empty($params['bind']));
+ return true;
+ }
+ return false;
+ }
+
+
+ //buys item from character
+ public function buyFromCharacter(array $ids)
+ {
+ foreach($ids as $inventoryId)
+ {
+ $cond = "inv.inventory_id=:id AND character_id=:charId";
+ $params = array('id' => $inventoryId, 'charId' => $this->characterData->character_id);
+ if(!$this->bankEnabled)
+ $cond .= " AND inv.status!='storage'";
+ $sql = "SELECT i.item_id, i.name, i.value, inv.equipped
+ FROM inventory inv JOIN items i USING(item_id) WHERE $cond";
+ if($item = $this->dbClient->selectRow($sql, $params))
+ {
+ $sql = "DELETE FROM inventory WHERE inventory_id=:id";
+ $this->dbClient->query($sql, array('id' => $inventoryId));
+ $buyPrice = ceil($item['value'] / 2);
+ if($this->bankEnabled)
+ $this->characterData->gold_bank += $buyPrice;
+ else $this->characterData->gold_purse += $buyPrice;
+ $this->characterData->put();
+ //add to shop offer
+ $sql = "INSERT INTO service_items (service_id, item_id, type, quantity)
+ VALUES (:serviceId, :itemId, 'drop', 1) ON DUPLICATE KEY UPDATE quantity = quantity + 1";
+ $params = array('serviceId' => $this->serviceData['service_id'], 'itemId' => $item['item_id']);
+ $this->dbClient->query($sql, $params);
+ Daemon_MsgQueue::add("Sprzedajesz $item[name] za $buyPrice zł.");
+ //update character stats if item was equipped
+ if($item['equipped'])
+ {
+ $this->characterData->resetCombatStats();
+ $this->characterData->put();
+ }
+ }
+ else Daemon_MsgQueue::add('Wybrany przedmiot nie istnieje.');
+ }
+ }
+
+
+ //fetches shop's offer, grouped by item type
+ public function getItems()
+ {
+ $result = array();
+ $sql = "SELECT s.item_id, s.type, s.quantity
+ FROM service_items s JOIN items i USING(item_id)
+ WHERE service_id=:id ORDER BY i.type ASC, s.type ASC, i.damage_type ASC, i.name ASC";
+ $params = array('id' => $this->serviceData['service_id']);
+ if($data = $this->dbClient->selectAll($sql, $params))
+ {
+ $characterGold = $this->characterData->gold_purse;
+ if($this->bankEnabled)
+ $characterGold += $this->characterData->gold_bank;
+ foreach($data as $row)
+ {
+ $item = new Daemon_DbObject_Item();
+ $item->attachDbClient($this->dbClient);
+ $item->get(array('item_id' => $row['item_id']));
+ $type = $item->type;
+ $item->_price = $this->sellPrice($item->value, $row['quantity']);
+ $item->_drop = ('normal' != $row['type']);
+ $item->_quantity = $row['quantity'];
+ $item->_canBuy = ($item->_price <= $characterGold);
+ $item->_soldOff = ($item->_drop && ($item->_quantity < 1));
+ if(!empty($this->_flags['temple']))
+ $item->_canBind = ($item->value + $item->_price <= $characterGold);
+ else $item->_canBind = false;
+ $result[$type]['items'][$row['item_id']] = $item;
+ }
+ }
+ $groupNames = Daemon_Dictionary::$equipmentGroups;
+ foreach(array_keys($result) as $key)
+ {
+ if(isset($groupNames[$key]))
+ $result[$key]['name'] = $groupNames[$key];
+ else unset($groupNames[$key]);
+ }
+ return $result;
+ }
+
+
+ //calculates item price
+ public function sellPrice($value, $quantity)
+ {
+ if($quantity > 0)
+ {
+ $mult = 1 + 4 * exp(-$quantity / 64);
+ return ceil($value * $mult);
+ }
+ else return $value;
+ }
+
+
+ //sells item to character
+ public function sellToCharacter($itemId, $amount, $bind)
+ {
+ $amount = max(1, $amount);
+ if(!$this->templeEnabled)
+ $bind = false;
+ //fetch item data
+ $sql = "SELECT s.*, i.name, i.value FROM service_items s JOIN items i USING(item_id)
+ WHERE service_id=:serviceId AND item_id=:itemId";
+ $params = array('serviceId' => $this->serviceData['service_id'], 'itemId' => $itemId);
+ $item = $this->dbClient->selectRow($sql, $params);
+ //check availability
+ if(!$item)
+ {
+ Daemon_MsgQueue::add('Wybrany przedmiot nie jest dostępny.');
+ return false;
+ }
+ if(('normal' != $item['type']) && ($amount > $item['quantity']))
+ {
+ Daemon_MsgQueue::add('Nie ma tyle towaru w ofercie.');
+ return false;
+ }
+ //calculate total cost
+ $totalCost = 0;
+ for($i = 0; $i < $amount; ++$i)
+ $totalCost += $this->sellPrice($item['value'], $item['quantity'] - $i);
+ if($bind)
+ $totalCost += $amount * $item['value'];
+ //check character gold
+ if(!$this->characterData->payGold($totalCost, $this->bankEnabled))
+ return false;
+ //update service
+ if('normal' != $item['type'])
+ {
+ $sql = "UPDATE service_items SET quantity = quantity - :amount
+ WHERE service_id=:serviceId AND item_id=:itemId";
+ $params = array('serviceId' => $this->serviceData['service_id'], 'itemId' => $itemId, 'amount' => $amount);
+ $this->dbClient->query($sql, $params);
+ }
+ //update character
+ $sql = "INSERT INTO inventory(character_id, item_id, flags) VALUES (:charId, :itemId, :flags)";
+ $params = array('charId' => $this->characterData->character_id, 'itemId' => $itemId);
+ $params['flags'] = $bind ? 'bound,identified' : 'identified';
+ for($i = 0; $i < $amount; ++$i)
+ $this->dbClient->query($sql, $params);
+ //show message
+ if($amount > 1)
+ Daemon_MsgQueue::add("Kupujesz {$amount}x $item[name] za łączną kwotę $totalCost zł.");
+ else Daemon_MsgQueue::add("Kupujesz $item[name] za $totalCost zł.");
+ return true;
+ }
+}
diff --git a/2013/daemon/lib/daemon/service/temple.php b/2013/daemon/lib/daemon/service/temple.php
new file mode 100644
index 0000000..34b10e0
--- /dev/null
+++ b/2013/daemon/lib/daemon/service/temple.php
@@ -0,0 +1,333 @@
+setParams();
+ //run commands
+ $this->isCommand = $this->runCommands($params);
+ //generate output
+ ob_start();
+ $this->view->characterData = $this->characterData;
+ $this->view->bankEnabled = $this->bankEnabled;
+ $this->view->itemsToBind = $this->getItems(false, true);
+ $this->view->itemsToOffer = $this->getItems(true, false);
+ $this->view->lastMission = $this->characterData->getLastMission('completed');
+ $this->view->display('service/temple.xml');
+ $this->eventLog = ob_get_clean();
+ }
+
+
+ private function runCommands($params)
+ {
+ //bind item
+ if(isset($params['bind']))
+ {
+ $this->bindItem($params['bind']);
+ return true;
+ }
+ //pray at altar
+ if(isset($params['pray']))
+ {
+ $inventoryId = isset($params['offer']) ? $params['offer'] : null;
+ $this->pray($params['pray'], $inventoryId);
+ return true;
+ }
+ //give up mission
+ if(isset($params['giveUp']))
+ {
+ $this->removeMission();
+ return true;
+ }
+ //check mission
+ $this->checkMission();
+ return false;
+ }
+
+
+ public function bindItem($inventoryId)
+ {
+ //get item data
+ $sql = "SELECT i.name, i.value FROM inventory inv JOIN items i USING(item_id)
+ WHERE inventory_id=:id AND character_id=:charId AND NOT FIND_IN_SET('bound', inv.flags)";
+ $params = array('id' => $inventoryId, 'charId' => $this->characterData->character_id);
+ $item = $this->dbClient->selectRow($sql, $params);
+ if(!$item)
+ {
+ Daemon_MsgQueue::add('Wybrany przedmiot nie istnieje albo już jest przypisany.');
+ return false;
+ }
+ //check character gold
+ if(!$this->characterData->payGold($item['value'], $this->bankEnabled))
+ return false;
+ //bind item
+ $sql = "UPDATE inventory SET flags = CONCAT(',bound,', flags) WHERE inventory_id=:id";
+ $params = array('id' => $inventoryId);
+ $this->dbClient->query($sql, $params);
+ }
+
+
+ //check if the mission is completed
+ public function checkMission()
+ {
+ $inventoryId = null;
+ $char = $this->characterData;
+ $mission = $char->getLastMission('completed');
+ //check conditions
+ if(!$mission)
+ return false;
+ if('completed' != $mission['progress'])
+ return false;
+ if($this->serviceData['service_id'] != $mission['service_id'])
+ return false;
+ //give xp & gold
+ $rewardXp = ceil(sqrt($char->xp_used));
+ $rewardGold = mt_rand(10 * $rewardXp, 15 * $rewardXp);
+ $char->xp_free += $rewardXp;
+ if($this->bankEnabled)
+ $char->gold_bank += $rewardGold;
+ else $char->gold_purse += $rewardGold;
+ $message = "Misja wykonana. Doświadczenie +$rewardXp, złoto +$rewardGold.";
+ //give skill
+ $skillNames = Daemon_Dictionary::$characterSkills;
+ foreach(array_keys($skillNames) as $key)
+ {
+ $name = "s_$key";
+ if($char->$name)
+ unset($skillNames[$key]);
+ }
+ if(isset($skillNames['preg']) && ($char->xp_used >= $this->xpForRegen))
+ $skill = 'preg';
+ else //random other skill
+ {
+ unset($skillNames['preg']);
+ $skill = array_rand($skillNames);
+ }
+ if($skill)
+ {
+ $skillName = $skillNames[$skill];
+ $message .= " Poznajesz nową umiejętność: $skillName.";
+ $name = "s_$skill";
+ $char->$name = 1;
+ }
+ //join faction or raise reputation
+ if($this->serviceData['faction_id'])
+ $char->improveReputation($this->serviceData['faction_id'], mt_rand(4,6));
+ //save character & mission
+ $char->put();
+ $sql = "UPDATE character_statistics SET missions=missions+1 WHERE character_id=:id";
+ $this->dbClient->query($sql, array('id' => $char->character_id));
+ $sql = "UPDATE character_missions SET progress='rewarded'
+ WHERE character_id=:cid AND rollover_id=:rid";
+ $params = array('cid' => $char->character_id, 'rid' => $mission['rollover_id']);
+ $this->dbClient->query($sql, $params);
+ Daemon_MsgQueue::add($message);
+ }
+
+
+ //returns a list of unbound items
+ public function getItems($withoutEquipped = false, $withoutBound = false)
+ {
+ $result = array();
+ $cond = "character_id=:id";
+ if($withoutEquipped)
+ $cond .= " AND inv.equipped IS NULL";
+ if($withoutBound)
+ $cond .= " AND NOT FIND_IN_SET('bound', inv.flags)";
+ if(!$this->bankEnabled)
+ $cond .= " AND status!='storage'";
+ $sql = "SELECT inv.*, i.name, i.value FROM inventory inv JOIN items i USING(item_id)
+ WHERE $cond ORDER BY i.name, inv.inventory_id";
+ $params = array('id' => $this->characterData->character_id);
+ foreach($this->dbClient->selectAll($sql, $params) as $row)
+ {
+ $flags = $row['flags']
+ ? array_fill_keys(explode(',', $row['flags']), true)
+ : array();
+ $status = $row['status'];
+ if(('inventory' == $status) && $row['equipped'])
+ $status = 'equipment';
+ $result[$status][$row['inventory_id']] = array(
+ 'name' => $row['name'], 'value' => $row['value'], 'flags' => $flags);
+ }
+ return $result;
+ }
+
+
+ //gives mission if its allowed
+ private function giveMission()
+ {
+ $char = $this->characterData;
+ $lastMission = $char->getLastMission('rewarded');
+ //check character's xp
+ if($char->xp_used < $this->xpForMission)
+ {
+ switch($char->_gender)
+ {
+ case 'm': $weak = 'słaby'; break;
+ case 'k': $weak = 'słaba'; break;
+ default: $weak = 'słabe';
+ }
+ Daemon_MsgQueue::add(
+ "Słyszysz głos z nieba:"
+ ." \"Twa gorliwość jest godna pochwały, lecz jesteś jeszcze za $weak"
+ ." - wróć gdy osiągniesz $this->xpForMission doświadczenia.\""
+ );
+ return false;
+ }
+ //check last mission
+ $sql = "SELECT MAX(rollover_id) FROM rollovers";
+ $lastRollover = $this->dbClient->selectValue($sql);
+ if (empty($lastRollover))
+ {
+ Daemon_MsgQueue::add(
+ 'Słyszysz głos z nieba:'
+ .' "Twa gorliwość jest godna pochwały, lecz jeszcze za wcześnie na misje. Wróć później."'
+ );
+ return false;
+ }
+ if($lastRollover && $lastMission && ($lastRollover <= $lastMission['rollover_id']))
+ {
+ switch($char->_gender)
+ {
+ case 'm': $x = 'wykonałeś'; break;
+ case 'k': $x = 'wykonałaś'; break;
+ default: $x = 'wykonałeś';
+ }
+ Daemon_MsgQueue::add(
+ "Słyszysz głos z nieba:"
+ ." \"Twa gorliwość jest godna pochwały, lecz $x już dzisiaj misję. Wróć później."
+ );
+ return false;
+ }
+ //get character's region
+ $sql = "SELECT region_id FROM locations WHERE location_id=:id";
+ $regionId = $this->dbClient->selectValue($sql, array('id' => $char->location_id));
+ //find monster near character's level & location
+ $cols = "m.monster_id, m.name";
+ $tables = "monsters m JOIN location_monsters lm USING(monster_id) JOIN locations l USING(location_id)";
+ $params = array('regionId' => $regionId, 'level' => $char->level);
+ $sql = "SELECT $cols FROM $tables
+ WHERE l.region_id=:regionId AND m.level>=:level AND lm.chance > 0
+ ORDER BY level ASC, RAND() LIMIT 1";
+ $monster = $this->dbClient->selectRow($sql, $params);
+ if(!$monster)
+ {
+ $sql = "SELECT $cols FROM $tables
+ WHERE l.region_id=:regionId AND m.level<:level AND lm.chance > 0
+ ORDER BY level DESC, RAND() LIMIT 1";
+ $monster = $this->dbClient->selectRow($sql, $params);
+ }
+ if(!$monster)
+ return false;
+ //get random drop from that monster
+ $sql = "SELECT i.item_id, i.name, md.chance*RAND() AS ord
+ FROM items i JOIN monster_drops md USING(item_id)
+ WHERE md.monster_id=:id AND md.chance > 0 ORDER BY ord LIMIT 1";
+ $params = array('id' => $monster['monster_id']);
+ $item = $this->dbClient->selectRow($sql, $params);
+ //choose mission type
+ if($item && (mt_rand(0,255) < 128))
+ {
+ $missionType = 'item';
+ $missionParams = $item['item_id'];
+ $message = "Przynieś mi przedmiot - $item[name] - a twój wysiłek zostanie nagrodzony.";
+ }
+ else
+ {
+ $missionType = 'monster';
+ $missionParams = $monster['monster_id'];
+ $message = "Pokonaj potwora - $monster[name] - a twój wysiłek zostanie nagrodzony.";
+ }
+ $sql = "INSERT INTO character_missions(character_id, rollover_id, service_id, type, params)
+ VALUES (:cid, :rid, :sid, :type, :params)";
+ $params = array('cid' => $char->character_id, 'rid' => $lastRollover,
+ 'sid' => $this->serviceData['service_id'], 'type' => $missionType, 'params' => $missionParams);
+ $this->dbClient->query($sql, $params);
+ Daemon_MsgQueue::add("Słyszysz głos z nieba: \"$message\"");
+ return true;
+ }
+
+
+ //pray at altar, offering gold
+ public function pray($gold, $inventoryId)
+ {
+ $char = $this->characterData;
+ $mission = $char->getLastMission('active');
+ $gold = ceil(abs($gold));
+ //check character gold
+ if(!$char->payGold($gold, $this->bankEnabled))
+ return false;
+ //check item for value and mission
+ $cond = "inv.character_id=:charId AND inv.inventory_id=:inventoryId";
+ if(!$this->bankEnabled)
+ $cond .= " AND inv.status!='storage'";
+ $sql = "SELECT inv.item_id, i.value FROM inventory inv JOIN items i USING(item_id) WHERE $cond";
+ $params = array('charId' => $char->character_id, 'inventoryId' => $inventoryId);
+ $item = $this->dbClient->selectRow($sql, $params);
+ if($item)
+ {
+ $gold += $item['value'];
+ //check for mission target
+ if(($this->serviceData['service_id'] == $mission['service_id']) && ('item' == $mission['type'])
+ && ($item['item_id'] == $mission['params']) && ('completed' != $mission['progress']))
+ {
+ $mission['progress'] = 1;
+ $sql = "UPDATE character_missions SET progress='completed'
+ WHERE character_id=:cid AND rollover_id=:rid";
+ $params = array('cid' => $char->character_id, 'rid' => $mission['rollover_id']);
+ $this->dbClient->query($sql, $params);
+ }
+ //remove item
+ $sql = "DELETE FROM inventory WHERE inventory_id=:id";
+ $this->dbClient->query($sql, array('id' => $inventoryId));
+ $char->resetCombatStats();
+ }
+ //check for reaction
+ if(!$mission['progress'])
+ {
+ $wealth = $gold + $char->gold_purse + $char->gold_bank;
+ if($wealth)
+ $chance = round(2560 * $gold / $wealth);
+ else $chance = 0;
+ $d256 = mt_rand(0, 255);
+ if($chance <= $d256)
+ {
+ Daemon_msgQueue::add('Twa ofiara nie wywołała żadnej reakcji.');
+ return false;
+ }
+ }
+ //heal character & give mission
+ $char->health = $char->health_max;
+ $char->mana = $char->mana_max;
+ Daemon_MsgQueue::add('Stwórca przyjął ofiarę. Twoje rany zostały uleczone a siły odnowione.');
+ if($mission['progress'])
+ $this->checkMission();
+ else $this->giveMission();
+ //save character
+ $this->characterData->put();
+ return true;
+ }
+
+
+ //removes mission
+ public function removeMission()
+ {
+ $sql = "DELETE FROM character_missions WHERE character_id=:id AND progress < 'completed'";
+ $this->dbClient->query($sql, array('id' => $this->characterData->character_id));
+ }
+
+
+ public function setParams()
+ {
+ $dbCfg = new Daemon_DbConfig($this->dbClient);
+ $this->xpForMission = max(0, (int) $dbCfg->templeXpForMission);
+ $this->xpForRegen = max(0, (int) $dbCfg->templeXpForRegen);
+ }
+}
diff --git a/2013/daemon/lib/daemon/spell.php b/2013/daemon/lib/daemon/spell.php
new file mode 100644
index 0000000..56c14fb
--- /dev/null
+++ b/2013/daemon/lib/daemon/spell.php
@@ -0,0 +1,63 @@
+characterData = $characterData;
+ }
+
+
+ public function attachDbClient(Daemon_DbClient $dbClient)
+ {
+ $this->dbClient = $dbClient;
+ }
+
+
+ public function getUsageLog()
+ {
+ return $this->usageLog;
+ }
+
+
+ public function execute(Daemon_View $view, $spellId)
+ {
+ //fetch spell info
+ $sql = "SELECT name, handle FROM spells WHERE spell_id=:id";
+ $spell = $this->dbClient->selectRow($sql, array('id' => $spellId));
+ if(!$spell)
+ $spell = array('name' => '???', 'handle' => null);
+ //get spell's cost
+ $cost = null;
+ foreach($this->characterData->getSpells() as $row)
+ {
+ if($row['spell_id'] == $spellId)
+ $cost = $row['_cost'];
+ }
+ if(!$cost)
+ {
+ Daemon_MsgQueue::add('Nie znasz tego zaklęcia.');
+ return false;
+ }
+ //check if handler is implemented
+ $className = "Daemon_Spell_$spell[handle]";
+ if(class_exists($className, true) && is_subclass_of($className, 'Daemon_SpellInterface'))
+ {
+ //valid spell, execute it
+ $handler = new $className($this->dbClient, $this->characterData, $view);
+ $this->usageLog = $handler->execute($spellId, $cost);
+ $this->characterData->put();
+ return true;
+ }
+ else
+ {
+ //no effect
+ Daemon_MsgQueue::add("Nieznany efekt: $spell[name]");
+ return false;
+ }
+ }
+}
diff --git a/2013/daemon/lib/daemon/spell/identify.php b/2013/daemon/lib/daemon/spell/identify.php
new file mode 100644
index 0000000..c680ac9
--- /dev/null
+++ b/2013/daemon/lib/daemon/spell/identify.php
@@ -0,0 +1,15 @@
+updateCharacterMana($cost))
+ return null;
+ $sql = "UPDATE inventory SET flags=CONCAT(flags, ',identified') WHERE character_id=:id AND status!='storage'";
+ $this->dbClient->query($sql, array('id' => $this->characterData->character_id));
+ Daemon_MsgQueue::add('Zawartość plecaka została zidentyfikowana.');
+ return null;
+ }
+}
diff --git a/2013/daemon/lib/daemon/spell/scancharacter.php b/2013/daemon/lib/daemon/spell/scancharacter.php
new file mode 100644
index 0000000..89665fc
--- /dev/null
+++ b/2013/daemon/lib/daemon/spell/scancharacter.php
@@ -0,0 +1,69 @@
+updateCharacterMana($cost))
+ return null;
+ $result['char'] = $this->getCharacterByName($target);
+ if($result['char']->character_id)
+ {
+ $result['cdata'] = $result['char']->getCharacterData();
+ if($result['cdata']->level)
+ $chance = $this->characterData->level / ($this->characterData->level + $result['cdata']->level);
+ else $chance = 0;
+ if(mt_rand(0, 255) < 256 * $chance)
+ {
+ $result['equipment'] = $this->getEquipmentByCharacterId($result['char']->character_id);
+ $result['locationName'] = $this->getLocationNameById($result['cdata']->location_id);
+ }
+ else
+ {
+ Daemon_MsgQueue::add('Nie udało się rzucić zaklęcia!');
+ $result = null;
+ }
+ }
+ else
+ {
+ Daemon_MsgQueue::add('Dziwne... zaklęcie niczego nie wskazuje...');
+ $result = null;
+ }
+ }
+ $this->view->spellId = $spellId;
+ $this->view->cost = $cost;
+ $this->view->target = $target;
+ $this->view->result = $result;
+ ob_start();
+ $this->view->display('spell/scancharacter.xml');
+ return ob_get_clean();
+ }
+
+
+ private function getCharacterByName($name)
+ {
+ $char = new Daemon_DbObject_Character();
+ $char->attachDbClient($this->dbClient);
+ $char->get(array('name' => $name), true);
+ return $char;
+ }
+
+
+ private function getEquipmentByCharacterId($charId)
+ {
+ $sql = "SELECT i.name FROM inventory inv JOIN items i USING(item_id)
+ WHERE inv.character_id=:id AND inv.equipped IS NOT NULL ORDER BY i.name";
+ return $this->dbClient->selectColumn($sql, array('id' => $charId));
+ }
+
+
+ private function getLocationNameById($locationId)
+ {
+ $sql = "SELECT name FROM locations WHERE location_id=:id";
+ return $this->dbClient->selectValue($sql, array('id' => $locationId));
+ }
+}
diff --git a/2013/daemon/lib/daemon/spell/scanitem.php b/2013/daemon/lib/daemon/spell/scanitem.php
new file mode 100644
index 0000000..19356b8
--- /dev/null
+++ b/2013/daemon/lib/daemon/spell/scanitem.php
@@ -0,0 +1,65 @@
+updateCharacterMana($cost))
+ return null;
+ $item = $this->getItemByName($target);
+ if($item->item_id)
+ {
+ $result['item'] = $item;
+ $result['typeName'] = Daemon::getArrayValue(Daemon_Dictionary::$itemTypes, $item->type);
+ $result['damageType'] = Daemon::getArrayValue(Daemon_Dictionary::$itemDamageTypes, $item->damage_type);
+ $result['shops'] = $this->getShopsByItemId($result['item']->item_id);
+ $result['monsters'] = $this->getMonstersByItemId($result['item']->item_id);
+ }
+ else
+ {
+ Daemon_MsgQueue::add('Dziwne... zaklęcie niczego nie wskazuje...');
+ $result = null;
+ }
+ }
+ $this->view->spellId = $spellId;
+ $this->view->cost = $cost;
+ $this->view->target = $target;
+ $this->view->result = $result;
+ ob_start();
+ $this->view->display('spell/scanitem.xml');
+ return ob_get_clean();
+ }
+
+
+ private function getItemByName($name)
+ {
+ $item = new Daemon_DbObject_Item();
+ $item->attachDbClient($this->dbClient);
+ $item->get(array('name' => $name), true);
+ return $item;
+ }
+
+
+ private function getMonstersByItemId($itemId)
+ {
+ $sql = "SELECT m.name, m.level FROM monster_drops md JOIN monsters m USING(monster_id)
+ WHERE md.item_id=:id ORDER BY m.name";
+ $data = $this->dbClient->selectAll($sql, array('id' => $itemId));
+ $result = array();
+ foreach($data as $row)
+ $result[] = sprintf('%s (poziom %d)', $row['name'], $row['level']);
+ return $result;
+ }
+
+
+ private function getShopsByItemId($itemId)
+ {
+ $sql = "SELECT s.name FROM service_items si JOIN services s USING(service_id)
+ WHERE si.item_id=:id ORDER BY s.name";
+ return $this->dbClient->selectColumn($sql, array('id' => $itemId));
+ }
+}
diff --git a/2013/daemon/lib/daemon/spell/scanmonster.php b/2013/daemon/lib/daemon/spell/scanmonster.php
new file mode 100644
index 0000000..d8fef0b
--- /dev/null
+++ b/2013/daemon/lib/daemon/spell/scanmonster.php
@@ -0,0 +1,93 @@
+updateCharacterMana($cost))
+ return null;
+ $result['monster'] = $this->getMonsterByName($target);
+ if($result['monster']->monster_id)
+ {
+ if($result['monster']->level)
+ $chance = $this->characterData->level / ($this->characterData->level + $result['monster']->level);
+ else $chance = 0;
+ if(mt_rand(0, 255) < 256 * $chance)
+ {
+ $result['title'] = $this->getTitleById($result['monster']->title_id);
+ $result['items'] = $this->getItemsByMonsterId($result['monster']->monster_id);
+ $result['locations'] = $this->getLocationsByMonsterId($result['monster']->monster_id);
+ $result['className'] = Daemon_Dictionary::$monsterClasses[$result['monster']->class];
+ //prepare combat unit
+ $unit = (array) $result['monster']->getCombatUnit(false);
+ $attackTypes = Daemon_Dictionary::$combatAttackTypes;
+ $attackSpecials = Daemon_Dictionary::$combatAttackSpecials;
+ $armorSpecials = Daemon_Dictionary::$combatArmorSpecials;
+ $unit['type1_name'] = $unit['type1'] ? $attackTypes[$unit['type1']] : null;
+ $unit['type2_name'] = $unit['type2'] ? $attackTypes[$unit['type2']] : null;
+ $unit['sp1_name'] = $unit['sp1_type'] ? $attackSpecials[$unit['sp1_type']] : null;
+ $unit['sp2_name'] = $unit['sp2_type'] ? $attackSpecials[$unit['sp2_type']] : null;
+ $unit['armor_sp_name'] = $unit['armor_sp_type'] ? $armorSpecials[$unit['armor_sp_type']] : null;
+ $result['unit'] = $unit;
+ }
+ else
+ {
+ Daemon_MsgQueue::add('Nie udało się rzucić zaklęcia!');
+ $result = null;
+ }
+ }
+ else
+ {
+ Daemon_MsgQueue::add('Dziwne... zaklęcie niczego nie wskazuje...');
+ $result = null;
+ }
+ }
+ $this->view->spellId = $spellId;
+ $this->view->cost = $cost;
+ $this->view->target = $target;
+ $this->view->result = $result;
+ ob_start();
+ $this->view->display('spell/scanmonster.xml');
+ return ob_get_clean();
+ }
+
+
+ private function getItemsByMonsterId($monsterId)
+ {
+ $sql = "SELECT i.name, md.chance FROM monster_drops md JOIN items i USING(item_id)
+ WHERE md.monster_id=:id ORDER BY i.name";
+ $data = $this->dbClient->selectAll($sql, array('id' => $monsterId));
+ $result = array();
+ foreach($data as $row)
+ $result[] = sprintf('%s (częstość %d)', $row['name'], $row['chance']);
+ return $result;
+ }
+
+
+ private function getLocationsByMonsterId($monsterId)
+ {
+ $sql = "SELECT l.name FROM location_monsters lm JOIN locations l USING(location_id)
+ WHERE lm.monster_id=:id ORDER BY l.name";
+ return $this->dbClient->selectColumn($sql, array('id' => $monsterId));
+ }
+
+
+ private function getMonsterByName($name)
+ {
+ $monster = new Daemon_DbObject_Monster();
+ $monster->attachDbClient($this->dbClient);
+ $monster->get(array('name' => $name), true);
+ return $monster;
+ }
+
+
+ private function getTitleById($titleId)
+ {
+ $sql = "SELECT name_f, name_m, name_n FROM titles WHERE title_id=:id";
+ return $this->dbClient->selectRow($sql, array('id' => $titleId));
+ }
+}
diff --git a/2013/daemon/lib/daemon/spell/scout.php b/2013/daemon/lib/daemon/spell/scout.php
new file mode 100644
index 0000000..05a8237
--- /dev/null
+++ b/2013/daemon/lib/daemon/spell/scout.php
@@ -0,0 +1,56 @@
+updateCharacterMana($cost))
+ return null;
+ $location = $this->getLocationById($this->characterData->location_id);
+ if(!$location->location_id)
+ {
+ Daemon_MsgQueue::add('Nie da się badać Otchłani!');
+ return null;
+ }
+ $locations = array(0 => $location);
+ $pathIds = $this->getPathsByLocationId($this->characterData->location_id);
+ foreach($pathIds as $id)
+ $locations[] = $this->getLocationById($id);
+ ob_start();
+ $this->view->locations = $locations;
+ $this->view->display('spell/scout.xml');
+ return ob_get_clean();
+ }
+
+
+ private function getLocationById($locationId)
+ {
+ $location = new Daemon_DbObject_Location;
+ $location->attachDbClient($this->dbClient);
+ $location->get(array('location_id' => $locationId));
+ $location->_monsters = array();
+ $location->_events = array();
+ if($location->location_id)
+ {
+ $params = array('id' => $location->location_id);
+ $sql = "SELECT m.name, m.level, lm.chance FROM location_monsters lm JOIN monsters m USING(monster_id)
+ WHERE lm.location_id=:id ORDER BY m.name";
+ foreach($this->dbClient->selectAll($sql, $params) as $row)
+ $location->_monsters[] = sprintf('%s (poziom %d, częstość %d)', $row['name'], $row['level'], $row['chance']);
+ $sql = "SELECT e.name, le.chance FROM location_events le JOIN events e USING(event_id)
+ WHERE le.location_id=:id ORDER BY e.name";
+ foreach($this->dbClient->selectAll($sql, $params) as $row)
+ $location->_events[] = sprintf('%s (specjalne, częstość %d)', $row['name'], $row['chance']);
+ }
+ return $location;
+ }
+
+
+ private function getPathsByLocationId($locationId)
+ {
+ $sql = "SELECT destination_id FROM location_paths p
+ JOIN locations l ON l.location_id = p.destination_id
+ WHERE p.location_id=:id ORDER BY l.name, p.destination_id";
+ return $this->dbClient->selectColumn($sql, array('id' => $locationId));
+ }
+}
diff --git a/2013/daemon/lib/daemon/spellinterface.php b/2013/daemon/lib/daemon/spellinterface.php
new file mode 100644
index 0000000..da5bb72
--- /dev/null
+++ b/2013/daemon/lib/daemon/spellinterface.php
@@ -0,0 +1,32 @@
+dbClient = $dbClient;
+ $this->characterData = $characterData;
+ $this->view = $view;
+ }
+
+
+ abstract public function execute($spellId, $cost);
+
+
+ final public function updateCharacterMana($cost)
+ {
+ if($this->characterData->mana < $cost)
+ {
+ Daemon_MsgQueue::add("Koszt $cost - nie masz tyle many.");
+ return false;
+ }
+ $this->characterData->mana -= $cost;
+ return true;
+ }
+}
diff --git a/2013/daemon/lib/daemon/statistics.php b/2013/daemon/lib/daemon/statistics.php
new file mode 100644
index 0000000..3377445
--- /dev/null
+++ b/2013/daemon/lib/daemon/statistics.php
@@ -0,0 +1,233 @@
+ array('key' => 'name', 'sort' => 'name ASC', 'from' => 'name >= :from'),
+ 'lvl' => array('key' => 'level', 'sort' => 'level DESC', 'from' => 'level <= :from'),
+ 'xp' => array('key' => 'xp_used', 'sort' => 'xp_used DESC', 'from' => 'xp_used <= :from'),
+ 'fac' => array('key' => 'faction_id', 'sort' => 'faction_id ASC', 'from' => 'faction_id >= :from'),
+ 'clan' => array('key' => 'clan_id', 'sort' => 'clan_id ASC', 'from' => 'clan_id >= :from'),
+ 'date' => array('key' => 'date_created', 'sort' => 'date_created ASC', 'from' => 'date_created >= :from'),
+ 'last' => array('key' => 'last_action', 'sort' => 'last_action DESC', 'from' => 'last_action >= :from'),
+ 'win' => array('key' => 'duel_wins', 'sort' => 'duel_wins DESC', 'from' => 'duel_wins <= :from'),
+ 'los' => array('key' => 'duel_losses', 'sort' => 'duel_losses DESC', 'from' => 'duel_losses <= :from'),
+ );
+
+
+ public function __construct(Daemon_DbClient $dbClient)
+ {
+ $this->dbClient = $dbClient;
+ }
+
+
+ public function getBattleById($battleId)
+ {
+ $sql = "SELECT b.combat_log, b.type, l.name AS location_name
+ FROM battles b
+ LEFT JOIN locations l USING(location_id)
+ WHERE b.battle_id = :battleId";
+ $params = array('battleId' => $battleId);
+ return $this->dbClient->selectRow($sql, $params);
+ }
+
+
+ public function getBattles($limit, $from)
+ {
+ $params = array('limit' => $limit + 1);
+ $cond = '';
+ if($from)
+ {
+ $cond = 'WHERE battle_id <= :from';
+ $params['from'] = (int) $from;
+ }
+ $sql = "SELECT b.battle_id, b.rollover_id, b.location_id, b.type, l.name AS location_name,
+ IF(b.combat_log IS NULL OR b.combat_log = '', 0, 1) AS log_exists
+ FROM battles b
+ LEFT JOIN locations l USING(location_id)
+ $cond ORDER BY battle_id DESC LIMIT :limit";
+ return $this->getItemList($sql, $params, $limit, 'battle_id');
+ }
+
+
+ //fetches character data by ID
+ public function getCharacterById($characterId)
+ {
+ $params = array('characterId' => $characterId);
+ $sql = "SELECT c.player_id, p.name AS player_name, c.show_player,
+ c.name, c.gender, c.clan_id, cp.level, cp.xp_used,
+ c.avatar_url, c.quote, c.description, date_format(c.date_created, '%Y-%m-%d') AS date_created,
+ cl.name AS clan_name, f.name AS faction_name, COALESCE(cp.rank_id, 0) AS rank_id,
+ CASE c.gender WHEN 'f' THEN frt.name_f WHEN 'm' THEN frt.name_m ELSE frt.name_n END AS rank_name
+ FROM characters c
+ LEFT JOIN players p USING(player_id)
+ LEFT JOIN character_data cp USING(character_id)
+ LEFT JOIN factions f USING(faction_id)
+ LEFT JOIN faction_ranks fr USING(faction_id, rank_id)
+ LEFT JOIN titles frt USING(title_id)
+ LEFT JOIN clans cl USING(clan_id)
+ WHERE character_id = :characterId";
+ if($character = $this->dbClient->selectRow($sql, $params))
+ {
+ $sql = "SELECT CASE c.gender WHEN 'f' THEN t.name_f WHEN 'm' THEN t.name_m WHEN 'n' THEN t.name_n END AS title
+ FROM character_titles ct
+ JOIN characters c ON c.character_id=ct.character_id
+ JOIN titles t ON ct.title_id=t.title_id
+ WHERE ct.character_id = :characterId ORDER BY title ASC";
+ if($titles = $this->dbClient->selectColumn($sql, $params))
+ $character['titles'] = implode(', ', $titles);
+ else $character['titles'] = null;
+ $sql = "SELECT * FROM character_statistics WHERE character_id = :characterId";
+ $character['statistics'] = $this->dbClient->selectRow($sql, $params);
+ }
+ return $character;
+ }
+
+
+ //fetches a list of characters
+ public function getCharacters($limit, $from, $order, $clanId)
+ {
+ if(!isset($this->charactersOrderTypes[$order]))
+ $order = 'xp';
+ $orderParams = $this->charactersOrderTypes[$order];
+
+ $from = explode(',', $from, 2);
+ if(count($from)<2)
+ $from = array();
+
+ $params = array('limit' => $limit + 1);
+ $where = array("$orderParams[key] IS NOT NULL", "c.character_id!=392");
+ if($clanId)
+ {
+ $params['clanId'] = $clanId;
+ $where[] = 'clan_id=:clanId';
+ }
+ if($from)
+ {
+ $params['from'] = $from[1];
+ $params['characterId'] = $from[0];
+ $where[] = "($orderParams[from] AND character_id>= :characterId)";
+ }
+ if($where)
+ $where = 'WHERE ' . implode(' AND ', $where);
+ else $where = '';
+ $orderClause = $orderParams['sort'];
+ $sql = "SELECT c.character_id, c.name, c.clan_id, cp.level, cp.xp_used,
+ cp.faction_id, COALESCE(cp.rank_id, 0) AS rank_id,
+ date_format(c.date_created, '%Y-%m-%d') AS date_created,
+ date_format(c.last_action, '%Y-%m-%d') AS last_action,
+ cs.duel_wins, cs.duel_losses, cs.kills_mob1, cs.kills_mob2, cs.kills_mob3, cs.kills_mob4
+ FROM characters c
+ LEFT JOIN character_data cp USING(character_id)
+ LEFT JOIN character_statistics cs USING(character_id)
+ $where ORDER BY $orderClause, character_id ASC LIMIT :limit";
+ $list = $this->dbClient->selectAll($sql, $params);
+ if(count($list) > $limit)
+ {
+ $next = array_pop($list);
+ $next = sprintf('%s,%s', $next['character_id'], $next[$orderParams['key']]);
+ }
+ else $next = null;
+ return array('list' => $list, 'next' => $next);
+ }
+
+
+ //fetches clan data by ID
+ public function getClanById($clanId)
+ {
+ $params = array('clanId' => $clanId);
+ $sql = "SELECT cl.*, c.name AS leader_name,
+ date_format(cl.date_created, '%Y-%m-%d') AS date_created
+ FROM clans cl LEFT JOIN characters c ON c.character_id=leader_id
+ WHERE cl.clan_id = :clanId";
+ if($clan = $this->dbClient->selectRow($sql, $params))
+ {
+ $sql = "SELECT COUNT(1) FROM characters WHERE clan_id = :clanId";
+ $clan['members'] = $this->dbClient->selectColumn($sql, $params);
+ }
+ return $clan;
+ }
+
+
+ //fetches a list of clans
+ public function getClans($limit, $from)
+ {
+ $params = array('limit' => $limit + 1);
+ $cond = '';
+ if($from)
+ {
+ $cond = 'WHERE cl.clan_id >= :from';
+ $params['from'] = $from;
+ }
+ $sql = "SELECT cl.*, c.name AS leader_name, n.members,
+ date_format(cl.date_created, '%Y-%m-%d') AS date_created
+ FROM clans cl LEFT JOIN characters c ON c.character_id=leader_id
+ LEFT JOIN (
+ SELECT clan_id, COUNT(1) AS members FROM characters WHERE clan_id IS NOT NULL GROUP BY clan_id
+ ) AS n ON n.clan_id=cl.clan_id
+ $cond ORDER BY cl.clan_id ASC LIMIT :limit";
+ return $this->getItemList($sql, $params, $limit, 'clan_id');
+ }
+
+
+ //fetches combat log by duelId
+ public function getDuelById($characterId, $duelId)
+ {
+ $sql = "SELECT d.combat_log, ca.name AS attacker_name, cb.name AS defender_name
+ FROM duels d
+ LEFT JOIN characters ca ON ca.character_id=d.attacker_id
+ LEFT JOIN characters cb ON cb.character_id=d.defender_id
+ WHERE d.duel_id = :duelId AND (d.attacker_id=:characterId OR d.defender_id=:characterId)";
+ $params = array('characterId' => $characterId, 'duelId' => $duelId);
+ return $this->dbClient->selectRow($sql, $params);
+ }
+
+
+ //fetches a list of duels, optionally filtered by character
+ public function getDuels($limit, $from, $characterId, $viewerId)
+ {
+ $params = array('limit' => $limit + 1, 'vid1' => $viewerId, 'vid2' => $viewerId);
+ $where = array();
+ if($characterId)
+ {
+ $params['characterId'] = $characterId;
+ $where[] = '(attacker_id=:characterId OR defender_id=:characterId)';
+ }
+ if($from)
+ {
+ $params['from'] = (int) $from;
+ $where[] = 'duel_id <= :from';
+ }
+ if($where)
+ $where = 'WHERE ' . implode(' AND ', $where);
+ else $where = '';
+ $sql = "SELECT d.duel_id,
+ date_format(d.date_added, '%Y-%m-%d %H:%i:%s') AS date_added,
+ d.rollover_id, d.attacker_id, d.defender_id, d.type, d.winner,
+ (
+ d.combat_log IS NOT NULL AND d.combat_log != ''
+ AND (d.attacker_id = :vid1 OR d.defender_id = :vid2)
+ ) AS log_exists,
+ ca.name AS attacker_name, cb.name AS defender_name
+ FROM duels d
+ LEFT JOIN characters ca ON ca.character_id=d.attacker_id
+ LEFT JOIN characters cb ON cb.character_id=d.defender_id
+ $where ORDER BY d.duel_id DESC LIMIT :limit";
+ return $this->getItemList($sql, $params, $limit, 'duel_id');
+ }
+
+
+ private function getItemList($sql, array $params, $limit, $indexCol)
+ {
+ $list = $this->dbClient->selectAll($sql, $params);
+ if(count($list) > $limit)
+ {
+ $next = array_pop($list);
+ $next = $next[$indexCol];
+ }
+ else $next = null;
+ return array('list' => $list, 'next' => $next);
+ }
+}
diff --git a/2013/daemon/lib/daemon/view.php b/2013/daemon/lib/daemon/view.php
new file mode 100644
index 0000000..856e3af
--- /dev/null
+++ b/2013/daemon/lib/daemon/view.php
@@ -0,0 +1,133 @@
+ /u', ">\n", $str);
+ }
+}
+
+
+class Daemon_View
+{
+ public $subtitle;
+ public $subtitleDetails;
+ public $titlePrefix;
+ private $applicationTitle; //for setPageTitle()
+ private $filter;
+ private $phptal;
+ const MODE_HTML = PHPTAL::HTML5;
+ const MODE_ATOM = PHPTAL::XML;
+ const PAGING_MAX_ITEMS = 10;
+
+
+ public function __construct(Daemon_Config $cfg)
+ {
+ $this->applicationTitle = $cfg->applicationTitle;
+ $this->phptal = new PHPTAL();
+ $this->phptal->setTemplateRepository(array($cfg->getFilePath('tpl')));
+ $this->phptal->setPhpCodeDestination($cfg->getFilePath('tmp'));
+ $this->filter = new Daemon_View_Filter();
+ if($cfg->minifyHtml)
+ $this->phptal->setPostFilter($this->filter);
+ }
+
+
+ public function __set($name, $value)
+ {
+ $this->phptal->$name = $value;
+ }
+
+
+ //displays page content
+ public function display($templateName, $outputMode = self::MODE_HTML)
+ {
+ if($outputMode != self::MODE_HTML)
+ {
+ $contentType = 'Content-Type:application/atom+xml;charset=UTF-8';
+ $this->phptal->setOutputMode(PHPTAL::XML);
+ }
+ else
+ {
+ $contentType = 'Content-Type:text/html;charset=UTF-8';
+ $this->phptal->setOutputMode(PHPTAL::HTML5);
+ }
+ $this->phptal->setTemplate($templateName);
+ header($contentType);
+ echo $this->phptal->execute();
+ }
+
+
+ //generates channel menu for chat page
+ public function getChatMenu($channels, $channelId = null)
+ {
+ $menu = array();
+ foreach($channels as $key => $row)
+ $menu[] = array('name' => $row['name'], 'url' => ($key != $channelId) ? "?v=$key" : null);
+ return $menu;
+ }
+
+
+ //generates menu for statistics pages
+ public function getStatisticsMenu($type = null)
+ {
+ $menu = array(
+ 'status' => array('name' => 'Status', 'url' => 'stats'),
+ 'characters' => array('name' => 'Postacie', 'url' => 'stats-characters'),
+ 'clans' => array('name' => 'Klany', 'url' => 'stats-clans'),
+ 'duels' => array('name' => 'Pojedynki', 'url' => 'stats-duels'),
+ 'battles' => array('name' => 'Bitwy', 'url' => 'stats-battles'),
+ );
+ if(isset($menu[$type]))
+ $menu[$type]['url'] = null;
+ return $menu;
+ }
+
+
+ public function setGameHeader($playerId, $activeCharacter = null, $characterData = null, $location = null)
+ {
+ $this->__set('playerId', $playerId);
+ $this->__set('activeCharacter', $activeCharacter);
+ $this->__set('characterData', $characterData);
+ $this->__set('location', $location);
+ }
+
+
+ public function setMessages($messages)
+ {
+ $this->__set('pageMessages', $messages);
+ }
+
+
+ public function setPageSkin($skinId)
+ {
+ $skinDirUrls = Daemon_Dictionary::$skinDirUrls;
+ if (isset($skinDirUrls[$skinId]))
+ $url = $skinDirUrls[$skinId];
+ else
+ $url = array_shift($skinDirUrls);
+ $this->__set('pageSkinName', $skinId);
+ $this->__set('pageSkinUrl', $url);
+ }
+
+
+ public function setPageTitle($subtitle = null, $details = null, $isCommand = false)
+ {
+ $title = $this->applicationTitle;
+ if($subtitle)
+ {
+ if($details)
+ $title = sprintf('%s: %s - %s', $subtitle, $details, $title);
+ else $title = sprintf('%s - %s', $subtitle, $title);
+ }
+ if($isCommand)
+ $title = sprintf('[cmd] %s', $title);
+ $this->__set('pageTitle', $title);
+ }
+}
diff --git a/2013/daemon/lib/jsmin.php b/2013/daemon/lib/jsmin.php
new file mode 100644
index 0000000..2f3bcc7
--- /dev/null
+++ b/2013/daemon/lib/jsmin.php
@@ -0,0 +1,291 @@
+
+ * @copyright 2002 Douglas Crockford (jsmin.c)
+ * @copyright 2008 Ryan Grove (PHP port)
+ * @license http://opensource.org/licenses/mit-license.php MIT License
+ * @version 1.1.1 (2008-03-02)
+ * @link http://code.google.com/p/jsmin-php/
+ */
+
+class JSMin {
+ const ORD_LF = 10;
+ const ORD_SPACE = 32;
+
+ protected $a = '';
+ protected $b = '';
+ protected $input = '';
+ protected $inputIndex = 0;
+ protected $inputLength = 0;
+ protected $lookAhead = null;
+ protected $output = '';
+
+ // -- Public Static Methods --------------------------------------------------
+
+ public static function minify($js) {
+ $jsmin = new JSMin($js);
+ return $jsmin->min();
+ }
+
+ // -- Public Instance Methods ------------------------------------------------
+
+ public function __construct($input) {
+ $this->input = str_replace("\r\n", "\n", $input);
+ $this->inputLength = strlen($this->input);
+ }
+
+ // -- Protected Instance Methods ---------------------------------------------
+
+ protected function action($d) {
+ switch($d) {
+ case 1:
+ $this->output .= $this->a;
+
+ case 2:
+ $this->a = $this->b;
+
+ if ($this->a === "'" || $this->a === '"') {
+ for (;;) {
+ $this->output .= $this->a;
+ $this->a = $this->get();
+
+ if ($this->a === $this->b) {
+ break;
+ }
+
+ if (ord($this->a) <= self::ORD_LF) {
+ throw new JSMinException('Unterminated string literal.');
+ }
+
+ if ($this->a === '\\') {
+ $this->output .= $this->a;
+ $this->a = $this->get();
+ }
+ }
+ }
+
+ case 3:
+ $this->b = $this->next();
+
+ if ($this->b === '/' && (
+ $this->a === '(' || $this->a === ',' || $this->a === '=' ||
+ $this->a === ':' || $this->a === '[' || $this->a === '!' ||
+ $this->a === '&' || $this->a === '|' || $this->a === '?')) {
+
+ $this->output .= $this->a . $this->b;
+
+ for (;;) {
+ $this->a = $this->get();
+
+ if ($this->a === '/') {
+ break;
+ } elseif ($this->a === '\\') {
+ $this->output .= $this->a;
+ $this->a = $this->get();
+ } elseif (ord($this->a) <= self::ORD_LF) {
+ throw new JSMinException('Unterminated regular expression '.
+ 'literal.');
+ }
+
+ $this->output .= $this->a;
+ }
+
+ $this->b = $this->next();
+ }
+ }
+ }
+
+ protected function get() {
+ $c = $this->lookAhead;
+ $this->lookAhead = null;
+
+ if ($c === null) {
+ if ($this->inputIndex < $this->inputLength) {
+ $c = $this->input[$this->inputIndex];
+ $this->inputIndex += 1;
+ } else {
+ $c = null;
+ }
+ }
+
+ if ($c === "\r") {
+ return "\n";
+ }
+
+ if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
+ return $c;
+ }
+
+ return ' ';
+ }
+
+ protected function isAlphaNum($c) {
+ return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
+ }
+
+ protected function min() {
+ $this->a = "\n";
+ $this->action(3);
+
+ while ($this->a !== null) {
+ switch ($this->a) {
+ case ' ':
+ if ($this->isAlphaNum($this->b)) {
+ $this->action(1);
+ } else {
+ $this->action(2);
+ }
+ break;
+
+ case "\n":
+ switch ($this->b) {
+ case '{':
+ case '[':
+ case '(':
+ case '+':
+ case '-':
+ $this->action(1);
+ break;
+
+ case ' ':
+ $this->action(3);
+ break;
+
+ default:
+ if ($this->isAlphaNum($this->b)) {
+ $this->action(1);
+ }
+ else {
+ $this->action(2);
+ }
+ }
+ break;
+
+ default:
+ switch ($this->b) {
+ case ' ':
+ if ($this->isAlphaNum($this->a)) {
+ $this->action(1);
+ break;
+ }
+
+ $this->action(3);
+ break;
+
+ case "\n":
+ switch ($this->a) {
+ case '}':
+ case ']':
+ case ')':
+ case '+':
+ case '-':
+ case '"':
+ case "'":
+ $this->action(1);
+ break;
+
+ default:
+ if ($this->isAlphaNum($this->a)) {
+ $this->action(1);
+ }
+ else {
+ $this->action(3);
+ }
+ }
+ break;
+
+ default:
+ $this->action(1);
+ break;
+ }
+ }
+ }
+
+ return $this->output;
+ }
+
+ protected function next() {
+ $c = $this->get();
+
+ if ($c === '/') {
+ switch($this->peek()) {
+ case '/':
+ for (;;) {
+ $c = $this->get();
+
+ if (ord($c) <= self::ORD_LF) {
+ return $c;
+ }
+ }
+
+ case '*':
+ $this->get();
+
+ for (;;) {
+ switch($this->get()) {
+ case '*':
+ if ($this->peek() === '/') {
+ $this->get();
+ return ' ';
+ }
+ break;
+
+ case null:
+ throw new JSMinException('Unterminated comment.');
+ }
+ }
+
+ default:
+ return $c;
+ }
+ }
+
+ return $c;
+ }
+
+ protected function peek() {
+ $this->lookAhead = $this->get();
+ return $this->lookAhead;
+ }
+}
+
+// -- Exceptions ---------------------------------------------------------------
+class JSMinException extends Exception {}
+?>
\ No newline at end of file
diff --git a/2013/daemon/php.ini b/2013/daemon/php.ini
new file mode 100644
index 0000000..4f7cbbe
--- /dev/null
+++ b/2013/daemon/php.ini
@@ -0,0 +1,39 @@
+[PHP]
+; language options
+short_open_tag = Off
+asp_tags = Off
+
+; error handling and logging
+error_reporting = E_ALL | E_STRICT
+display_errors = On
+display_startup_errors = Off
+log_errors = On
+log_errors_max_len = 0
+html_errors = Off
+error_log = "path/to/error.log"
+
+; data handling
+register_globals = Off
+register_long_arrays = Off
+register_argc_argv = Off
+auto_globals_jit = On
+magic_quotes_gpc = Off
+magic_quotes_runtime = Off
+magic_quotes_sybase = Off
+default_mimetype = "text/plain"
+default_charset = "UTF-8"
+always_populate_raw_post_data = Off
+
+
+[Date]
+date.timezone = "Europe/Warsaw"
+
+[iconv]
+iconv.input_encoding = "UTF-8"
+iconv.internal_encoding = "UTF-8"
+iconv.output_encoding = "UTF-8"
+
+[Session]
+session.use_cookies = 1
+session.use_only_cookies = 1
+session.auto_start = 0
diff --git a/2013/daemon/public/.htaccess b/2013/daemon/public/.htaccess
new file mode 100644
index 0000000..be9318b
--- /dev/null
+++ b/2013/daemon/public/.htaccess
@@ -0,0 +1,10 @@
+DirectoryIndex index.php
+Redirect gone ./favicon.ico
+Redirect permanent /help http://pl.daemon.wikia.com/wiki/Daemon_Wiki
+
+RewriteEngine On
+
+RewriteCond %{SCRIPT_FILENAME} !-d
+RewriteCond %{SCRIPT_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME}.php -f
+RewriteRule ^(.*)$ /$1.php [L,QSA]
diff --git a/2013/daemon/public/_init.php b/2013/daemon/public/_init.php
new file mode 100644
index 0000000..28d45fa
--- /dev/null
+++ b/2013/daemon/public/_init.php
@@ -0,0 +1,31 @@
+characters = $this->player->getCharacters();
+ //mark active character
+ $activeCharId = $this->player->getCharacterId();
+ if($activeCharId && isset($this->characters[$activeCharId]))
+ $this->characters[$activeCharId]['active'] = true;
+ else $activeCharId = null;
+ //prepare view
+ $this->view->characters = $this->characters;
+ $this->view->genders = Daemon_Dictionary::$genders;
+ $this->view->preview = Daemon::formatMessage($this->activeCharacter->description, true);
+ }
+
+
+ protected function runCommands()
+ {
+ $turnDelta = $this->dbCfg->turnDelta;
+ $turnLimit = $this->dbCfg->turnLimit;
+ //create character
+ if(isset($_POST['newName'], $_POST['newGender']))
+ {
+ $this->player->addCharacter($_POST['newName'], $_POST['newGender'], $turnDelta, $turnLimit);
+ return true;
+ }
+ //set active character
+ if(isset($_POST['use']))
+ {
+ $this->player->setCharacterId($_POST['use']);
+ $this->activeCharacter = $this->player->getActiveCharacter();
+ $this->characterData = $this->activeCharacter->getCharacterData();
+ $this->activeCharacter->updateLastAction();
+ return true;
+ }
+ //reset or delete character
+ if(isset($_POST['char'], $_POST['action']))
+ {
+ $reset = ($_POST['action'] == 'reset');
+ $this->player->deleteCharacter($_POST['char'], $reset, $turnDelta, $turnLimit);
+ $this->activeCharacter = $this->player->getActiveCharacter();
+ $this->characterData = $this->activeCharacter->getCharacterData();
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Account($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/auth.php b/2013/daemon/public/auth.php
new file mode 100644
index 0000000..18abf53
--- /dev/null
+++ b/2013/daemon/public/auth.php
@@ -0,0 +1,46 @@
+cfg->applicationUrl;
+ if($this->player->getPlayerId())
+ $url .= 'account';
+ Daemon::redirect($url);
+ exit;
+ }
+
+
+ protected function runCommands()
+ {
+ if(!$this->dbCfg->loginEnabled)
+ return false;
+ if(isset($_POST['login'], $_POST['pass']))
+ {
+ $this->player->authenticate($_POST['login'], $_POST['pass']);
+ return true;
+ }
+ if(isset($_POST['logout']))
+ {
+ $this->player->unauthenticate();
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Auth($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/character.php b/2013/daemon/public/character.php
new file mode 100644
index 0000000..17b2db3
--- /dev/null
+++ b/2013/daemon/public/character.php
@@ -0,0 +1,89 @@
+eventLog)
+ {
+ $this->pageSubtitle = 'Użycie zaklęcia';
+ $this->pageTemplatePath = 'event.xml';
+ $this->view->eventLog = $this->eventLog;
+ return;
+ }
+ //prepare attributes list
+ $list = array();
+ foreach(Daemon_Dictionary::$characterAttributes as $key => $name)
+ {
+ $col = "a_$key";
+ $value = $this->characterData->$col;
+ $list[$key] = array('name' => $name, 'value' => $value, 'inc' => ($value <= $this->characterData->xp_free));
+ }
+ $this->view->attributes = $list;
+ //prepare skill list
+ $list = array();
+ foreach(Daemon_Dictionary::$characterSkills as $key => $name)
+ {
+ $col = "s_$key";
+ $value = $this->characterData->$col;
+ $list[$key] = array('name' => $name, 'value' => $value, 'inc' => ($value <= $this->characterData->xp_free));
+ }
+ $this->view->skills = $list;
+ //prepare spell list
+ $this->view->spells = $this->characterData->getSpells();
+ //prepare combat stats
+ $unit = (array) $this->characterData->getCombatUnit();
+ $attackTypes = Daemon_Dictionary::$combatAttackTypes;
+ $attackSpecials = Daemon_Dictionary::$combatAttackSpecials;
+ $armorSpecials = Daemon_Dictionary::$combatArmorSpecials;
+ $unit['type1_name'] = $unit['type1'] ? $attackTypes[$unit['type1']] : null;
+ $unit['type2_name'] = $unit['type2'] ? $attackTypes[$unit['type2']] : null;
+ $unit['sp1_name'] = $unit['sp1_type'] ? $attackSpecials[$unit['sp1_type']] : null;
+ $unit['sp2_name'] = $unit['sp2_type'] ? $attackSpecials[$unit['sp2_type']] : null;
+ $unit['armor_sp_name'] = $unit['armor_sp_type'] ? $armorSpecials[$unit['armor_sp_type']] : null;
+ $this->view->combatStats = $unit;
+ }
+
+
+ protected function runCommands()
+ {
+ //improve attribute
+ if(isset($_POST['incA']))
+ {
+ $this->characterData->improveAttribute($_POST['incA']);
+ return true;
+ }
+ //improve skill
+ if(isset($_POST['incS']))
+ {
+ $this->characterData->improveSkill($_POST['incS']);
+ return true;
+ }
+ //cast spell
+ if(isset($_POST['cast']))
+ {
+ $handler = new Daemon_Spell();
+ $handler->attachCharacterData($this->characterData);
+ $handler->attachDbClient($this->dbClient);
+ $handler->execute($this->view, $_POST['cast']);
+ $this->eventLog = $handler->getUsageLog();
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Character($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/chat.php b/2013/daemon/public/chat.php
new file mode 100644
index 0000000..2bd7bdf
--- /dev/null
+++ b/2013/daemon/public/chat.php
@@ -0,0 +1,61 @@
+forum = new Daemon_Forum($this->dbClient);
+ $this->channels = $this->activeCharacter->getForumChannels();
+ $this->channelId = isset($_GET['v']) ? $_GET['v'] : null;
+ if(!isset($this->channels[$this->channelId]))
+ $this->channelId = 'public';
+ $this->writeAccess = !empty($this->channels[$this->channelId]['writable']);
+ }
+
+
+ public function prepareView()
+ {
+ $listLimit = max(1, (int) $this->dbCfg->listLimitMessages);
+ $listOffset = isset($_GET['n']) ? (int) $_GET['n'] : 0;
+
+ $this->pageSubtitleUseQuery = true;
+ $from = isset($_GET['from']) ? (int) $_GET['from'] : 0;
+ $data = $this->forum->getChat($listLimit, $from, $this->channelId);
+
+ foreach($data['list'] as &$row)
+ $row['content'] = Daemon::formatMessage($row['content'], true);
+ $this->view->inputMsg = isset($_POST['msg']) ? $_POST['msg'] : null;
+ $this->view->list = $data['list'];
+
+ $this->view->menu = $this->view->getChatMenu($this->channels, $this->channelId);
+ $this->view->nextUrl = $data['next'] ? '?from='.urlencode($data['next']) : null;
+ $this->view->channelId = $this->channelId;
+ $this->view->writeAccess = $this->writeAccess;
+ }
+
+
+ protected function runCommands()
+ {
+ if($this->writeAccess && isset($_POST['msg']))
+ {
+ $this->forum->addChat($this->player->getCharacterId(), $this->channelId, $_POST['msg']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Chat($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/clan.php b/2013/daemon/public/clan.php
new file mode 100644
index 0000000..f0eaab5
--- /dev/null
+++ b/2013/daemon/public/clan.php
@@ -0,0 +1,129 @@
+clan = new Daemon_DbObject_Clan;
+ if($this->activeCharacter->clan_id)
+ {
+ $this->clan->attachDbClient($this->dbClient);
+ $this->clan->get(array('clan_id' => $this->activeCharacter->clan_id));
+ if($this->clan->leader_id)
+ $this->isLeader = ($this->clan->leader_id == $this->activeCharacter->character_id);
+ }
+ }
+
+
+ public function prepareView()
+ {
+ if($this->clan->clan_id)
+ $this->prepareViewMember();
+ else $this->prepareViewSolo();
+ }
+
+
+ private function prepareViewMember()
+ {
+ $this->view->clan = $this->clan;
+ $this->view->preview = Daemon::formatMessage($this->clan->description, true);
+ $this->view->isLeader = $this->isLeader;
+ $this->view->members = $this->clan->getMembers($this->activeCharacter->character_id);
+ $invitations = $this->clan->getInvitations();
+ foreach($invitations as &$row)
+ $row['description'] = Daemon::formatMessage($row['description'], true);
+ $this->view->invitations = $invitations;
+ }
+
+
+ private function prepareViewSolo()
+ {
+ $this->view->invitations = $this->activeCharacter->getInvitations();
+ }
+
+
+ public function runCommands()
+ {
+ if($this->clan->clan_id)
+ return $this->runCommandsMember();
+ else return $this->runCommandsSolo();
+ }
+
+
+ private function runCommandsMember()
+ {
+ if($this->isLeader)
+ {
+ if(isset($_POST['accept']))
+ {
+ $forum = new Daemon_Forum($this->dbClient);
+ $this->clan->acceptCharacter($_POST['accept'], $forum);
+ return true;
+ }
+ if(isset($_POST['kick']))
+ {
+ $forum = new Daemon_Forum($this->dbClient);
+ $this->clan->kickMember($_POST['kick'], $forum);
+ return true;
+ }
+ if(isset($_POST['setLeader'], $_POST['desc']))
+ {
+ if($_POST['setLeader'] && ($_POST['setLeader'] != $this->clan->leader_id))
+ {
+ $this->clan->leader_id = $_POST['setLeader'];
+ $this->isLeader = false;
+ }
+ $this->clan->description = $_POST['desc'];
+ $this->clan->put();
+ return true;
+ }
+ if(isset($_POST['disband']))
+ {
+ $this->clan->delete();
+ $this->clan = new Daemon_DbObject_Clan;
+ $this->activeCharacter->clan_id = null;
+ return true;
+ }
+ }
+ if(isset($_POST['leave']))
+ {
+ $this->activeCharacter->clan_id = null;
+ $this->activeCharacter->put();
+ return true;
+ }
+ }
+
+
+ private function runCommandsSolo()
+ {
+ if(isset($_POST['join'], $_POST['desc']))
+ {
+ $forum = new Daemon_Forum($this->dbClient);
+ $this->activeCharacter->inviteClan($_POST['join'], $_POST['desc'], $forum);
+ return true;
+ }
+ if(isset($_POST['create'], $_POST['id'], $_POST['name']))
+ {
+ $this->activeCharacter->createClan($_POST['id'], $_POST['name']);
+ $this->prepareModel();
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/duel.php b/2013/daemon/public/duel.php
new file mode 100644
index 0000000..8f35305
--- /dev/null
+++ b/2013/daemon/public/duel.php
@@ -0,0 +1,39 @@
+view->combatLog = $this->combatLog;
+ }
+
+
+ public function runCommands()
+ {
+ //attack
+ if(isset($_POST['attack']))
+ {
+ $this->view->setGameHeader($this->player->getPlayerId(),
+ $this->activeCharacter, $this->characterData, $this->location);
+ $this->combatLog = $this->characterData->attack($this->view, $_POST['attack'], $this->location->type);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Duel($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/edit-account.php b/2013/daemon/public/edit-account.php
new file mode 100644
index 0000000..72aa5d1
--- /dev/null
+++ b/2013/daemon/public/edit-account.php
@@ -0,0 +1,41 @@
+view->player = $this->player;
+ $this->view->skins = array_keys(Daemon_Dictionary::$skinDirUrls);
+ }
+
+
+ protected function runCommands()
+ {
+ //update player data
+ if(isset($_POST['name'], $_POST['pass1'], $_POST['pass2'], $_POST['skin'], $_POST['email']))
+ {
+ if($_POST['pass1'] || $_POST['pass2'])
+ $this->player->setPassword($_POST['pass1'], $_POST['pass2']);
+ $_POST['name'] = Daemon::normalizeString($_POST['name']);
+ $this->player->name = $_POST['name'] ? $_POST['name'] : null;
+ $this->player->skin = $_POST['skin'] ? $_POST['skin'] : null;
+ $this->player->email = $_POST['email'] ? $_POST['email'] : null;
+ $this->player->put();
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/edit-character.php b/2013/daemon/public/edit-character.php
new file mode 100644
index 0000000..b79357a
--- /dev/null
+++ b/2013/daemon/public/edit-character.php
@@ -0,0 +1,60 @@
+character = new Daemon_DbObject_Character;
+ if($id)
+ {
+ $this->character->attachDbClient($this->dbClient);
+ $params = array('character_id' => $id, 'player_id' => $this->player->getPlayerId());
+ $this->character->get($params);
+ }
+ if(!$this->character->character_id)
+ {
+ Daemon_MsgQueue::add('Wybrana postać nie istnieje.');
+ Daemon::redirect($this->cfg->getUrl('map'));
+ exit;
+ }
+ }
+
+
+ public function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->character->name;
+ $this->view->character = $this->character;
+ $this->view->preview = Daemon::formatMessage($this->character->description, true);
+ }
+
+
+ protected function runCommands()
+ {
+ //update character
+ if(isset($_POST['avatar'], $_POST['quote'], $_POST['desc']))
+ {
+ $this->character->show_player = !empty($_POST['player']);
+ $this->character->avatar_url = $_POST['avatar'];
+ $this->character->quote = $_POST['quote'];
+ $this->character->description = $_POST['desc'];
+ $this->character->put();
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Account($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/index.php b/2013/daemon/public/index.php
new file mode 100644
index 0000000..4de6119
--- /dev/null
+++ b/2013/daemon/public/index.php
@@ -0,0 +1,27 @@
+news = new Daemon_News($this->dbClient);
+ }
+
+
+ public function prepareView()
+ {
+ $this->view->loginEnabled = (bool) $this->dbCfg->loginEnabled;
+ $this->view->news = $this->news->getEntries(3, false);
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Index($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/inventory.php b/2013/daemon/public/inventory.php
new file mode 100644
index 0000000..1f66cc7
--- /dev/null
+++ b/2013/daemon/public/inventory.php
@@ -0,0 +1,106 @@
+inventory = new Daemon_Inventory($this->dbClient, $this->characterData);
+ }
+
+
+ public function prepareView()
+ {
+ if($this->eventLog)
+ {
+ $this->pageSubtitle = 'Użycie przedmiotu';
+ $this->view->eventLog = $this->eventLog;
+ }
+ else $this->view->eventLog = null;
+ $items = $this->inventory->getItems('inventory');
+ $this->view->equipmentSlots = Daemon_Dictionary::$equipmentSlots;
+ //prepare items
+ $cmdNames = Daemon_Dictionary::$equipmentButtons;
+ foreach($items as &$row)
+ {
+ if($row['equipped'])
+ $cmd = 'unequip';
+ elseif('item' != $row['item']->type)
+ $cmd = 'equip';
+ else $cmd = 'use';
+ if(isset($cmdNames[$cmd]))
+ {
+ $row['item']->_cmdType = $cmd;
+ $row['item']->_cmdName = $cmdNames[$cmd];
+ }
+ else
+ {
+ $row['item']->_cmdType = null;
+ $row['item']->_cmdName = null;
+ }
+ $row['_showSlots'] = ('equip' == $cmd);
+ $row['_slots'] = $row['item']->getSlots();
+ $row['_multiSlots'] = (count($row['_slots']) > 1);
+ }
+ $this->view->items = $this->inventory->groupItemsByType($items);
+ $this->view->equipment = $this->inventory->getEquipment($items);
+ //prepare combat stats
+ $unit = (array) $this->characterData->getCombatUnit();
+ $attackTypes = Daemon_Dictionary::$combatAttackTypes;
+ $attackSpecials = Daemon_Dictionary::$combatAttackSpecials;
+ $armorSpecials = Daemon_Dictionary::$combatArmorSpecials;
+ $unit['type1_name'] = $unit['type1'] ? $attackTypes[$unit['type1']] : null;
+ $unit['type2_name'] = $unit['type2'] ? $attackTypes[$unit['type2']] : null;
+ $unit['sp1_name'] = $unit['sp1_type'] ? $attackSpecials[$unit['sp1_type']] : null;
+ $unit['sp2_name'] = $unit['sp2_type'] ? $attackSpecials[$unit['sp2_type']] : null;
+ $unit['armor_sp_name'] = $unit['armor_sp_type'] ? $armorSpecials[$unit['armor_sp_type']] : null;
+ $this->view->combatStats = $unit;
+ }
+
+
+ protected function runCommands()
+ {
+ //equip item
+ if(isset($_POST['equip'], $_POST['slot']))
+ {
+ $this->inventory->equip($_POST['equip'], $_POST['slot']);
+ $this->characterData->resetCombatStats();
+ $this->characterData->put();
+ return true;
+ }
+ //unequip item
+ if(isset($_POST['unequip']))
+ {
+ $this->inventory->unequip($_POST['unequip']);
+ $this->characterData->resetCombatStats();
+ $this->characterData->put();
+ return true;
+ }
+ //use item
+ if(isset($_POST['use']))
+ {
+ $handler = new Daemon_Item();
+ $handler->attachCharacterData($this->characterData);
+ $handler->attachDbClient($this->dbClient);
+ $handler->execute($this->view, $_POST['use']);
+ $this->eventLog = $handler->getUsageLog();
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Inventory($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/mail.php b/2013/daemon/public/mail.php
new file mode 100644
index 0000000..5b88fdc
--- /dev/null
+++ b/2013/daemon/public/mail.php
@@ -0,0 +1,67 @@
+forum = new Daemon_Forum($this->dbClient);
+ if(isset($_GET['to']))
+ $_POST['to'] = $_GET['to'];
+ }
+
+
+ public function prepareView()
+ {
+ //fetch mail
+ $listLimit = max(1, (int) $this->dbCfg->listLimitMessages);
+ $listOffset = isset($_GET['n']) ? (int) $_GET['n'] : 0;
+ $characterId = (int) $this->activeCharacter->character_id;
+
+ $this->pageSubtitleUseQuery = true;
+ $from = isset($_GET['from']) ? (int) $_GET['from'] : 0;
+ $data = $this->forum->getMail($listLimit, $from, $characterId);
+ foreach($data['list'] as &$row)
+ $row['content'] = Daemon::formatMessage($row['content'], true);
+
+ //mark as read
+ if($data['list'])
+ {
+ $messageId = $data['list'][0]['message_id'];
+ $sql = "UPDATE characters SET last_mail_id = :messageId WHERE character_id = :characterId";
+ $params = array('characterId' => $characterId, 'messageId' => $messageId);
+ $this->dbClient->query($sql, $params);
+ $this->activeCharacter->last_mail_id = $messageId;
+ }
+
+ //display page
+ $this->view->inputTo = isset($_POST['to']) ? $_POST['to'] : null;
+ $this->view->inputMsg = isset($_POST['msg']) ? $_POST['msg'] : null;
+ $this->view->list = $data['list'];
+ $nextUrl = $data['next'] ? '?from='.urlencode($data['next']) : null;
+ $this->view->nextUrl = $nextUrl;
+ }
+
+
+ protected function runCommands()
+ {
+ if(isset($_POST['to'], $_POST['msg']))
+ {
+ $this->forum->addMail($this->player->getCharacterId(), $_POST['to'], $_POST['msg']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Chat($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/map.php b/2013/daemon/public/map.php
new file mode 100644
index 0000000..c544d8a
--- /dev/null
+++ b/2013/daemon/public/map.php
@@ -0,0 +1,86 @@
+eventLog)
+ {
+ $this->pageSubtitle = 'Zdarzenie';
+ $this->pageTemplatePath = 'event.xml';
+ $this->view->eventLog = $this->eventLog;
+ return;
+ }
+ $bossStatuses = Daemon_Dictionary::$bossStatuses;
+ if(isset($bossStatuses[$this->location->boss_status]))
+ $this->location->boss_status_name = $bossStatuses[$this->location->boss_status];
+ else
+ $this->location->boss_status_name = null;
+ $this->pageSubtitleDetails = $this->location->name;
+ $this->view->locationDesc = nl2br(htmlspecialchars($this->location->description));
+ $this->view->pictureUrl = $this->location->getPictureUrl();
+ $this->view->region = $this->location->getRegionName();
+ $this->view->faction = $this->location->getFactionName();
+ $this->view->maps = $this->location->getMaps();
+ $this->view->paths = $this->location->getPaths();
+ $this->view->services = $this->location->getServices();
+ $this->view->lastMission = $this->characterData->getLastMission('completed');
+ //prepare character list
+ $showAll = isset($_GET['more']);
+ $halfLimit = $showAll ? null : (int) ceil($this->dbCfg->listLimitCharacters/2);
+ $n = $this->location->getCharacterCount(2*$halfLimit+1);
+ $characters = $this->location->getCharacters($this->characterData, $halfLimit);
+ $this->view->characters = $characters;
+ $this->view->showMoreLink = !$showAll && ($n > 2*$halfLimit);
+ }
+
+
+ public function runCommands()
+ {
+ $isCommand = false;
+ //actions
+ if(isset($_POST['act']))
+ {
+ switch($_POST['act'])
+ {
+ case'train':
+ $this->location->actionTrain();
+ break;
+ case'rest':
+ $this->location->actionRest();
+ break;
+ case'hunt':
+ $this->location->actionHunt();
+ break;
+ }
+ $isCommand = true;
+ }
+ //travel
+ if(isset($_POST['travel']))
+ {
+ $this->location->actionTravel($_POST['travel']);
+ $isCommand = true;
+ }
+ //run events
+ $this->view->setGameHeader($this->player->getPlayerId(),
+ $this->activeCharacter, $this->characterData, $this->location);
+ $this->eventLog = $this->characterData->runEvent($this->view);
+ //set "isCommand" flag
+ return $isCommand;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Map($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/news.php b/2013/daemon/public/news.php
new file mode 100644
index 0000000..720a046
--- /dev/null
+++ b/2013/daemon/public/news.php
@@ -0,0 +1,33 @@
+news = new Daemon_News($this->dbClient);
+ }
+
+
+ public function prepareView()
+ {
+ $this->view->feedId = $this->cfg->applicationUrl;
+ $this->view->feedUrl = "{$this->cfg->applicationUrl}news";
+ $this->view->feedTitle = $this->cfg->applicationTitle;
+ $this->view->feedUpdated = $this->news->getLastUpdated();
+ $this->view->entries = $this->news->getEntries(10, true);
+ }
+}
+
+
+$ctrl = new Daemon_Controller_News($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/not-implemented.html b/2013/daemon/public/not-implemented.html
new file mode 100644
index 0000000..045a1da
--- /dev/null
+++ b/2013/daemon/public/not-implemented.html
@@ -0,0 +1,6 @@
+
+
+
+Błąd
+Wybrana strona jeszcze nie istnieje.
+
diff --git a/2013/daemon/public/register.php b/2013/daemon/public/register.php
new file mode 100644
index 0000000..d6ef0e8
--- /dev/null
+++ b/2013/daemon/public/register.php
@@ -0,0 +1,40 @@
+registerEnabled = (bool) $this->dbCfg->registerEnabled;
+ }
+
+
+ public function prepareView()
+ {
+ $this->view->registerEnabled = $this->registerEnabled;
+ }
+
+
+ protected function runCommands()
+ {
+ if(!$this->registerEnabled)
+ Daemon_MsgQueue::add('Rejestracja wyłączona.');
+ elseif(isset($_POST['login'], $_POST['pass'], $_POST['pass2']))
+ {
+ $this->player->register($_POST['login'], $_POST['pass'], $_POST['pass2']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Register($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/reset-password.php b/2013/daemon/public/reset-password.php
new file mode 100644
index 0000000..948fd43
--- /dev/null
+++ b/2013/daemon/public/reset-password.php
@@ -0,0 +1,38 @@
+registerEnabled = (bool) $this->dbCfg->registerEnabled;
+ }
+
+
+ protected function runCommands()
+ {
+ if(isset($_POST['login'], $_POST['email'], $_POST['pass'], $_POST['pass2']))
+ {
+ $this->player->preparePasswordReset($_POST['login'], $_POST['email'], $_POST['pass'], $_POST['pass2']);
+ return true;
+ }
+ elseif (isset($_GET['key']))
+ {
+ $this->player->resetPassword($_GET['key']);
+ return true;
+ }
+ return false;
+ }
+
+}
+
+
+$ctrl = new Daemon_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/respawn.php b/2013/daemon/public/respawn.php
new file mode 100644
index 0000000..064212f
--- /dev/null
+++ b/2013/daemon/public/respawn.php
@@ -0,0 +1,59 @@
+characterData->xp_used))
+ {
+ Daemon_MsgQueue::add('Pamiętaj by wydać startowe doświadczenie.');
+ Daemon::redirect($this->cfg->getUrl('character'));
+ exit;
+ }
+ $this->defaultRespawn = $this->dbCfg->defaultRespawn;
+ $this->gender = $this->characterData->_gender;
+ if(empty($this->location->location_id))
+ $this->respawns = $this->characterData->getRespawns($this->defaultRespawn);
+ else
+ {
+ Daemon_MsgQueue::add('Już posiadasz powłokę cielesną.');
+ Daemon::redirect($this->cfg->getUrl('map'));
+ exit;
+ }
+ }
+
+
+ public function prepareView()
+ {
+ $this->view->respawns = $this->respawns;
+ $this->view->firstOne = empty($this->characterData->deaths);
+ $this->view->rolloversEnabled = (bool) $this->dbCfg->rolloversEnabled;
+ }
+
+
+ protected function runCommands()
+ {
+ if(isset($_POST['respawn']))
+ {
+ $this->characterData->respawn($_POST['respawn'], $this->defaultRespawn);
+ Daemon::redirect($this->cfg->getUrl('map'));
+ exit;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Respawn($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/robots.txt b/2013/daemon/public/robots.txt
new file mode 100644
index 0000000..5d856c8
--- /dev/null
+++ b/2013/daemon/public/robots.txt
@@ -0,0 +1,2 @@
+User-Agent: *
+Allow: *
diff --git a/2013/daemon/public/rules.php b/2013/daemon/public/rules.php
new file mode 100644
index 0000000..f542c4c
--- /dev/null
+++ b/2013/daemon/public/rules.php
@@ -0,0 +1,21 @@
+view->lastModified = date(DATE_RFC1123, filemtime($this->cfg->getFilePath('tpl', 'rules.xml')));
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Rules($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/arena.php b/2013/daemon/public/scyzoryk/arena.php
new file mode 100644
index 0000000..63e802d
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/arena.php
@@ -0,0 +1,126 @@
+selectMode = isset($_POST['mode']) ? $_POST['mode'] : null;
+ $this->combatCount = isset($_POST['n']) ? min(500, max(100, (int) $_POST['n'])) : 100;
+ $this->unitIdA = isset($_POST['unitA']) ? $_POST['unitA'] : null;
+ $this->unitIdB = isset($_POST['unitB']) ? $_POST['unitB'] : null;
+ }
+
+
+ public function prepareView()
+ {
+ $this->view->selectMode = $this->selectMode;
+ $this->view->combatCount = $this->combatCount;
+ $this->view->unitIdA = $this->unitIdA;
+ $this->view->unitIdB = $this->unitIdB;
+ $this->view->winsA = round(100 * $this->winsA / $this->combatCount, 2);
+ $this->view->winsB = round(100 * $this->winsB / $this->combatCount, 2);
+ $this->view->draws = round(100 * $this->draws / $this->combatCount, 2);
+ $this->view->doubleKOs = round(100 * $this->doubleKOs / $this->combatCount, 2);
+ $this->view->healthSumA = round(100 * $this->healthSumA / $this->combatCount, 2);
+ $this->view->healthSumB = round(100 * $this->healthSumB / $this->combatCount, 2);
+ $this->view->healthMinA = round(100 * $this->healthMinA, 2);
+ $this->view->healthMinB = round(100 * $this->healthMinB, 2);
+ $this->view->healthMaxA = round(100 * $this->healthMaxA, 2);
+ $this->view->healthMaxB = round(100 * $this->healthMaxB, 2);
+
+ $filter = new Daemon_Scyzoryk_Filter('combat-units');
+ $filter->noChars = false;
+ $unitsC = $unitsM = array();
+ foreach ($this->browser->getCombatUnits($filter) as $row)
+ {
+ if ($row['_character'])
+ $unitsC[] = $row;
+ else
+ $unitsM[] = $row;
+ }
+ $this->view->unitsC = $unitsC;
+ $this->view->unitsM = $unitsM;
+ }
+
+
+ public function runCommands()
+ {
+ if(isset($_POST['attack']))
+ {
+ if(!$this->unitIdA || !$this->unitIdB)
+ {
+ Daemon_MsgQueue::add('Wybierz obie jednostki.');
+ return true;
+ }
+ $this->winsA = 0;
+ $this->winsB = 0;
+ $this->draws = 0;
+ $this->doubleKOs = 0;
+ $this->healthSumA = 0;
+ $this->healthSumB = 0;
+ $unitA = new Daemon_Combat_Unit();
+ $unitA->attachDbClient($this->dbClient);
+ $unitA->get(array('combat_unit_id' => $this->unitIdA));
+ $unitB = new Daemon_Combat_Unit();
+ $unitB->attachDbClient($this->dbClient);
+ $unitB->get(array('combat_unit_id' => $this->unitIdB));
+ $this->healthMinA = 1.0;
+ $this->healthMinB = 1.0;
+ $this->healthMaxA = 0.0;
+ $this->healthMaxB = 0.0;
+ for ($i = 0; $i < $this->combatCount; ++$i)
+ {
+ $unitA->health = $unitA->health_max;
+ $unitB->health = $unitB->health_max;
+ $combat = new Daemon_Combat();
+ $combat->addUnit('a', $unitA, true);
+ $combat->addUnit('b', $unitB, false);
+ $combat->execute(true);
+ $deathA = ($unitA->health < 1);
+ $deathB = ($unitB->health < 1);
+ if ($deathA && $deathB)
+ $this->doubleKOs += 1;
+ elseif ($deathA)
+ $this->winsB += 1;
+ elseif ($deathB)
+ $this->winsA += 1;
+ else
+ $this->draws += 1;
+ $relHealthA = max(0.0, $unitA->health / $unitA->health_max);
+ $relHealthB = max(0.0, $unitB->health / $unitB->health_max);
+ $this->healthSumA += $relHealthA;
+ $this->healthSumB += max(0.0, $relHealthB);
+ $this->healthMinA = min($this->healthMinA, $relHealthA);
+ $this->healthMinB = min($this->healthMinB, $relHealthB);
+ $this->healthMaxA = max($this->healthMaxA, $relHealthA);
+ $this->healthMaxB = max($this->healthMaxB, $relHealthB);
+ }
+ return true;
+ }
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/character-edit.php b/2013/daemon/public/scyzoryk/character-edit.php
new file mode 100644
index 0000000..35380bd
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/character-edit.php
@@ -0,0 +1,98 @@
+character = new Daemon_DbObject_Character();
+ $this->character->attachDbClient($this->dbClient);
+ $this->character->get(array('character_id' => $this->editId));
+ if (empty($this->character->character_id))
+ {
+ Daemon_MsgQueue::add('Wybrana postać nie istnieje.');
+ Daemon::redirect($this->cfg->getUrl('scyzoryk/characters'));
+ exit;
+ }
+ $this->characterData = $this->character->getCharacterData();
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->character ? $this->character->name : null;
+ $this->view->character = $this->character;
+ $this->view->characterData = $this->characterData;
+ $this->view->genders = Daemon_Dictionary::$genders;
+ }
+
+
+ protected function runCommands()
+ {
+ if(is_null($this->character))
+ return false;
+ if(isset($_POST['save']))
+ {
+ $this->character->name = Daemon::getArrayValue($_POST, 'name');
+ $this->character->gender = Daemon::getArrayValue($_POST, 'gender');
+ $this->character->last_action = Daemon::getArrayValue($_POST, 'last_action');
+ $this->character->clan_id = Daemon::getArrayValue($_POST, 'clan_id');
+ $this->character->avatar_url = Daemon::getArrayValue($_POST, 'avatar_url');
+ $this->character->quote = Daemon::getArrayValue($_POST, 'quote');
+ $this->character->description = Daemon::getArrayValue($_POST, 'description');
+ $this->character->put();
+ return true;
+ }
+ if(isset($_POST['saveData']))
+ {
+ $this->characterData->location_id = Daemon::getArrayValue($_POST, 'location_id');
+ $this->characterData->faction_id = Daemon::getArrayValue($_POST, 'faction_id');
+ $this->characterData->faction_points = (int) Daemon::getArrayValue($_POST, 'faction_points');
+ $this->characterData->rank_id = (int) Daemon::getArrayValue($_POST, 'rank_id');
+ $this->characterData->turns = (int) Daemon::getArrayValue($_POST, 'turns');
+ $this->characterData->gold_purse = (int) Daemon::getArrayValue($_POST, 'gold_purse');
+ $this->characterData->gold_bank = (int) Daemon::getArrayValue($_POST, 'gold_bank');
+ $this->characterData->level = (int) Daemon::getArrayValue($_POST, 'level');
+ $this->characterData->xp_free = (int) Daemon::getArrayValue($_POST, 'xp_free');
+ $this->characterData->health = (int) Daemon::getArrayValue($_POST, 'health');
+ $this->characterData->health_max = (int) Daemon::getArrayValue($_POST, 'health_max');
+ $this->characterData->mana = (int) Daemon::getArrayValue($_POST, 'mana');
+ $this->characterData->mana_max = (int) Daemon::getArrayValue($_POST, 'mana_max');
+ $this->characterData->a_str = (int) Daemon::getArrayValue($_POST, 'a_str');
+ $this->characterData->a_dex = (int) Daemon::getArrayValue($_POST, 'a_dex');
+ $this->characterData->a_vit = (int) Daemon::getArrayValue($_POST, 'a_vit');
+ $this->characterData->a_pwr = (int) Daemon::getArrayValue($_POST, 'a_pwr');
+ $this->characterData->a_wil = (int) Daemon::getArrayValue($_POST, 'a_wil');
+ $this->characterData->s_pstr = (int) Daemon::getArrayValue($_POST, 's_pstr');
+ $this->characterData->s_patk = (int) Daemon::getArrayValue($_POST, 's_patk');
+ $this->characterData->s_pdef = (int) Daemon::getArrayValue($_POST, 's_pdef');
+ $this->characterData->s_pres = (int) Daemon::getArrayValue($_POST, 's_pres');
+ $this->characterData->s_preg = (int) Daemon::getArrayValue($_POST, 's_preg');
+ $this->characterData->s_mstr = (int) Daemon::getArrayValue($_POST, 's_mstr');
+ $this->characterData->s_matk = (int) Daemon::getArrayValue($_POST, 's_matk');
+ $this->characterData->s_mdef = (int) Daemon::getArrayValue($_POST, 's_mdef');
+ $this->characterData->s_mres = (int) Daemon::getArrayValue($_POST, 's_mres');
+ $this->characterData->s_mreg = (int) Daemon::getArrayValue($_POST, 's_mreg');
+ $this->characterData->sp_scout = (int) Daemon::getArrayValue($_POST, 'sp_scout');
+ $this->characterData->sp_identify = (int) Daemon::getArrayValue($_POST, 'sp_identify');
+ $this->characterData->sp_vchar = (int) Daemon::getArrayValue($_POST, 'sp_vchar');
+ $this->characterData->sp_vmonster = (int) Daemon::getArrayValue($_POST, 'sp_vmonster');
+ $this->characterData->sp_vitem = (int) Daemon::getArrayValue($_POST, 'sp_vitem');
+ $this->characterData->put();
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/characters.php b/2013/daemon/public/scyzoryk/characters.php
new file mode 100644
index 0000000..263a68e
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/characters.php
@@ -0,0 +1,30 @@
+dbClient->selectAll($sql);
+/*
+ foreach ($data as &$row)
+ $row['characters'] = explode("\n", $row['characters']);
+*/
+ $this->view->rows = $data;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/combat-unit-edit.php b/2013/daemon/public/scyzoryk/combat-unit-edit.php
new file mode 100644
index 0000000..7028005
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/combat-unit-edit.php
@@ -0,0 +1,51 @@
+unit = new Daemon_DbObject_CombatUnit();
+ $this->unit->attachDbClient($this->dbClient);
+ if($this->editId)
+ $this->unit->get(array('combat_unit_id' => $this->editId));
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->unit ? $this->unit->name : null;
+ $this->view->unit = $this->unit;
+ $this->view->attackTypes = Daemon_Dictionary::$combatAttackTypes;
+ $this->view->attackSpecials = Daemon_Dictionary::$combatAttackSpecials;
+ $this->view->armorSpecials = Daemon_Dictionary::$combatArmorSpecials;
+ }
+
+
+ protected function runCommands()
+ {
+ if(isset($_POST['combat_unit_id']))
+ {
+ if(!$_POST['combat_unit_id'])
+ {
+ Daemon_MsgQueue::add('Uzupełnij ID.');
+ return true;
+ }
+ $this->unit->import($_POST);
+ $this->unit->put();
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/combat-units.php b/2013/daemon/public/scyzoryk/combat-units.php
new file mode 100644
index 0000000..fe93a07
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/combat-units.php
@@ -0,0 +1,61 @@
+filter = new Daemon_Scyzoryk_Filter('combat-units');
+ }
+
+
+ protected function prepareView()
+ {
+ $this->view->filter = $this->filter;
+ $units = array();
+ foreach ($this->browser->getCombatUnits($this->filter) as $row)
+ if (!$row['_character'])
+ $units[] = $row;
+ $this->view->units = $units;
+ }
+
+
+ protected function runCommands()
+ {
+ //add new row
+ if(isset($_POST['newId'], $_POST['newName']) && $_POST['newId'])
+ {
+ $object = new Daemon_DbObject_CombatUnit();
+ $object->attachDbClient($this->dbClient);
+ $object->combat_unit_id = $_POST['newId'];
+ $object->name = $_POST['newName'];
+ $object->put();
+ return true;
+ }
+ //delete rows
+ if(isset($_POST['del']))
+ {
+ $this->editor->deleteCombatUnits($_POST['del']);
+ return true;
+ }
+ //set filter
+ if(isset($_POST['filter']) && is_array($_POST['filter']))
+ {
+ foreach($_POST['filter'] as $name => $value)
+ $this->filter->$name = $value;
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/config-generator.php b/2013/daemon/public/scyzoryk/config-generator.php
new file mode 100644
index 0000000..6757934
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/config-generator.php
@@ -0,0 +1,51 @@
+dbCfg = new Daemon_DbConfig($this->dbClient);
+ $this->itemTypes = Daemon_Dictionary::$generatorItemTypes;
+ }
+
+
+ protected function prepareView()
+ {
+ $this->view->generatorBaseValue = $this->dbCfg->generatorBaseValue;
+ $generatorOptions = array();
+ foreach ($this->itemTypes as $type => $name)
+ {
+ $generatorOptions[$type] = array(
+ 'name' => $name,
+ 'weights' => $this->dbCfg->getGeneratorWeights("$type")
+ );
+ }
+ $this->view->generatorOptions = $generatorOptions;
+ }
+
+
+ protected function runCommands()
+ {
+ if(isset($_POST['baseValue'], $_POST['weights']) && is_array($_POST['weights']))
+ {
+ $this->dbCfg->generatorBaseValue = max(1, (int) $_POST['baseValue']);
+ foreach (array_keys($this->itemTypes) as $type)
+ $this->dbCfg->setGeneratorWeights($type, $_POST['weights'][$type]);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Config($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/config.php b/2013/daemon/public/scyzoryk/config.php
new file mode 100644
index 0000000..35a91a3
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/config.php
@@ -0,0 +1,49 @@
+dbCfg = new Daemon_DbConfig($this->dbClient);
+ }
+
+
+ protected function prepareView()
+ {
+ $this->view->cfg = $this->dbCfg;
+ //healer
+ $healer = explode(',', $this->dbCfg->healer);
+ if(!isset($healer[0], $healer[1], $healer[2], $healer[3]))
+ $healer = array(null, null, null, null);
+ $this->view->healer = $healer;
+ }
+
+
+ protected function runCommands()
+ {
+ if(isset($_POST['cfg']) && is_array($_POST['cfg']))
+ {
+ $cfg = $_POST['cfg'];
+ if(isset($_POST['healer']) && is_array($_POST['healer']))
+ $cfg['healer'] = implode(',', $_POST['healer']);
+ else $cfg['healer'] = '1,1,1,1';
+ ksort($cfg);
+ foreach($cfg as $name => $value)
+ $this->dbCfg->$name = $value;
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Config($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/cron-ui.php b/2013/daemon/public/scyzoryk/cron-ui.php
new file mode 100644
index 0000000..38029bf
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/cron-ui.php
@@ -0,0 +1,20 @@
+
+
+
+
+Cron
+
+
diff --git a/2013/daemon/public/scyzoryk/event-edit.php b/2013/daemon/public/scyzoryk/event-edit.php
new file mode 100644
index 0000000..4d42cc7
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/event-edit.php
@@ -0,0 +1,45 @@
+editObj = new Daemon_DbObject_Event();
+ $this->editObj->attachDbClient($this->dbClient);
+ if($this->editId)
+ $this->editObj->get(array('event_id' => $this->editId));
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->editObj ? $this->editObj->name : null;
+ $this->view->editObj = $this->editObj;
+ }
+
+
+ protected function runCommands()
+ {
+ if(isset($_POST['event_id']))
+ {
+ $this->editObj->import($_POST);
+ if($_POST['event_id'])
+ $this->editObj->put();
+ else Daemon_MsgQueue::add('Uzupełnij ID.');
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_EventEdit($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/events.php b/2013/daemon/public/scyzoryk/events.php
new file mode 100644
index 0000000..27e6ecf
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/events.php
@@ -0,0 +1,43 @@
+view->items = $this->dbClient->selectAll($sql);
+ }
+
+
+ protected function runCommands()
+ {
+ //add new row
+ if(isset($_POST['newId'], $_POST['newName']) && $_POST['newId'])
+ {
+ $object = new Daemon_DbObject_Event();
+ $object->attachDbClient($this->dbClient);
+ $object->event_id = $_POST['newId'];
+ $object->name = $_POST['newName'];
+ $object->put();
+ return true;
+ }
+ //delete rows
+ if(isset($_POST['del']) && is_array($_POST['del']))
+ {
+ $this->editor->deleteRows('events', 'event_id', $_POST['del']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Events($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/faction-edit.php b/2013/daemon/public/scyzoryk/faction-edit.php
new file mode 100644
index 0000000..3c97e0c
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/faction-edit.php
@@ -0,0 +1,65 @@
+faction = $this->editor->selectRow('Daemon_Scyzoryk_DbRowFaction', $this->editId);
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->faction ? $this->faction->name : null;
+ $this->view->faction = $this->faction;
+ $this->view->factionRanks = $this->browser->getFactionRanks($this->editId);
+ $this->view->titles = $this->browser->getTitles();
+ }
+
+
+ protected function runCommands()
+ {
+ if(is_null($this->faction))
+ return false;
+ if(isset($_POST['id'], $_POST['name']) && $_POST['id'])
+ {
+ $this->faction->faction_id = $_POST['id'];
+ $this->faction->name = $_POST['name'];
+ $this->faction->power = $_POST['power'];
+ $this->editor->updateRow($this->faction);
+ return true;
+ }
+ //add rank
+ if(isset($_POST['addRank'], $_POST['id']) && $_POST['id'])
+ {
+ $params = array(
+ 'faction_id' => $this->editId,
+ 'rank_id' => (int) $_POST['id'],
+ 'min_points' => (int) Daemon::getArrayValue($_POST, 'min_points'),
+ 'title_id' => Daemon::getArrayValue($_POST, 'title_id'),
+ );
+ $row = new Daemon_Scyzoryk_DbRowFactionRank($params);
+ $this->editor->updateRow($row);
+ return true;
+ }
+ //delete ranks
+ if(isset($_POST['del']))
+ {
+ $this->editor->deleteFactionRanks($this->editId, $_POST['del']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_FactionEdit($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/factions.php b/2013/daemon/public/scyzoryk/factions.php
new file mode 100644
index 0000000..c4e4836
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/factions.php
@@ -0,0 +1,40 @@
+view->factions = $this->browser->getFactions();
+ }
+
+
+ protected function runCommands()
+ {
+ //add new row
+ if(isset($_POST['newId'], $_POST['newName']) && $_POST['newId'])
+ {
+ $params = array('faction_id' => $_POST['newId'], 'name' => $_POST['newName']);
+ $this->editor->updateRow(new Daemon_Scyzoryk_DbRowFaction($params));
+ return true;
+ }
+ //delete rows
+ if(isset($_POST['del']))
+ {
+ $this->editor->deleteFactions($_POST['del']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Factions($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/generator.php b/2013/daemon/public/scyzoryk/generator.php
new file mode 100644
index 0000000..35e733e
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/generator.php
@@ -0,0 +1,205 @@
+dbCfg = new Daemon_DbConfig($this->dbClient);
+ $this->itemWeaponTypes = Daemon_Dictionary::$itemWeaponTypes;
+ unset($this->itemWeaponTypes['']);
+ $this->itemArmorTypes = Daemon_Dictionary::$itemArmorTypes;
+ unset($this->itemArmorTypes['']);
+ $this->itemTemplates = $this->browser->getItemTemplates();
+ }
+
+
+ protected function prepareView()
+ {
+ $this->view->itemWeaponTypes = $this->itemWeaponTypes;
+ $this->view->itemArmorTypes = $this->itemArmorTypes;
+ $this->view->itemTemplates = $this->itemTemplates;
+ }
+
+
+ protected function runCommands()
+ {
+ //generate random item
+ if (isset($_POST['generate'], $_POST['id'], $_POST['name'],
+ $_POST['type'], $_POST['value'], $_POST['template']))
+ {
+ if (empty($_POST['id']))
+ {
+ Daemon_MsgQueue::add('Musisz wybrać ID.');
+ return true;
+ }
+ if (empty($_POST['template']))
+ {
+ Daemon_MsgQueue::add('Musisz wybrać szablon przedmiotu.');
+ return true;
+ }
+ $item = $this->generateItem($_POST['id'], $_POST['name'],
+ $_POST['type'], $_POST['value'], $_POST['template']);
+ if ($item && ($item->item_id))
+ {
+ $item->attachDbClient($this->dbClient);
+ $item->put();
+ $url = $this->cfg->getUrl('scyzoryk/item-edit?id='.urlencode($item->item_id));
+ Daemon::redirect($url);
+ exit;
+ }
+ return true;
+ }
+ //merge items
+ if (isset($_POST['merge'], $_POST['id'], $_POST['name']))
+ {
+ //multipliers
+ $this->weightA = isset($_POST['weightA']) ? max(1, (int) $_POST['weightA']) : 1;
+ $this->weightB = isset($_POST['weightB']) ? max(1, (int) $_POST['weightB']) : 1;
+ //base items
+ $baseItemA = new Daemon_DbObject_Item();
+ $baseItemA->attachDbClient($this->dbClient);
+ if(isset($_POST['baseA']))
+ $baseItemA->get(array('item_id' => $_POST['baseA']));
+ $baseItemB = new Daemon_DbObject_Item();
+ $baseItemB->attachDbClient($this->dbClient);
+ if(isset($_POST['baseB']))
+ $baseItemB->get(array('item_id' => $_POST['baseB']));
+ //result item
+ $resultItem = new Daemon_DbObject_Item();
+ $resultItem->attachDbClient($this->dbClient);
+ if($this->editId)
+ $resultItem->get(array('item_id' => $this->editId));
+ $resultItem->item_id = $_POST['id'];
+ $resultItem->name = $_POST['name'];
+ $resultItem->type = $baseItemA->type;
+ $resultItem->damage_type = $baseItemA->damage_type;
+ $resultItem->special_type = $baseItemA->special_type;
+ $resultItem->regen = ($baseItemA->regen + $baseItemB->regen) / 2;
+ //merge values
+ $keys = array('value', 'special_param',
+ 'pstr_p', 'pstr_c', 'patk_p', 'patk_c',
+ 'pdef_p', 'pdef_c', 'pres_p', 'pres_c',
+ 'mstr_p', 'mstr_c', 'matk_p', 'matk_c',
+ 'mdef_p', 'mdef_c', 'mres_p', 'mres_c',
+ 'armor', 'speed', 'regen');
+ foreach ($keys as $k)
+ $resultItem->$k = $this->mergeValues($baseItemA->$k, $baseItemB->$k);
+ //save item
+ if ($resultItem->item_id)
+ {
+ $resultItem->validate();
+ $resultItem->updateSuggestedValue($this->dbCfg);
+ $resultItem->put();
+ Daemon::redirect($this->cfg->getUrl('scyzoryk/item-edit?id='.urlencode($resultItem->item_id)));
+ exit;
+ }
+ return true;
+ }
+ }
+
+
+ private function mergeValues($valueA, $valueB)
+ {
+ $x = $this->weightA * (int) $valueA + $this->weightB * (int) $valueB;
+ $y = max(1, $this->weightA + $this->weightB);
+ return round($x / $y);
+ }
+
+
+ private function generateItem($id, $name, $type, $value, $templateId)
+ {
+ //initialise
+ $item = new Daemon_DbObject_Item();
+ $item->item_id = $id;
+ $item->name = $name;
+ $isWeapon = false;
+ $isArmor = false;
+ if (isset($this->itemWeaponTypes[$type]))
+ {
+ $isWeapon = true;
+ $item->type = $_POST['type'];
+ $item->damage_type = 'p';
+ }
+ elseif (isset($this->itemArmorTypes[$type]))
+ {
+ $isArmor = true;
+ $item->type = $_POST['type'];
+ }
+ if (!$isWeapon && !$isArmor)
+ {
+ Daemon_MsgQueue::add('Wybierz typ przedmiotu.');
+ return null;
+ }
+ //read chances
+ $chances = array();
+ $template = new Daemon_DbObject_ItemTemplate();
+ $template->attachDbClient($this->dbClient);
+ $template->get(array('id' => $templateId));
+ foreach (get_object_vars($template) as $key => $val)
+ {
+ if (($key[0] != '_') && !empty($val) && is_numeric($val))
+ $chances[$key] = (float) $val;
+ }
+ //generate stats
+ $specialKeys = array('armor', 'speed', 'regen');
+ while ($item->suggested_value < $value)
+ {
+ $chanceKey = $this->getRandomKey($chances);
+ unset($matches);
+ preg_match('/^(.+)_([^_]+)$/', $chanceKey, $matches);
+ if (isset($matches[0], $matches[1]))
+ {
+ $key = $matches[1];
+ $sign = ($matches[2] != 'm') ? +1 : -1;
+ $item->$key += $sign;
+ }
+ else
+ {
+ Daemon_MsgQueue::add('Ten szablon nie nadaje się do generowania - suma szans nie jest dodatnia.');
+ return null;
+ }
+ $item->updateSuggestedValue($this->dbCfg);
+ }
+ //set price
+ $item->value = round($item->suggested_value);
+ return $item;
+ }
+
+
+ private function getRandomKey(array $chances)
+ {
+ $chanceSum = array_sum($chances);
+ if ($chanceSum < 1)
+ return null;
+ $key = null;
+ $d256 = mt_rand(0, 255);
+ foreach ($chances as $key => $val)
+ {
+ $chance = 256 * $val / $chanceSum;
+ if($d256 < $chance)
+ break;
+ $d256 -= $chance;
+ }
+ return $key;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/index.php b/2013/daemon/public/scyzoryk/index.php
new file mode 100644
index 0000000..e895056
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/index.php
@@ -0,0 +1,51 @@
+view->prices = $prices;
+
+ //Ile bonusu powinien mieć przedmiot za potwora
+ $bonuses = array();
+ $cecha = 0;
+ $cena = 0;
+ for ($i = 1; $i < 100; ++$i)
+ {
+ if ($i < 11)
+ $mnoz=3;
+ elseif ($cecha<31)
+ $mnoz=4;
+ else
+ $mnoz=5;
+ $cena = round($cena * 0.9 + $i * $mnoz);
+ $cecha += $mnoz;
+ $st = round($cecha * $i / (100+$i));
+ $bonuses[] = array('bonusp' => $i, 'bonusc' => $st, 'price' => $cena);
+ }
+ $this->view->bonuses = $bonuses;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Index($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/info.php b/2013/daemon/public/scyzoryk/info.php
new file mode 100644
index 0000000..2d324de
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/info.php
@@ -0,0 +1,19 @@
+dbCfg = new Daemon_DbConfig($this->dbClient);
+ $this->item = new Daemon_DbObject_Item();
+ $this->item->attachDbClient($this->dbClient);
+ if($this->editId)
+ $this->item->get(array('item_id' => $this->editId));
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->item ? $this->item->name : null;
+ $this->view->item = $this->item;
+ $this->view->itemTypes = Daemon_Dictionary::$itemTypes;
+ $this->view->itemWeaponTypes = Daemon_Dictionary::$itemWeaponTypes;
+ $this->view->itemDamageTypes = Daemon_Dictionary::$itemDamageTypes;
+ $this->view->itemArmorTypes = Daemon_Dictionary::$itemArmorTypes;
+ $this->view->combatAttackSpecials = Daemon_Dictionary::$combatAttackSpecials;
+ $this->view->combatArmorSpecials = Daemon_Dictionary::$combatArmorSpecials;
+ $itemUsableSpecials = array();
+ $sql = "SELECT special_id, name FROM item_specials ORDER BY name";
+ foreach($this->dbClient->selectAll($sql) as $row)
+ $itemUsableSpecials[$row['special_id']] = $row['name'];
+ $this->view->itemSpecials = $itemUsableSpecials;
+ }
+
+
+ protected function runCommands()
+ {
+ if(is_null($this->item))
+ return false;
+ if(isset($_POST['id'], $_POST['name'], $_POST['p']) && $_POST['id'])
+ {
+ $this->item->item_id = $_POST['id'];
+ $this->item->name = $_POST['name'];
+ $this->item->type = Daemon::getArrayValue($_POST, 'type');
+ $this->item->value = Daemon::getArrayValue($_POST, 'value');
+ $this->item->description = Daemon::getArrayValue($_POST, 'description');
+ $this->item->damage_type = Daemon::getArrayValue($_POST, 'damage_type');
+ $this->item->special_type = Daemon::getArrayValue($_POST, 'special_type');
+ $this->item->special_param = Daemon::getArrayValue($_POST, 'special_param');
+ $keys = array_keys(get_class_vars('Daemon_DbObject_Item'));
+ foreach($_POST['p'] as $key => $val)
+ if(in_array($key, $keys))
+ $this->item->$key = $val;
+ $this->item->validate();
+ $this->item->updateSuggestedValue($this->dbCfg);
+ $this->item->put();
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_ItemEdit($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/item-template-edit.php b/2013/daemon/public/scyzoryk/item-template-edit.php
new file mode 100644
index 0000000..5d0d0d4
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/item-template-edit.php
@@ -0,0 +1,45 @@
+editObj = new Daemon_DbObject_ItemTemplate();
+ $this->editObj->attachDbClient($this->dbClient);
+ if($this->editId)
+ $this->editObj->get(array('id' => $this->editId));
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->editObj ? $this->editObj->name : null;
+ $this->view->editObj = $this->editObj;
+ }
+
+
+ protected function runCommands()
+ {
+ if(isset($_POST['id']))
+ {
+ $this->editObj->import($_POST);
+ if($_POST['id'])
+ $this->editObj->put();
+ else Daemon_MsgQueue::add('Uzupełnij ID.');
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/item-templates.php b/2013/daemon/public/scyzoryk/item-templates.php
new file mode 100644
index 0000000..f0f438a
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/item-templates.php
@@ -0,0 +1,42 @@
+view->rows = $this->browser->getItemTemplates();
+ }
+
+
+ protected function runCommands()
+ {
+ //add new row
+ if(isset($_POST['newId'], $_POST['newName']) && $_POST['newId'])
+ {
+ $item = new Daemon_DbObject_ItemTemplate();
+ $item->attachDbClient($this->dbClient);
+ $item->id = $_POST['newId'];
+ $item->name = $_POST['newName'];
+ $item->put();
+ return true;
+ }
+ //delete rows
+ if(isset($_POST['del']))
+ {
+ $this->editor->deleteItemTemplates($_POST['del']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/items.php b/2013/daemon/public/scyzoryk/items.php
new file mode 100644
index 0000000..3100f2d
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/items.php
@@ -0,0 +1,62 @@
+filter = new Daemon_Scyzoryk_Filter('items', array('type'));
+ }
+
+
+ protected function prepareView()
+ {
+ $this->view->filter = $this->filter;
+ $this->view->items = $this->browser->getItems($this->filter);
+ $this->view->itemTypes = Daemon_Dictionary::$itemTypes;
+ $this->view->itemWeaponTypes = Daemon_Dictionary::$itemWeaponTypes;
+ $this->view->itemDamageTypes = Daemon_Dictionary::$itemDamageTypes;
+ $this->view->itemArmorTypes = Daemon_Dictionary::$itemArmorTypes;
+ }
+
+
+ protected function runCommands()
+ {
+ //add new row
+ if(isset($_POST['newId'], $_POST['newName'], $_POST['newType']) && $_POST['newId'])
+ {
+ $item = new Daemon_DbObject_Item();
+ $item->attachDbClient($this->dbClient);
+ $item->item_id = $_POST['newId'];
+ $item->name = $_POST['newName'];
+ $item->type = $_POST['newType'];
+ $item->put();
+ return true;
+ }
+ //delete rows
+ if(isset($_POST['del']))
+ {
+ $this->editor->deleteItems($_POST['del']);
+ return true;
+ }
+ //set filter
+ if(isset($_POST['filter']) && is_array($_POST['filter']))
+ {
+ foreach($_POST['filter'] as $name => $value)
+ $this->filter->$name = $value;
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Items($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/location-edit.php b/2013/daemon/public/scyzoryk/location-edit.php
new file mode 100644
index 0000000..4092cee
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/location-edit.php
@@ -0,0 +1,122 @@
+editObj = new Daemon_DbObject_Location();
+ $this->editObj->attachDbClient($this->dbClient);
+ if($this->editId)
+ $this->editObj->get(array('location_id' => $this->editId));
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->editObj ? $this->editObj->name : null;
+ $this->view->editObj = $this->editObj;
+ $this->view->paths = $this->browser->getLocationPaths($this->editId);
+ $this->view->monsters = $this->browser->getLocationMonsters($this->editId);
+ $this->view->events = $this->browser->getLocationEvents($this->editId);
+ $this->view->services = $this->browser->getLocationServices($this->editId);
+ $this->view->regions = $this->browser->getRegions();
+ $this->view->factions = $this->browser->getFactions();
+ $this->view->locationTypes = Daemon_Dictionary::$locationTypes;
+ $this->view->bossStatuses = Daemon_Dictionary::$bossStatuses;
+ //event names
+ $sql = "SELECT event_id, name FROM events ORDER BY event_id";
+ $this->view->eventNames = $this->dbClient->selectAll($sql);
+ //service names
+ $sql = "SELECT service_id, name, type FROM services ORDER BY service_id";
+ $this->view->serviceNames = $this->dbClient->selectAll($sql);
+ }
+
+
+ protected function runCommands()
+ {
+ if(isset($_POST['location_id']))
+ {
+ $this->editObj->import($_POST);
+ if($_POST['location_id'])
+ $this->editObj->put();
+ else Daemon_MsgQueue::add('Uzupełnij ID.');
+ return true;
+ }
+ //add path
+ if(isset($_POST['addPath'], $_POST['id']) && $_POST['id'])
+ {
+ $params = array('location_id' => $this->editId, 'destination_id' => $_POST['id']);
+ $row = new Daemon_Scyzoryk_DbRowLocationPath($params);
+ $this->editor->updateRow($row);
+ if(!empty($_POST['bidir']))
+ {
+ $params = array('location_id' => $_POST['id'], 'destination_id' => $this->editId);
+ $row = new Daemon_Scyzoryk_DbRowLocationPath($params);
+ $this->editor->updateRow($row);
+ }
+ return true;
+ }
+ //delete paths
+ if(isset($_POST['delPaths']))
+ {
+ $delPathsRev = (array) Daemon::getArrayValue($_POST, 'delPathsRev', array());
+ $this->editor->deleteLocationPaths($this->editId, $_POST['delPaths'], $delPathsRev);
+ return true;
+ }
+ //add monster
+ if(isset($_POST['addMonster'], $_POST['id']) && $_POST['id'])
+ {
+ $params = array('location_id' => $this->editId, 'monster_id' => $_POST['id']);
+ $row = new Daemon_Scyzoryk_DbRowLocationMonster($params);
+ $this->editor->updateRow($row);
+ return true;
+ }
+ //delete monsters
+ if(isset($_POST['delMonster']))
+ {
+ $this->editor->deleteLocationMonsters($this->editId, $_POST['delMonster']);
+ return true;
+ }
+ //add event
+ if(isset($_POST['addEvent'], $_POST['id']) && $_POST['id'])
+ {
+ $params = array('location_id' => $this->editId, 'event_id' => $_POST['id']);
+ $row = new Daemon_Scyzoryk_DbRowLocationEvent($params);
+ $this->editor->updateRow($row);
+ return true;
+ }
+ //delete events
+ if(isset($_POST['delEvent']))
+ {
+ $this->editor->deleteLocationEvents($this->editId, $_POST['delEvent']);
+ return true;
+ }
+ //add service
+ if(isset($_POST['addService'], $_POST['id']) && $_POST['id'])
+ {
+ $params = array('location_id' => $this->editId, 'service_id' => $_POST['id']);
+ $row = new Daemon_Scyzoryk_DbRowLocationService($params);
+ $this->editor->updateRow($row);
+ return true;
+ }
+ //delete services
+ if(isset($_POST['delService']))
+ {
+ $this->editor->deleteLocationServices($this->editId, $_POST['delService']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_LocationEdit($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/location-event-edit.php b/2013/daemon/public/scyzoryk/location-event-edit.php
new file mode 100644
index 0000000..98087fa
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/location-event-edit.php
@@ -0,0 +1,43 @@
+event = $this->editor->selectRow('Daemon_Scyzoryk_DbRowLocationEvent', $this->editId, $this->editId2);
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->event ? 'edycja zdarzenia specjalnego' : null;
+ $this->view->event = $this->event;
+ }
+
+
+ protected function runCommands()
+ {
+ if(is_null($this->event))
+ return false;
+ if(isset($_POST['chance'], $_POST['params']))
+ {
+ $this->event->chance = $_POST['chance'];
+ $this->event->params = $_POST['params'];
+ $this->editor->updateRow($this->event);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_LocationEventEdit($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/location-monster-edit.php b/2013/daemon/public/scyzoryk/location-monster-edit.php
new file mode 100644
index 0000000..ea7006d
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/location-monster-edit.php
@@ -0,0 +1,42 @@
+monster = $this->editor->selectRow('Daemon_Scyzoryk_DbRowLocationMonster', $this->editId, $this->editId2);
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->monster ? 'edycja zdarzenia-potwora' : null;
+ $this->view->monster = $this->monster;
+ }
+
+
+ protected function runCommands()
+ {
+ if(is_null($this->monster))
+ return false;
+ if(isset($_POST['chance']))
+ {
+ $this->monster->chance = $_POST['chance'];
+ $this->editor->updateRow($this->monster);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_LocationMonsterEdit($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/location-path-edit.php b/2013/daemon/public/scyzoryk/location-path-edit.php
new file mode 100644
index 0000000..2aca151
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/location-path-edit.php
@@ -0,0 +1,44 @@
+path = $this->editor->selectRow('Daemon_Scyzoryk_DbRowLocationPath', $this->editId, $this->editId2);
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->path ? 'edycja ścieżki' : null;
+ $this->view->path = $this->path;
+ }
+
+
+ protected function runCommands()
+ {
+ if(is_null($this->path))
+ return false;
+ if(isset($_POST['name']))
+ {
+ $this->path->name = $_POST['name'];
+ $this->path->cost_gold = Daemon::getArrayValue($_POST, 'cost_gold');
+ $this->path->cost_mana = Daemon::getArrayValue($_POST, 'cost_mana');
+ $this->editor->updateRow($this->path);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_LocationPathEdit($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/locations.php b/2013/daemon/public/scyzoryk/locations.php
new file mode 100644
index 0000000..9473fd9
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/locations.php
@@ -0,0 +1,60 @@
+filter = new Daemon_Scyzoryk_Filter('locations', array('region_id'));
+ }
+
+
+ protected function prepareView()
+ {
+ $this->view->filter = $this->filter;
+ $this->view->locations = $this->browser->getLocations($this->filter);
+ $this->view->regions = $this->browser->getRegions();
+ $this->view->locationTypes = Daemon_Dictionary::$locationTypes;
+ }
+
+
+ protected function runCommands()
+ {
+ //add new row
+ if(isset($_POST['newId'], $_POST['newName'], $_POST['newRegion']) && $_POST['newId'])
+ {
+ $object = new Daemon_DbObject_Location();
+ $object->attachDbClient($this->dbClient);
+ $object->location_id = $_POST['newId'];
+ $object->name = $_POST['newName'];
+ $object->region_id = $_POST['newRegion'];
+ $object->put();
+ return true;
+ }
+ //delete rows
+ if(isset($_POST['del']))
+ {
+ $this->editor->deleteLocations($_POST['del']);
+ return true;
+ }
+ //set filter
+ if(isset($_POST['filter']) && is_array($_POST['filter']))
+ {
+ foreach($_POST['filter'] as $name => $value)
+ $this->filter->$name = $value;
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Locations($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/map-edit.php b/2013/daemon/public/scyzoryk/map-edit.php
new file mode 100644
index 0000000..5174432
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/map-edit.php
@@ -0,0 +1,45 @@
+map = $this->editor->selectRow('Daemon_Scyzoryk_DbRowMap', $this->editId);
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->map ? $this->map->name : null;
+ $this->view->map = $this->map;
+ }
+
+
+ protected function runCommands()
+ {
+ if(is_null($this->map))
+ return false;
+ if(isset($_POST['id'], $_POST['name']) && $_POST['id'])
+ {
+ $this->map->map_id = $_POST['id'];
+ $this->map->name = $_POST['name'];
+ $this->map->url = Daemon::getArrayValue($_POST, 'url');
+ $this->map->sort = max(0, Daemon::getArrayValue($_POST, 'sort'));
+ $this->editor->updateRow($this->map);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_MapEdit($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/maps.php b/2013/daemon/public/scyzoryk/maps.php
new file mode 100644
index 0000000..e919668
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/maps.php
@@ -0,0 +1,39 @@
+view->maps = $this->browser->getMaps();
+ }
+
+
+ protected function runCommands()
+ {
+ //add new row
+ if(isset($_POST['newId'], $_POST['newName']) && $_POST['newId'])
+ {
+ $params = array('map_id' => $_POST['newId'], 'name' => $_POST['newName']);
+ $this->editor->updateRow(new Daemon_Scyzoryk_DbRowMap($params));
+ return true;
+ }
+ //delete rows
+ if(isset($_POST['del']))
+ {
+ $this->editor->deleteMaps($_POST['del']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Maps($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/monster-drop-edit.php b/2013/daemon/public/scyzoryk/monster-drop-edit.php
new file mode 100644
index 0000000..bba3c06
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/monster-drop-edit.php
@@ -0,0 +1,42 @@
+drop = $this->editor->selectRow('Daemon_Scyzoryk_DbRowMonsterDrop', $this->editId, $this->editId2);
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->drop ? 'edycja dropu' : null;
+ $this->view->drop = $this->drop;
+ }
+
+
+ protected function runCommands()
+ {
+ if(is_null($this->drop))
+ return false;
+ if(isset($_POST['chance']))
+ {
+ $this->drop->chance = $_POST['chance'];
+ $this->editor->updateRow($this->drop);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_MonsterDropEdit($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/monster-edit.php b/2013/daemon/public/scyzoryk/monster-edit.php
new file mode 100644
index 0000000..fc5d114
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/monster-edit.php
@@ -0,0 +1,70 @@
+monster = new Daemon_DbObject_Monster();
+ $this->monster->attachDbClient($this->dbClient);
+ if($this->editId)
+ $this->monster->get(array('monster_id' => $this->editId));
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->monster ? $this->monster->name : null;
+ $this->view->monster = $this->monster;
+ $this->view->drops = $this->browser->getMonsterDrops($this->editId);
+ $this->view->titles = $this->browser->getTitles();
+ $this->view->combatUnits = $this->browser->getCombatUnits(null);
+ $names = Daemon_Dictionary::$monsterClasses;
+ $this->view->className = isset($names[$this->monster->class]) ? $names[$this->monster->class] : null;
+ $this->view->attackTypes = Daemon_Dictionary::$combatAttackTypes;
+ $this->view->attackSpecials = Daemon_Dictionary::$combatAttackSpecials;
+ $this->view->armorSpecials = Daemon_Dictionary::$combatArmorSpecials;
+ }
+
+
+ protected function runCommands()
+ {
+ if(isset($_POST['monster_id']))
+ {
+ if(!$_POST['monster_id'])
+ {
+ Daemon_MsgQueue::add('Uzupełnij ID.');
+ return true;
+ }
+ $this->monster->import($_POST);
+ $this->monster->put();
+ return true;
+ }
+ //add drop
+ if(isset($_POST['addDrop'], $_POST['id']) && $_POST['id'])
+ {
+ $params = array('monster_id' => $this->editId, 'item_id' => $_POST['id']);
+ $row = new Daemon_Scyzoryk_DbRowMonsterDrop($params);
+ $this->editor->updateRow($row);
+ return true;
+ }
+ //delete drops
+ if(isset($_POST['del']))
+ {
+ $this->editor->deleteMonsterDrops($this->editId, $_POST['del']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/monsters.php b/2013/daemon/public/scyzoryk/monsters.php
new file mode 100644
index 0000000..e53aac8
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/monsters.php
@@ -0,0 +1,58 @@
+filter = new Daemon_Scyzoryk_Filter('monsters', array('class'));
+ }
+
+
+ protected function prepareView()
+ {
+ $this->view->filter = $this->filter;
+ $this->view->monsters = $this->browser->getMonsters($this->filter);
+ $this->view->monsterClasses = Daemon_Dictionary::$monsterClasses;
+ }
+
+
+ protected function runCommands()
+ {
+ //add new row
+ if(isset($_POST['newId'], $_POST['newName']) && $_POST['newId'])
+ {
+ $object = new Daemon_DbObject_Monster();
+ $object->attachDbClient($this->dbClient);
+ $object->monster_id = $_POST['newId'];
+ $object->name = $_POST['newName'];
+ $object->put();
+ return true;
+ }
+ //delete rows
+ if(isset($_POST['del']))
+ {
+ $this->editor->deleteMonsters($_POST['del']);
+ return true;
+ }
+ //set filter
+ if(isset($_POST['filter']) && is_array($_POST['filter']))
+ {
+ foreach($_POST['filter'] as $name => $value)
+ $this->filter->$name = $value;
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Monsters($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/news.php b/2013/daemon/public/scyzoryk/news.php
new file mode 100644
index 0000000..76750db
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/news.php
@@ -0,0 +1,47 @@
+news = new Daemon_News($this->dbClient);
+ }
+
+
+ protected function prepareView()
+ {
+ $this->view->entries = $this->news->getEntries(null, false);
+ }
+
+
+ protected function runCommands()
+ {
+ //delete entry
+ if(isset($_POST['del']))
+ {
+ $this->news->deleteEntry($_POST['del']);
+ return true;
+ }
+ //add entry
+ if(isset($_POST['id'], $_POST['title'], $_POST['author'], $_POST['content']))
+ {
+ if(!$_POST['id'])
+ $_POST['id'] = $this->news->generateId(getenv('SERVER_NAME'), $_POST['title']);
+ $this->news->updateEntry($_POST['id'], $_POST['title'], $_POST['author'], $_POST['content']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_News($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/player-edit.php b/2013/daemon/public/scyzoryk/player-edit.php
new file mode 100644
index 0000000..3561064
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/player-edit.php
@@ -0,0 +1,65 @@
+player = new Daemon_DbObject_Player($this->dbClient);
+ $this->player->get(array('player_id' => $this->editId));
+ if (empty($this->player->login))
+ {
+ Daemon_MsgQueue::add('Wybrany gracz nie istnieje.');
+ Daemon::redirect($this->cfg->getUrl('scyzoryk/players'));
+ exit;
+ }
+ //player roles
+ $this->playerRoles = array('chat' => false, 'login' => false);
+ foreach (explode(',', $this->player->roles) as $key)
+ $this->playerRoles[$key] = true;
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->player ? $this->player->login : null;
+ $this->view->player = $this->player;
+ $this->view->skins = array_keys(Daemon_Dictionary::$skinDirUrls);
+ $this->view->playerRoles = $this->playerRoles;
+ }
+
+
+ protected function runCommands()
+ {
+ if(is_null($this->player))
+ return false;
+ if(isset($_POST['save']))
+ {
+ $this->player->date_created = Daemon::getArrayValue($_POST, 'date_created');
+ $this->player->last_login = Daemon::getArrayValue($_POST, 'last_login');
+ $this->player->name = Daemon::getArrayValue($_POST, 'name');
+ $this->player->skin = Daemon::getArrayValue($_POST, 'skin');
+ $this->player->email = Daemon::getArrayValue($_POST, 'email');
+ foreach ($this->playerRoles as $key => &$val)
+ $val = isset($_POST['roles'][$key]);
+ $this->player->roles = implode(',', array_keys(array_filter($this->playerRoles)));
+ $this->player->put();
+ if(!empty($_POST['pass1']) || !empty($_POST['pass2']))
+ $this->player->setPassword($_POST['pass1'], $_POST['pass2']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/players.php b/2013/daemon/public/scyzoryk/players.php
new file mode 100644
index 0000000..7d04795
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/players.php
@@ -0,0 +1,31 @@
+dbClient->selectAll($sql);
+ foreach ($data as &$row)
+ $row['characters'] = explode("\n", $row['characters']);
+ $this->view->rows = $data;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/region-edit.php b/2013/daemon/public/scyzoryk/region-edit.php
new file mode 100644
index 0000000..6a5a22d
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/region-edit.php
@@ -0,0 +1,48 @@
+region = $this->editor->selectRow('Daemon_Scyzoryk_DbRowRegion', $this->editId);
+ }
+
+
+ protected function prepareView()
+ {
+ $filter = new Daemon_Scyzoryk_Filter('locations', array('region_id'), true);
+ $filter->region_id = $this->region->region_id;
+ $this->pageSubtitleDetails = $this->region ? $this->region->name : null;
+ $this->view->region = $this->region;
+ $this->view->locations = $this->browser->getLocations($filter);
+ }
+
+
+ protected function runCommands()
+ {
+ if(is_null($this->region))
+ return false;
+ if(isset($_POST['id'], $_POST['name']) && $_POST['id'])
+ {
+ $this->region->region_id = $_POST['id'];
+ $this->region->name = $_POST['name'];
+ $this->region->respawn_id = Daemon::getArrayValue($_POST, 'respawn_id');
+ $this->region->picture_url = Daemon::getArrayValue($_POST, 'picture_url');
+ $this->editor->updateRow($this->region);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_RegionEdit($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/regions.php b/2013/daemon/public/scyzoryk/regions.php
new file mode 100644
index 0000000..11d055d
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/regions.php
@@ -0,0 +1,39 @@
+view->regions = $this->browser->getRegions();
+ }
+
+
+ protected function runCommands()
+ {
+ //add new row
+ if(isset($_POST['newId'], $_POST['newName']) && $_POST['newId'])
+ {
+ $params = array('region_id' => $_POST['newId'], 'name' => $_POST['newName']);
+ $this->editor->updateRow(new Daemon_Scyzoryk_DbRowRegion($params));
+ return true;
+ }
+ //delete rows
+ if(isset($_POST['del']))
+ {
+ $this->editor->deleteRegions($_POST['del']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Regions($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/reset.php b/2013/daemon/public/scyzoryk/reset.php
new file mode 100644
index 0000000..d57ee26
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/reset.php
@@ -0,0 +1,91 @@
+dbCfg = new Daemon_DbConfig($this->dbClient);
+ }
+
+
+ private function resetCharacters()
+ {
+ $queries = array(
+ "TRUNCATE TABLE inventory",
+ "TRUNCATE TABLE character_data",
+ "INSERT INTO character_data(character_id) SELECT character_id FROM characters",
+ "DELETE FROM combat_units WHERE combat_unit_id LIKE 'character-%'",
+ "TRUNCATE TABLE character_regions",
+ "TRUNCATE TABLE character_missions",
+ "DELETE FROM character_titles WHERE title_id NOT IN (SELECT title_id FROM titles WHERE type='special')",
+ "TRUNCATE TABLE character_statistics",
+ "INSERT INTO character_statistics(character_id) SELECT character_id FROM characters",
+ );
+ foreach ($queries as $q)
+ $this->dbClient->query($q);
+ }
+
+
+ private function resetHistory()
+ {
+ $queries = array(
+ "UPDATE characters SET last_mail_id = DEFAULT",
+ "TRUNCATE TABLE mail",
+ "TRUNCATE TABLE chat",
+ "TRUNCATE TABLE duels",
+ "TRUNCATE TABLE rollovers",
+ );
+ foreach ($queries as $q)
+ $this->dbClient->query($q);
+ }
+
+
+ public function runCommands()
+ {
+ $methods = array(
+ 'characters' => 'resetCharacters',
+ 'history' => 'resetHistory',
+ 'items' => 'updateItems',
+ );
+ if (isset($_POST['reset']))
+ {
+ if (isset($methods[$_POST['reset']]))
+ {
+ $method = $methods[$_POST['reset']];
+ $this->$method();
+ }
+ return true;
+ }
+ }
+
+
+ private function updateItems()
+ {
+ $sql = "SELECT item_id FROM items";
+ $ids = $this->dbClient->selectColumn($sql);
+ $n = 0;
+ foreach ($ids as $id)
+ {
+ $item = new Daemon_DbObject_Item();
+ $item->attachDbClient($this->dbClient);
+ $item->get(array('item_id' => $id));
+ $item->validate();
+ $item->updateSuggestedValue($this->dbCfg);
+ $item->put();
+ $n += 1;
+ }
+ Daemon_MsgQueue::add("Przeliczono $n przedmiotów.");
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/search.php b/2013/daemon/public/scyzoryk/search.php
new file mode 100644
index 0000000..7095eac
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/search.php
@@ -0,0 +1,53 @@
+searchType = isset($_GET['type']) ? $_GET['type'] : null;
+ $this->inputId = isset($_POST['id']) ? $_POST['id'] : null;
+ $this->inputName = isset($_POST['name']) ? $_POST['name'] : null;
+ }
+
+
+ protected function prepareView()
+ {
+ $this->view->results = $this->results;
+ $this->view->inputId = $this->inputId;
+ $this->view->inputName = $this->inputName;
+ }
+
+
+ protected function runCommands()
+ {
+ if(!$this->inputId && !$this->inputName)
+ return false;
+ $searchTypes = array(
+ 'l' => array('tableName' => 'locations', 'indexCol' => 'location_id'),
+ 'm' => array('tableName' => 'monsters', 'indexCol' => 'monster_id'),
+ 'i' => array('tableName' => 'items', 'indexCol' => 'item_id'),
+ );
+ if(!isset($searchTypes[$this->searchType]))
+ return false;
+ $searchType = $searchTypes[$this->searchType];
+ $tableName = $searchType['tableName'];
+ $indexCol = $searchType['indexCol'];
+ $this->results = $this->browser->findRow($tableName, $indexCol, $this->inputId, $this->inputName);
+ return true;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Search($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/service-edit.php b/2013/daemon/public/scyzoryk/service-edit.php
new file mode 100644
index 0000000..50acd76
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/service-edit.php
@@ -0,0 +1,64 @@
+service = $this->editor->selectRow('Daemon_Scyzoryk_DbRowService', $this->editId);
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->service ? $this->service->name : null;
+ $this->view->service = $this->service;
+ $this->view->serviceItems = $this->browser->getServiceItems($this->editId);
+ $this->view->factions = $this->browser->getFactions();
+ $this->view->serviceTypes = Daemon_Dictionary::$serviceTypes;
+ }
+
+
+ protected function runCommands()
+ {
+ if(is_null($this->service))
+ return false;
+ if(isset($_POST['id'], $_POST['name'], $_POST['type']) && $_POST['id'])
+ {
+ $this->service->service_id = $_POST['id'];
+ $this->service->name = $_POST['name'];
+ $this->service->type = $_POST['type'];
+ $this->service->faction_id = empty($_POST['faction_id']) ? null : $_POST['faction_id'];
+ $this->service->rank_id = empty($_POST['rank_id']) ? null : (int) $_POST['rank_id'];
+ $this->service->description = Daemon::getArrayValue($_POST, 'desc');
+ $this->editor->updateRow($this->service);
+ return true;
+ }
+ //add item
+ if(isset($_POST['addItem'], $_POST['id']) && $_POST['id'])
+ {
+ $params = array('service_id' => $this->editId, 'item_id' => $_POST['id']);
+ $row = new Daemon_Scyzoryk_DbRowServiceItem($params);
+ $this->editor->updateRow($row);
+ return true;
+ }
+ //delete items
+ if(isset($_POST['del']))
+ {
+ $this->editor->deleteServiceItems($this->editId, $_POST['del']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/services.php b/2013/daemon/public/scyzoryk/services.php
new file mode 100644
index 0000000..e35e3a9
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/services.php
@@ -0,0 +1,39 @@
+view->services = $this->browser->getServices();
+ }
+
+
+ protected function runCommands()
+ {
+ //add new row
+ if(isset($_POST['newId'], $_POST['newName']) && $_POST['newId'])
+ {
+ $params = array('service_id' => $_POST['newId'], 'name' => $_POST['newName']);
+ $this->editor->updateRow(new Daemon_Scyzoryk_DbRowService($params));
+ return true;
+ }
+ //delete rows
+ if(isset($_POST['del']))
+ {
+ $this->editor->deleteServices($_POST['del']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/title-edit.php b/2013/daemon/public/scyzoryk/title-edit.php
new file mode 100644
index 0000000..3d95828
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/title-edit.php
@@ -0,0 +1,46 @@
+title = $this->editor->selectRow('Daemon_Scyzoryk_DbRowTitle', $this->editId);
+ }
+
+
+ protected function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->title ? $this->editId : null;
+ $this->view->title = $this->title;
+ }
+
+
+ protected function runCommands()
+ {
+ if(is_null($this->title))
+ return false;
+ if(isset($_POST['id']) && $_POST['id'])
+ {
+ $this->title->title_id = $_POST['id'];
+ $this->title->name_f = Daemon::getArrayValue($_POST, 'name_f');
+ $this->title->name_m = Daemon::getArrayValue($_POST, 'name_m');
+ $this->title->name_n = Daemon::getArrayValue($_POST, 'name_n');
+ $this->title->type = Daemon::getArrayValue($_POST, 'type');
+ $this->editor->updateRow($this->title);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_TitleEdit($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/scyzoryk/titles.php b/2013/daemon/public/scyzoryk/titles.php
new file mode 100644
index 0000000..ca2e18d
--- /dev/null
+++ b/2013/daemon/public/scyzoryk/titles.php
@@ -0,0 +1,39 @@
+view->titles = $this->browser->getTitles();
+ }
+
+
+ protected function runCommands()
+ {
+ //add new row
+ if(isset($_POST['newId']) && $_POST['newId'])
+ {
+ $params = array('title_id' => $_POST['newId']);
+ $this->editor->updateRow(new Daemon_Scyzoryk_DbRowTitle($params));
+ return true;
+ }
+ //delete rows
+ if(isset($_POST['del']))
+ {
+ $this->editor->deleteTitles($_POST['del']);
+ return true;
+ }
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Scyzoryk_Controller_Titles($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/service.php b/2013/daemon/public/service.php
new file mode 100644
index 0000000..af5a573
--- /dev/null
+++ b/2013/daemon/public/service.php
@@ -0,0 +1,90 @@
+characterData->character_id)
+ return;//logged out
+ //check available services
+ $services = $this->location->getServices();
+ $serviceId = isset($_GET['id']) ? $_GET['id'] : null;
+ $this->service = null;
+ $this->bankEnabled = false;
+ $this->templeEnabled = false;
+ foreach ($services as $srv)
+ {
+ if (empty($srv['_enabled']))
+ continue;
+ if ($srv['service_id'] == $serviceId)
+ $this->service = $srv;
+ if ($srv['type'] == 'bank')
+ $this->bankEnabled = true;
+ elseif ($srv['type'] == 'temple')
+ $this->templeEnabled = true;
+ }
+ if(empty($this->service))
+ {
+ Daemon_MsgQueue::add('Wybrana usługa nie istnieje lub jest niedostępna.');
+ Daemon::redirect($this->cfg->getUrl('map'));
+ exit;
+ }
+ //prepare service handler
+ $classes = array(
+ 'bank' => 'Daemon_Service_Bank',
+ 'healer' => 'Daemon_Service_Healer',
+ 'shop' => 'Daemon_Service_Shop',
+ 'temple' => 'Daemon_Service_Temple',
+ );
+ if (isset($classes[$this->service['type']]))
+ $className = $classes[$this->service['type']];
+ else
+ $className = null;
+ if(class_exists($className, true) && is_subclass_of($className, 'Daemon_Service'))
+ {
+ $this->handler = new $className($this->dbClient, $this->characterData, $this->view,
+ $this->service, $this->bankEnabled, $this->templeEnabled);
+ }
+ else
+ {
+ Daemon_MsgQueue::add('Nieznany typ usługi.');
+ Daemon::redirect($this->cfg->getUrl('map'));
+ exit;
+ }
+ }
+
+
+ public function prepareView()
+ {
+ $this->pageSubtitleDetails = $this->service['name'];
+ $this->view->eventLog = $this->handler->getEventLog();
+ }
+
+
+ public function runCommands()
+ {
+ $this->handler->execute($_POST);
+ return $this->handler->isCommand();
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/static/badziew.jpg b/2013/daemon/public/static/badziew.jpg
new file mode 100644
index 0000000..a9a619a
Binary files /dev/null and b/2013/daemon/public/static/badziew.jpg differ
diff --git a/2013/daemon/public/static/badziew2.jpg b/2013/daemon/public/static/badziew2.jpg
new file mode 100644
index 0000000..f29b51c
Binary files /dev/null and b/2013/daemon/public/static/badziew2.jpg differ
diff --git a/2013/daemon/public/static/badziew3.jpg b/2013/daemon/public/static/badziew3.jpg
new file mode 100644
index 0000000..4f51fd9
Binary files /dev/null and b/2013/daemon/public/static/badziew3.jpg differ
diff --git a/2013/daemon/public/static/badziew4.jpg b/2013/daemon/public/static/badziew4.jpg
new file mode 100644
index 0000000..24e1473
Binary files /dev/null and b/2013/daemon/public/static/badziew4.jpg differ
diff --git a/2013/daemon/public/static/badziew5.jpg b/2013/daemon/public/static/badziew5.jpg
new file mode 100644
index 0000000..613cc31
Binary files /dev/null and b/2013/daemon/public/static/badziew5.jpg differ
diff --git a/2013/daemon/public/static/basic.css b/2013/daemon/public/static/basic.css
new file mode 100644
index 0000000..8859c71
--- /dev/null
+++ b/2013/daemon/public/static/basic.css
@@ -0,0 +1,67 @@
+@charset "UTF-8";
+
+* {font-family:sans-serif; border-width:thin; outline-width:thin}
+body {padding:1ex}
+h1, h2, h3 {margin-top:0; margin-bottom:0}
+a > img {border-style:none; vertical-align:text-bottom}
+a > * {color:inherit; background-color:transparent}
+a[rel=feed] {padding-right:16px;background:url("feed.png") no-repeat right}
+caption {margin-top:1em}
+th, td {padding-left:1ex; padding-right:1ex}
+
+header {display:table; margin-bottom:1ex}
+header > h1, header > form {display:table-cell}
+header > h1 {vertical-align:top; max-width:50%}
+header > h1 * {width:100%}
+header p, header ul {margin:.2ex 2ex}
+header ul {list-style-type:none; padding-left:0}
+header ul > li {margin-right:1ex; text-align:center}
+section {display:block; margin-top:1ex; margin-bottom:1ex}
+#menu {display:block; clear:both}
+#menu > li {display:block; float:left}
+#menu > li > a {display:block; float:left; min-width:100px; padding-top:85px; background-repeat:no-repeat}
+
+.msg {font-weight:bold; padding:0 1ex; outline-style:solid}
+ul.msg > li {margin:0; list-style-position:inside}
+ul.menu {padding:.5em 1ex; list-style-type:none}
+ul.menu > li {display:inline; margin:0 1ex}
+ul.menu > li > * {display:inline}
+ul.news {padding-left:0}
+dt {font-weight:bold}
+
+fieldset {margin:1ex}
+form > p {margin-left:1ex}
+label {white-space:nowrap}
+input, select, textarea, button {border-style:solid; border-color:#000; font-family:monospace; margin:0.5ex}
+button {cursor:pointer; font-family:sans-serif}
+th label, td label {font-weight:normal}
+input[type=checkbox], input[type=radio] {vertical-align:middle}
+button {border-style:outset; -moz-border-radius:4px; border-radius:4px}
+
+.center {text-align:center}
+.center legend {text-align:center; margin:auto}
+.border {border-style:solid}
+table.border {margin:1ex}
+table.border th, table.border td {border-style:solid}
+
+.avatar {text-align:center}
+.avatar img, img.bbcode {max-width:400px; max-height:500px}
+
+.multicols {display:table; width:100%; border-collapse:separate; border-spacing:1ex}
+.multicols > * {display:table-cell; padding:1ex; vertical-align:top; border-style:solid}
+
+.ex {font-size:1.5em; font-weight:bold;}
+
+form.pretty > fieldset {text-align:center}
+form.pretty ul {margin:0; padding:0; text-align:left}
+form.pretty li {list-style:none; margin: 0; padding: 1ex}
+form.pretty li > * {margin:0; padding:0}
+form.pretty li > label {display: inline-block; min-width:25%; line-height:1.8; vertical-align: top}
+form.pretty li > input[type=checkbox] {margin-left:25%}
+
+div.locationName {height:20em; background-position: center center; background-repeat: no-repeat}
+div.locationName *, div.locationName a {background: transparent}
+
+section.item-list {clear:both}
+section.item-list > img {float:left}
+section.item-list > form {margin-left:155px}
diff --git a/2013/daemon/public/static/biglogo.jpg b/2013/daemon/public/static/biglogo.jpg
new file mode 100644
index 0000000..2e94029
Binary files /dev/null and b/2013/daemon/public/static/biglogo.jpg differ
diff --git a/2013/daemon/public/static/common.js b/2013/daemon/public/static/common.js
new file mode 100644
index 0000000..1eae29a
--- /dev/null
+++ b/2013/daemon/public/static/common.js
@@ -0,0 +1,4 @@
+
+(function(){var i,n,elements;if(!document.addEventListener){return;}
+elements=document.getElementsByTagName('input');for(i=0,n=elements.length;i *, .box, fieldset, table.border th, table.border td {background-color:black; background-color:rgba(0, 0, 0, 0.5)}
+ body {background-image: url(bg.jpg)}
+ a:link, a:visited {font-weight:bold; color:red}
+ a:link:focus, a:visited:focus {color:red; background-color:white}
+ a:link:hover, a:visited:hover {color:red; background-color:white}
+ .msg {outline-color:red}
+ .msg, .msg > * {color:yellow; background-color:inherit}
+ input, select, textarea, button {border-color:#fff; color:white; background-color:black}
+ input:focus, select:focus, select:focus *, textarea:focus, button:focus, button:focus *,
+ input:hover, select:hover, select:hover *, textarea:hover, button:hover, button:hover *
+ {color:white; border-color:red; background-color:#333}
+ [disabled], [disabled]:hover {color:gray; border-color:gray; outline-color:gray; background-color:black}
+ button {background-image:-moz-linear-gradient(center top, gray, black)}
+ button {background-image:-webkit-gradient(linear, left top, left bottom, from(gray), to(black));}
+ #menu .menu-map {background-image:url(otoczenie.png)}
+ #menu .menu-character {background-image:url(postac.png)}
+ #menu .menu-inventory {background-image:url(ekwip.png)}
+ #menu .menu-clan {background-image:url(klan.png)}
+ #menu .menu-mail {background-image:url(poczta.png)}
+ #menu .menu-chat {background-image:url(forum.png)}
+ #menu .menu-account {background-image:url(konto.png)}
+ #menu .menu-register {background-image:url(konto.png)}
+ #menu .menu-stats {background-image:url(ranking.png)}
+ #menu .menu-help {background-image:url(pomoc.png)}
+}
diff --git a/2013/daemon/public/static/favicon.png b/2013/daemon/public/static/favicon.png
new file mode 100644
index 0000000..282fcc7
Binary files /dev/null and b/2013/daemon/public/static/favicon.png differ
diff --git a/2013/daemon/public/static/feed.png b/2013/daemon/public/static/feed.png
new file mode 100644
index 0000000..b3c949d
Binary files /dev/null and b/2013/daemon/public/static/feed.png differ
diff --git a/2013/daemon/public/static/item-types/accesory.gif b/2013/daemon/public/static/item-types/accesory.gif
new file mode 100644
index 0000000..f8589a7
Binary files /dev/null and b/2013/daemon/public/static/item-types/accesory.gif differ
diff --git a/2013/daemon/public/static/item-types/armor.gif b/2013/daemon/public/static/item-types/armor.gif
new file mode 100644
index 0000000..11ee027
Binary files /dev/null and b/2013/daemon/public/static/item-types/armor.gif differ
diff --git a/2013/daemon/public/static/item-types/boots.gif b/2013/daemon/public/static/item-types/boots.gif
new file mode 100644
index 0000000..b94f627
Binary files /dev/null and b/2013/daemon/public/static/item-types/boots.gif differ
diff --git a/2013/daemon/public/static/item-types/gloves.gif b/2013/daemon/public/static/item-types/gloves.gif
new file mode 100644
index 0000000..e2d4af6
Binary files /dev/null and b/2013/daemon/public/static/item-types/gloves.gif differ
diff --git a/2013/daemon/public/static/item-types/helmet.gif b/2013/daemon/public/static/item-types/helmet.gif
new file mode 100644
index 0000000..11327da
Binary files /dev/null and b/2013/daemon/public/static/item-types/helmet.gif differ
diff --git a/2013/daemon/public/static/item-types/item.gif b/2013/daemon/public/static/item-types/item.gif
new file mode 100644
index 0000000..643eea9
Binary files /dev/null and b/2013/daemon/public/static/item-types/item.gif differ
diff --git a/2013/daemon/public/static/item-types/pendant.gif b/2013/daemon/public/static/item-types/pendant.gif
new file mode 100644
index 0000000..c85c345
Binary files /dev/null and b/2013/daemon/public/static/item-types/pendant.gif differ
diff --git a/2013/daemon/public/static/item-types/weapon1h.gif b/2013/daemon/public/static/item-types/weapon1h.gif
new file mode 100644
index 0000000..3b1a562
Binary files /dev/null and b/2013/daemon/public/static/item-types/weapon1h.gif differ
diff --git a/2013/daemon/public/static/item-types/weapon2h.gif b/2013/daemon/public/static/item-types/weapon2h.gif
new file mode 100644
index 0000000..99e718c
Binary files /dev/null and b/2013/daemon/public/static/item-types/weapon2h.gif differ
diff --git a/2013/daemon/public/static/light/bg.jpg b/2013/daemon/public/static/light/bg.jpg
new file mode 100644
index 0000000..8bef276
Binary files /dev/null and b/2013/daemon/public/static/light/bg.jpg differ
diff --git a/2013/daemon/public/static/light/ekwip.png b/2013/daemon/public/static/light/ekwip.png
new file mode 100644
index 0000000..b7a73d8
Binary files /dev/null and b/2013/daemon/public/static/light/ekwip.png differ
diff --git a/2013/daemon/public/static/light/forum.png b/2013/daemon/public/static/light/forum.png
new file mode 100644
index 0000000..622f619
Binary files /dev/null and b/2013/daemon/public/static/light/forum.png differ
diff --git a/2013/daemon/public/static/light/klan.png b/2013/daemon/public/static/light/klan.png
new file mode 100644
index 0000000..7bb33b7
Binary files /dev/null and b/2013/daemon/public/static/light/klan.png differ
diff --git a/2013/daemon/public/static/light/konto.png b/2013/daemon/public/static/light/konto.png
new file mode 100644
index 0000000..ed38a49
Binary files /dev/null and b/2013/daemon/public/static/light/konto.png differ
diff --git a/2013/daemon/public/static/light/logo.jpg b/2013/daemon/public/static/light/logo.jpg
new file mode 100644
index 0000000..4b1847e
Binary files /dev/null and b/2013/daemon/public/static/light/logo.jpg differ
diff --git a/2013/daemon/public/static/light/otoczenie.png b/2013/daemon/public/static/light/otoczenie.png
new file mode 100644
index 0000000..3fb79cc
Binary files /dev/null and b/2013/daemon/public/static/light/otoczenie.png differ
diff --git a/2013/daemon/public/static/light/poczta.png b/2013/daemon/public/static/light/poczta.png
new file mode 100644
index 0000000..df68a19
Binary files /dev/null and b/2013/daemon/public/static/light/poczta.png differ
diff --git a/2013/daemon/public/static/light/pomoc.png b/2013/daemon/public/static/light/pomoc.png
new file mode 100644
index 0000000..64545ae
Binary files /dev/null and b/2013/daemon/public/static/light/pomoc.png differ
diff --git a/2013/daemon/public/static/light/postac.png b/2013/daemon/public/static/light/postac.png
new file mode 100644
index 0000000..0785b34
Binary files /dev/null and b/2013/daemon/public/static/light/postac.png differ
diff --git a/2013/daemon/public/static/light/ranking.png b/2013/daemon/public/static/light/ranking.png
new file mode 100644
index 0000000..512a703
Binary files /dev/null and b/2013/daemon/public/static/light/ranking.png differ
diff --git a/2013/daemon/public/static/light/skin.css b/2013/daemon/public/static/light/skin.css
new file mode 100644
index 0000000..5ef1a9b
--- /dev/null
+++ b/2013/daemon/public/static/light/skin.css
@@ -0,0 +1,31 @@
+@charset "UTF-8";
+@import "../basic.css";
+@media screen
+{
+ * {color:black; border-color:black; outline-color:black}
+ .multicols > *, .box, fieldset, table.border th, table.border td {background-color:white; background-color:rgba(255, 255, 255, 0.5)}
+ body {background-image: url(bg.jpg)}
+ a:link, a:visited {font-weight:bold; color:red}
+ a:link:focus, a:visited:focus {color:red; background-color:darkgray}
+ a:link:hover, a:visited:hover {color:red; background-color:darkgray}
+ .msg {outline-color:red}
+ .msg, .msg > * {color:purple; background-color:inherit}
+ fieldset {border-color:#888}
+ input, select, textarea, button {border-color:#000}
+ input:focus, select:focus, textarea:focus, button:focus, button:focus *,
+ input:hover, select:hover, textarea:hover, button:hover, button:hover *
+ {color:black; border-color:red; background-color:#ccc}
+ [disabled], [disabled]:hover {color:gray; border-color:gray; outline-color:gray; background-color:white}
+ button {background-image:-moz-linear-gradient(center top, white, gray)}
+ button {background-image:-webkit-gradient(linear, left top, left bottom, from(white), to(gray));}
+ #menu .menu-map {background-image:url(otoczenie.png)}
+ #menu .menu-character {background-image:url(postac.png)}
+ #menu .menu-inventory {background-image:url(ekwip.png)}
+ #menu .menu-clan {background-image:url(klan.png)}
+ #menu .menu-mail {background-image:url(poczta.png)}
+ #menu .menu-chat {background-image:url(forum.png)}
+ #menu .menu-account {background-image:url(konto.png)}
+ #menu .menu-register {background-image:url(konto.png)}
+ #menu .menu-stats {background-image:url(ranking.png)}
+ #menu .menu-help {background-image:url(pomoc.png)}
+}
diff --git a/2013/daemon/public/static/maps/Jary_Czyngijskie.jpg b/2013/daemon/public/static/maps/Jary_Czyngijskie.jpg
new file mode 100644
index 0000000..1647d29
Binary files /dev/null and b/2013/daemon/public/static/maps/Jary_Czyngijskie.jpg differ
diff --git a/2013/daemon/public/static/maps/gory_kranca.jpg b/2013/daemon/public/static/maps/gory_kranca.jpg
new file mode 100755
index 0000000..5d37afa
Binary files /dev/null and b/2013/daemon/public/static/maps/gory_kranca.jpg differ
diff --git a/2013/daemon/public/static/maps/goryczerwone.jpg b/2013/daemon/public/static/maps/goryczerwone.jpg
new file mode 100644
index 0000000..d6684d5
Binary files /dev/null and b/2013/daemon/public/static/maps/goryczerwone.jpg differ
diff --git a/2013/daemon/public/static/maps/kungfu1.jpg b/2013/daemon/public/static/maps/kungfu1.jpg
new file mode 100755
index 0000000..6c59edf
Binary files /dev/null and b/2013/daemon/public/static/maps/kungfu1.jpg differ
diff --git a/2013/daemon/public/static/maps/mainmap.jpg b/2013/daemon/public/static/maps/mainmap.jpg
new file mode 100755
index 0000000..21dd640
Binary files /dev/null and b/2013/daemon/public/static/maps/mainmap.jpg differ
diff --git a/2013/daemon/public/static/maps/prowincja_yang.jpg b/2013/daemon/public/static/maps/prowincja_yang.jpg
new file mode 100644
index 0000000..105b7fe
Binary files /dev/null and b/2013/daemon/public/static/maps/prowincja_yang.jpg differ
diff --git a/2013/daemon/public/static/maps/prowincja_yin.jpg b/2013/daemon/public/static/maps/prowincja_yin.jpg
new file mode 100644
index 0000000..045058d
Binary files /dev/null and b/2013/daemon/public/static/maps/prowincja_yin.jpg differ
diff --git a/2013/daemon/public/static/maps/wieczny_las.jpg b/2013/daemon/public/static/maps/wieczny_las.jpg
new file mode 100755
index 0000000..e35e6ab
Binary files /dev/null and b/2013/daemon/public/static/maps/wieczny_las.jpg differ
diff --git a/2013/daemon/public/static/monastery04.png b/2013/daemon/public/static/monastery04.png
new file mode 100644
index 0000000..f580eb8
Binary files /dev/null and b/2013/daemon/public/static/monastery04.png differ
diff --git a/2013/daemon/public/static/pack-css.php b/2013/daemon/public/static/pack-css.php
new file mode 100644
index 0000000..44bba7d
--- /dev/null
+++ b/2013/daemon/public/static/pack-css.php
@@ -0,0 +1,55 @@
+%s minified to %s ', $file, $dst);
+ else $msg[] = sprintf('%s is not writable', $dst);
+ }
+ else $msg[] = sprintf('%s is not readable', $file);
+ }
+}
+//list files
+$files = glob('*.js');
+$baseDir = dirname(__FILE__);
+header('Content-Type:text/html; charset=UTF-8', true);
+?>
+
+
+JS
+';
+ foreach($msg as $m)
+ printf('%s ', $m);
+ echo'';
+}
+?>
+
+%1$s [%2$d B]', htmlspecialchars($f), filesize($f));
+?>
+
+
+
diff --git a/2013/daemon/public/static/reyka.jpg b/2013/daemon/public/static/reyka.jpg
new file mode 100644
index 0000000..d1e81e2
Binary files /dev/null and b/2013/daemon/public/static/reyka.jpg differ
diff --git a/2013/daemon/public/static/scyzoryk.js b/2013/daemon/public/static/scyzoryk.js
new file mode 100644
index 0000000..ccff512
--- /dev/null
+++ b/2013/daemon/public/static/scyzoryk.js
@@ -0,0 +1,4 @@
+
+var scyzorykSearch={open:function(event){try{if(this.windowSearch&&this.windowSearch.close&&!this.windowSearch.closed){this.windowSearch.close();this.windowSearch=null;}
+this.windowSearch=window.open('search?type='+this.getAttribute('data-search-type'),this.getAttribute('data-search-target'));}catch(ex){alert('Błąd otwierania popupa.');}},loadResult:function(event){var target;if(window.opener&&window.opener.document){target=window.opener.document.getElementById(window.name);if(target){target.value=this.getAttribute('data-search-result');window.close();}}},init:function(elements){var e,i,n;for(i=0,n=elements.length;istats = new Daemon_Statistics($this->dbClient);
+ $this->listLimit = max(1, (int) $this->dbCfg->listLimitStatistics);
+ }
+
+
+ public function prepareView()
+ {
+ $battleId = isset($_GET['view']) ? (int) $_GET['view'] : 0;
+ if($battleId)
+ $this->prepareViewBattle($battleId);
+ else $this->prepareViewList();
+ }
+
+
+ //single item mode
+ private function prepareViewBattle($battleId)
+ {
+ $this->pageSubtitle = 'Bitwa';
+ $this->pageTemplatePath = 'stats-battle.xml';
+ $this->view->menu = $this->view->getStatisticsMenu();
+ $this->view->battle = $this->stats->getBattleById($battleId);
+ }
+
+
+ //character list mode
+ private function prepareViewList()
+ {
+ $this->pageSubtitleUseQuery = true;
+ $from = isset($_GET['from']) ? (int) $_GET['from'] : 0;
+ $data = $this->stats->getBattles($this->listLimit, $from);
+ $nextUrl = $data['next'] ? '?from='.urlencode($data['next']) : null;
+ $this->view->menu = $this->view->getStatisticsMenu('battles');
+ $this->view->nextUrl = $nextUrl;
+ $this->view->list = $data['list'];
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/stats-characters.php b/2013/daemon/public/stats-characters.php
new file mode 100644
index 0000000..6c214b6
--- /dev/null
+++ b/2013/daemon/public/stats-characters.php
@@ -0,0 +1,94 @@
+clanId = isset($_GET['clan']) ? (string) $_GET['clan'] : null;
+ $this->stats = new Daemon_Statistics($this->dbClient);
+ $this->listLimit = max(1, (int) $this->dbCfg->listLimitStatistics);
+ }
+
+
+ public function prepareView()
+ {
+ $characterId = isset($_GET['view']) ? (int) $_GET['view'] : 0;
+ if($characterId)
+ $this->prepareViewCharacter($characterId);
+ else $this->prepareViewList();
+ }
+
+
+ //single character mode
+ private function prepareViewCharacter($characterId)
+ {
+ $character = $this->stats->getCharacterById($characterId);
+ $this->pageTemplatePath = 'stats-character.xml';
+ $this->pageSubtitleDetails = isset($character['name']) ? $character['name'] : null;
+ $this->view->menu = $this->view->getStatisticsMenu();
+ if($character)
+ {
+ $character['description'] = Daemon::formatMessage($character['description'], true);
+ $this->view->genderName = Daemon_Dictionary::$genders[(string) $character['gender']];
+ $playerId = $this->player->getPlayerId();
+ if($playerId && ($character['player_id'] != $playerId))
+ $this->view->mailUrl = sprintf('mail?to=%s', urlencode($character['name']));
+ else $this->view->mailUrl = null;
+ }
+ $this->view->characterId = $characterId;
+ $this->view->character = $character;
+ }
+
+
+ //character list mode
+ private function prepareViewList()
+ {
+ $this->pageSubtitleUseQuery = true;
+ $listOrder = isset($_GET['sort']) ? (string) $_GET['sort'] : 'xp';
+
+ $from = isset($_GET['from']) ? (string) $_GET['from'] : null;
+ $data = $this->stats->getCharacters($this->listLimit, $from, $listOrder, $this->clanId);
+
+ if($data['next'] )
+ {
+ $nextUrl = '?from='.urlencode($data['next']);
+ if($this->clanId)
+ $nextUrl .= '&clan='.urlencode($this->clanId);
+ if($listOrder)
+ $nextUrl .= '&sort='.urlencode($listOrder);
+ }
+ else $nextUrl = null;
+ $this->view->menu = $this->view->getStatisticsMenu('characters');
+ $this->view->nextUrl = $nextUrl;
+ $this->view->list = $data['list'];
+
+ $headers = array(
+ 'name' => array('name' => 'Postać'),
+ 'lvl' => array('name' => 'Poziom'),
+ 'xp' => array('name' => 'Doświadczenie', 'abbr' => 'EXP'),
+ 'fac' => array('name' => 'Frakcja'),
+ 'clan' => array('name' => 'Klan'),
+ 'date' => array('name' => 'Data narodzin'),
+ 'last' => array('name' => 'Ostatnia wizyta'),
+ 'win' => array('name' => 'Wygrane pojedynki', 'abbr' => 'Win'),
+ 'los' => array('name' => 'Przegrane pojedynki', 'abbr' => 'Los'),
+ );
+ $headers[$listOrder]['selected'] = true;
+ $this->view->headers = $headers;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Characters($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/stats-clans.php b/2013/daemon/public/stats-clans.php
new file mode 100644
index 0000000..c03abdc
--- /dev/null
+++ b/2013/daemon/public/stats-clans.php
@@ -0,0 +1,60 @@
+stats = new Daemon_Statistics($this->dbClient);
+ $this->listLimit = max(1, (int) $this->dbCfg->listLimitStatistics);
+ }
+
+
+ public function prepareView()
+ {
+ $clanId = isset($_GET['view']) ? $_GET['view'] : null;
+ if($clanId)
+ $this->prepareViewClan($clanId);
+ else $this->prepareViewList();
+ }
+
+
+ //single duel mode
+ private function prepareViewClan($clanId)
+ {
+ $clan = $this->stats->getClanById($clanId);
+ if ($clan)
+ $clan['description'] = Daemon::formatMessage($clan['description'], true);
+ $this->pageSubtitle = 'Klan';
+ $this->pageTemplatePath = 'stats-clan.xml';
+ $this->pageSubtitleDetails = isset($clan['name']) ? $clan['name'] : null;
+ $this->view->menu = $this->view->getStatisticsMenu();
+ $this->view->clan = $clan;
+ }
+
+
+ //character list mode
+ private function prepareViewList()
+ {
+ $this->pageSubtitleUseQuery = true;
+ $from = isset($_GET['from']) ? $_GET['from'] : null;
+ $data = $this->stats->getClans($this->listLimit, $from);
+ $nextUrl = $data['next'] ? '?from='.urlencode($data['next']) : null;
+ $this->view->menu = $this->view->getStatisticsMenu('clans');
+ $this->view->nextUrl = $nextUrl;
+ $this->view->list = $data['list'];
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/stats-duels.php b/2013/daemon/public/stats-duels.php
new file mode 100644
index 0000000..db29875
--- /dev/null
+++ b/2013/daemon/public/stats-duels.php
@@ -0,0 +1,73 @@
+characterId = isset($_GET['char']) ? (int) $_GET['char'] : 0;
+ $this->stats = new Daemon_Statistics($this->dbClient);
+ $this->listLimit = max(1, (int) $this->dbCfg->listLimitStatistics);
+ }
+
+
+ public function prepareView()
+ {
+ $duelId = isset($_GET['view']) ? (int) $_GET['view'] : 0;
+ if($duelId)
+ $this->prepareViewDuel($duelId);
+ else $this->prepareViewList();
+ }
+
+
+ //single duel mode
+ private function prepareViewDuel($duelId)
+ {
+ $this->pageSubtitle = 'Pojedynek';
+ $this->pageTemplatePath = 'stats-duel.xml';
+ $this->view->menu = $this->view->getStatisticsMenu();
+ $this->view->duel = $this->stats->getDuelById($this->player->getCharacterId(), $duelId);
+ }
+
+
+ //character list mode
+ private function prepareViewList()
+ {
+ $this->pageSubtitleUseQuery = true;
+ $from = isset($_GET['from']) ? (int) $_GET['from'] : 0;
+ $data = $this->stats->getDuels($this->listLimit, $from, $this->characterId, $this->player->getCharacterId());
+
+ $duelTypes = array('normal' => 'zwykła', 'arena' => 'sparring');
+ $winnerTypes = array('a' => 'ataker', 'b' => 'obrońca');
+ foreach($data['list'] as &$row)
+ {
+ $row['type'] = isset($duelTypes[$row['type']]) ? $duelTypes[$row['type']] : null;
+ $row['winner'] = isset($winnerTypes[$row['winner']]) ? $winnerTypes[$row['winner']] : 'remis';
+ }
+
+ if($data['next'])
+ {
+ $nextUrl = '?from='.urlencode($data['next']);
+ if($this->characterId)
+ $nextUrl .= '&char='.urlencode($this->characterId);
+ }
+ else $nextUrl = null;
+ $this->view->menu = $this->view->getStatisticsMenu('duels');
+ $this->view->nextUrl = $nextUrl;
+ $this->view->list = $data['list'];
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Page($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/stats.php b/2013/daemon/public/stats.php
new file mode 100644
index 0000000..48e7816
--- /dev/null
+++ b/2013/daemon/public/stats.php
@@ -0,0 +1,74 @@
+view->$name = $this->dbCfg->$name;
+ $this->view->menu = $this->view->getStatisticsMenu('status');
+ //factions
+ $factions = array();
+ $powers = array();
+ $sql = "SELECT faction_id, name, power FROM factions ORDER BY name";
+ foreach($this->dbClient->selectAll($sql) as $row)
+ {
+ $factions[$row['faction_id']] = array('name' => $row['name'], 'power' => $row['power'],
+ 'chars' => 0, 'caerns' => '', 'powerMult' => null);
+ $powers[$row['faction_id']] = $row['power'];
+ }
+ foreach($factions as $factionId => &$row)
+ $row['powerMult'] = sprintf('%.2f', 100 * Daemon_Math::factionPowerMult($factionId, $powers));
+ unset($row, $powers);
+ $sql = "SELECT faction_id, COUNT(character_id) AS n
+ FROM character_data WHERE faction_id IS NOT NULL GROUP BY faction_id";
+ foreach($this->dbClient->selectAll($sql) as $row)
+ {
+ if(isset($factions[$row['faction_id']]))
+ $factions[$row['faction_id']]['chars'] = (int) $row['n'];
+ }
+ $sql = "SELECT faction_id, GROUP_CONCAT(name SEPARATOR ', ') AS names
+ FROM locations WHERE faction_id IS NOT NULL AND type='caern' GROUP BY faction_id";
+ foreach($this->dbClient->selectAll($sql) as $row)
+ {
+ if(isset($factions[$row['faction_id']]))
+ $factions[$row['faction_id']]['caerns'] = $row['names'];
+ }
+ $this->view->factions = $factions;
+ //caerns
+ $sql = "SELECT l.name
+ FROM locations l JOIN character_data cd USING(location_id)
+ WHERE l.type='caern' AND cd.faction_id IS NOT NULL AND cd.faction_id != l.faction_id
+ GROUP BY l.location_id ORDER BY l.name";
+ $this->view->caernSieges = $this->dbClient->selectColumn($sql);
+ //rollovers
+ $rollovers = array();
+ $sql = "SELECT rollover_id, players_total, characters_total, clans_total,
+ date_format(date_added, '%Y-%m-%d %H:%i') AS date_added
+ FROM rollovers ORDER BY rollover_id DESC LIMIT 10";
+ foreach ($this->dbClient->selectAll($sql) as $row)
+ {
+ $row['_battles'] = array();
+ $rollovers[$row['rollover_id']] = $row;
+ }
+ $sql = "SELECT b.battle_id, b.rollover_id, l.name
+ FROM battles b LEFT JOIN locations l USING(location_id)
+ WHERE b.rollover_id >= :id ORDER BY b.battle_id";
+ $params = array('id' => min(array_keys($rollovers)));
+ foreach ($this->dbClient->selectAll($sql, $params) as $row)
+ $rollovers[$row['rollover_id']]['_battles'][$row['battle_id']] = $row['name'];
+ $this->view->rollovers = $rollovers;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Status($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/public/temple.php b/2013/daemon/public/temple.php
new file mode 100644
index 0000000..e3a56b1
--- /dev/null
+++ b/2013/daemon/public/temple.php
@@ -0,0 +1,78 @@
+characterData->character_id)
+ return;//logged out
+ $flags = $this->location->getFlags();
+ $this->bankEnabled = !empty($flags['bank']);
+ if(empty($flags['temple']))
+ {
+ Daemon_MsgQueue::add('W tej lokacji nie ma świątyni.');
+ Daemon::redirect($this->cfg->getUrl('map'));
+ exit;
+ }
+ $this->temple = new Daemon_Temple($this->dbClient, $this->characterData,
+ $this->bankEnabled, $this->location->faction_id, $this->dbCfg);
+ $this->temple->locationId = $this->location->location_id;
+ $this->inventory = new Daemon_Inventory($this->dbClient, $this->characterData);
+ }
+
+
+ public function prepareView()
+ {
+ $this->view->temple = $this->temple;
+ $this->view->bankEnabled = $this->bankEnabled;
+ $this->view->itemsToBind = $this->temple->getItems(false, true);
+ $this->view->itemsToOffer = $this->temple->getItems(true, false);
+ $this->view->lastMission = $this->characterData->getLastMission('completed');
+ }
+
+
+ public function runCommands()
+ {
+ //bind item
+ if(isset($_POST['bind']))
+ {
+ $this->temple->bindItem($_POST['bind']);
+ return true;
+ }
+ //pray at altar
+ if(isset($_POST['pray']))
+ {
+ $inventoryId = isset($_POST['offer']) ? $_POST['offer'] : null;
+ $this->temple->pray($_POST['pray'], $inventoryId);
+ return true;
+ }
+ //give up mission
+ if(isset($_POST['giveUp']))
+ {
+ $this->temple->removeMission();
+ return true;
+ }
+ //check mission
+ $this->temple->checkMission();
+ return false;
+ }
+}
+
+
+$ctrl = new Daemon_Controller_Temple($cfg);
+$ctrl->execute();
diff --git a/2013/daemon/tpl/account.xml b/2013/daemon/tpl/account.xml
new file mode 100644
index 0000000..b7b3dc9
--- /dev/null
+++ b/2013/daemon/tpl/account.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+ustawienia konta
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/character.xml b/2013/daemon/tpl/character.xml
new file mode 100644
index 0000000..6265f77
--- /dev/null
+++ b/2013/daemon/tpl/character.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+ Postać
+
+ Poziom
+ ${characterData/level}
+
+
+ Doświadczenie
+ ${characterData/xp_free} + ${characterData/xp_used}
+
+
+ Zdrowie
+ ${characterData/health} / ${characterData/health_max}
+
+
+ Mana
+ ${characterData/mana} / ${characterData/mana_max}
+
+
+ Złoto
+ ${characterData/gold_purse} + ${characterData/gold_bank}
+
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/chat.xml b/2013/daemon/tpl/chat.xml
new file mode 100644
index 0000000..2a64c28
--- /dev/null
+++ b/2013/daemon/tpl/chat.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daemon-Info
+Wysłane: ${item/date_added}
+
+
+
+następna strona...
+
+
+
+
diff --git a/2013/daemon/tpl/clan.xml b/2013/daemon/tpl/clan.xml
new file mode 100644
index 0000000..c064cee
--- /dev/null
+++ b/2013/daemon/tpl/clan.xml
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ustawienia
+
+
+ Nowy przywódca:
+
+
+
+ ${row/name}
+
+
+
+
+ Opis klanu:
+
+ ${clan/description}
+
+ ściągawka
+
+
+
+
+
+ zapisz
+
+
+
+ Podgląd
+
+
+
+
+
+
+
+ odejdź z klanu
+ rozwiąż klan
+
+
+
+
+ Postacie
+
+ Imię
+ Poziom
+ EXP
+ Frakcja
+ Data narodzin
+
+
+
+ ${item/name}
+ ${item/level}
+ ${item/xp_used}
+ brak
+ ${item/faction_id} (r${item/rank_id})
+ ${item/date_created}
+
+ wyrzuć
+
+
+
+
+
+
+
+ Podania
+
+ Imię
+ Poziom
+ EXP
+ Frakcja
+ Data narodzin
+ Podanie
+
+
+
+ ${item/character_name}
+ ${item/level}
+ ${item/xp_used}
+ brak
+ ${item/faction_id} (r${item/rank_id})
+ ${item/date_created}
+ niewypełnione
+ przyjmij
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/duel.xml b/2013/daemon/tpl/duel.xml
new file mode 100644
index 0000000..25729ef
--- /dev/null
+++ b/2013/daemon/tpl/duel.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/duelcombat.xml b/2013/daemon/tpl/duelcombat.xml
new file mode 100644
index 0000000..5a9f89b
--- /dev/null
+++ b/2013/daemon/tpl/duelcombat.xml
@@ -0,0 +1,19 @@
+${attackerName} vs ${defenderName}
+
+
+ Walkę wygrywa ${winnerName} , zdobywając ${winnerXp} doświadczenia.
+ ${winnerName} zdobywa nowy poziom: ${winnerLevel} .
+ ${loserName} traci powłokę cielesną.
+
+
+
+ Walka zakończyła się remisem .
+
+
+
+
+ Zdrowie: ${characterData/health} / ${characterData/health_max}
+
+
+
+
diff --git a/2013/daemon/tpl/edit-account.xml b/2013/daemon/tpl/edit-account.xml
new file mode 100644
index 0000000..a4b1011
--- /dev/null
+++ b/2013/daemon/tpl/edit-account.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+Ustawienia konta
+
+Imię gracza:
+Do wyświetlania w profilu postaci.
+
+Nowe hasło:
+Powtórz hasło:
+Wypełnij tylko jeśli zmieniasz hasło.
+
+Styl strony:
+
+ ${skin}
+
+
+Email:
+Do przypominania hasła, nie wyświetlany w grze.
+
+zapisz
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/edit-character.xml b/2013/daemon/tpl/edit-character.xml
new file mode 100644
index 0000000..0f219ff
--- /dev/null
+++ b/2013/daemon/tpl/edit-character.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+ Ustawienia postaci
+
+ zapisz
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/event.xml b/2013/daemon/tpl/event.xml
new file mode 100644
index 0000000..b090480
--- /dev/null
+++ b/2013/daemon/tpl/event.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/event/deadend.xml b/2013/daemon/tpl/event/deadend.xml
new file mode 100644
index 0000000..60dccd4
--- /dev/null
+++ b/2013/daemon/tpl/event/deadend.xml
@@ -0,0 +1,3 @@
+
+Idąc drogą niespecjalnie zwracasz uwagę na otoczenie. Cóż mogłoby Cię zadziwić w miejscu gdzie upłynęło prawie całe Twe dotychczasowe życie. Jednak w pewnym momencie stajesz w osłupieniu. Oto przed Tobą stoi wielka ściana wykonana z dziwnego materiału. Przypomina on jakiś metal, jednak nie jesteś w stanie go zidentyfikować. Spoglądasz w obie strony, jednak ściana ciągnie się chyba w nieskończoność. Cholera Myślisz sobie, po czym z niechęcią zawracasz.
+
diff --git a/2013/daemon/tpl/event/intro.xml b/2013/daemon/tpl/event/intro.xml
new file mode 100644
index 0000000..99af5b1
--- /dev/null
+++ b/2013/daemon/tpl/event/intro.xml
@@ -0,0 +1,9 @@
+
+
+ Otacza cię mrok a w powietrzu unosi się jakaś dziwna woń. Otwierasz powoli oczy. Przed sobą widzisz jakąś istotę... Maleńkiego, przerażonego człowieczka, trzymającego jakieś zakrzywione ostrze w dłoni... Sztylet... SZTYLET OFIARNY!!! Rozglądasz się dookoła i ze zdumieniem stwierdzasz iż siedzisz właśnie na ołtarzu spływającym krwią. W ciszy niczym szum wodospadu słychać spływającą krew, a łomot przerażonego serca kultysty przygrywa niczym perkusja. Wstajesz i powoli zbliżasz się do tej maleńkiej istotki. Po raz pierwszy i ostatni zamierzasz okazać miłosierdzie. W końcu Ten człowieczek pomógł Ci tu przyjść. Tak... Okażę miłosierdzie... - myślisz, po czym rozszarpujesz kultystę gołymi rękoma...
+
+
+
+
+Stoisz pośrodku komnaty patrząc na resztki nieszczęsnego kultysty. Uśmiech pojawia się na chwile na Twej twarzy na wspomnienie jego agonii, po czym odwracasz się w stronę wyjścia. Z tamtego kierunku coś Cię nawołuje. Tak... Przypominasz sobie... To zew walki... To zew krwi...
+
diff --git a/2013/daemon/tpl/index.xml b/2013/daemon/tpl/index.xml
new file mode 100644
index 0000000..1af481a
--- /dev/null
+++ b/2013/daemon/tpl/index.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+Logowanie
+Login:
+Hasło:
+zaloguj
+
+nie pamiętasz hasła?
+
+
+
+
+
+
+
+Daemon to turowa gra w klimatach fantasy, rozgrywana za pomocą przeglądarki internetowej.
+Zostań daemonem , nadludzką istotą wędrującą po świecie w poszukiwaniu potęgi, bogactwa i sławy.
+W swoich podróżach napotkasz potwory (które możesz zabić) oraz postacie innych graczy (które możesz zabić).
+Mamy także wewnętrzy czat i pocztę, jeśli potrzebujesz innych niż agresja form komunikacji.
+
+Starsze wersje przeglądarki Internet Explorer nie są obsługiwane.
+
+Pomysł i pierwsze ery: Jingizu .
+Kontynuacja: Monku .
+Obecna edycja: anfurious & radical dreamer .
+
+
+Najnowsze wieści
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/inventory.xml b/2013/daemon/tpl/inventory.xml
new file mode 100644
index 0000000..5b59cda
--- /dev/null
+++ b/2013/daemon/tpl/inventory.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${slot/slotName}
+ brak
+
+ ${slot/item/name}
+ (przypisany)
+ zdejmij
+
+
+
+
+
+ Zdrowie ${characterData/health} / ${characterData/health_max}
+ Mana ${characterData/mana} / ${characterData/mana_max}
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/macros.xml b/2013/daemon/tpl/macros.xml
new file mode 100644
index 0000000..c3b18e9
--- /dev/null
+++ b/2013/daemon/tpl/macros.xml
@@ -0,0 +1,108 @@
+
+
+
+ Pierwszy atak
+ Atak z tarczą
+
+ Atak dwuręczny
+
+ ${combatStats/count1}x
+ ${combatStats/type1_name}, trafienie ${combatStats/atk1} , siła ${combatStats/str1}
+ , ${combatStats/sp1_name}(${combatStats/sp1_param})
+
+
+
+ Drugi atak
+
+ ${combatStats/count2}x
+ ${combatStats/type2_name}, trafienie ${combatStats/atk2} , siła ${combatStats/str2}
+ , ${combatStats/sp2_name}(${combatStats/sp2_param})
+
+
+
+ Obrona fizyczna
+ obrona: ${combatStats/pdef} , wytrzymałość: ${combatStats/pres}
+
+
+ Obrona magiczna
+ obrona: ${combatStats/mdef} , wytrzymałość: ${combatStats/mres}
+
+
+ Zbroja
+
+ pancerz: ${combatStats/armor}
+ , ${combatStats/armor_sp_name}(${combatStats/armor_sp_param})
+
+
+
+ Akcja
+ szybkość: ${combatStats/speed} , regeneruje ${combatStats/regen} HP
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/mail.xml b/2013/daemon/tpl/mail.xml
new file mode 100644
index 0000000..8e7e0e1
--- /dev/null
+++ b/2013/daemon/tpl/mail.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+${inputMsg}
+
+Adresat:
+wyślij wiadomość ściągawka
+
+
+
+
+
+pokaż starsze wiadomości...
+
+
+
+
diff --git a/2013/daemon/tpl/map.xml b/2013/daemon/tpl/map.xml
new file mode 100644
index 0000000..a2569e0
--- /dev/null
+++ b/2013/daemon/tpl/map.xml
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Poziom
+ ${characterData/level}
+
+
+ Doświadczenie
+ ${characterData/xp_free} + ${characterData/xp_used}
+
+
+ Zdrowie
+ ${characterData/health} / ${characterData/health_max}
+
+
+ Mana
+ ${characterData/mana} / ${characterData/mana_max}
+
+
+ Złoto
+ ${characterData/gold_purse} + ${characterData/gold_bank}
+
+
+ Misja
+
+ ${lastMission/_name}
+ świątynia: ${lastMission/service_name}
+ przeliczenie nr ${lastMission/rollover_id}
+ status: ${lastMission/_statusName}
+
+
+
+
+
+ Region: ${region}
+ Lokacja: ${location/name}
+ Arena - PvP ograniczone
+ Caern - PvP ograniczone
+ Boss (${location/boss_status_name}) - PvP ograniczone
+ Frakcja: ${faction}
+
+
+
+
+
+
+
+
+
+
+ Akcja
+
+ trening
+ odpoczynek
+ polowanie
+
+
+
+ Wędrówka
+
+
+
+ ${item/path_name}
+ (${item/cost_gold} zł, ${item/cost_mana} MP)
+
+
+
+
+
+
+
+
+
+
+ Inne postacie w tej lokacji
+
+ Postać Poziom EXP Frakcja PvP
+
+ ${item/name}
+ ${item/level}
+ ${item/xp_used}
+ brak
+ ${item/faction_name} (ranga ${item/rank_id})
+ niedozwolone
+
+ atakuj
+ sparring
+
+
+
+ pokaż wszystkie postacie
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/monstercombat.xml b/2013/daemon/tpl/monstercombat.xml
new file mode 100644
index 0000000..78dc28b
--- /dev/null
+++ b/2013/daemon/tpl/monstercombat.xml
@@ -0,0 +1,43 @@
+${activeCharacter/name} vs ${monsterName}
+
+
+
+
+
+ Zdrowie: ${characterData/health} / ${characterData/health_max}
+
+ Mana: ${characterData/mana} / ${characterData/mana_max}
+
+
+
+ trening
+ odpoczynek
+ polowanie
+
+
+
+
+
+ Walkę wygrywa ${activeCharacter/name} .
+
+ Doświadczenie: ${characterData/xp_free} (+${winnerXp}) ,
+ złoto ${characterData/gold_purse} (+${winnerGold}) .
+
+ Nowy poziom: ${winnerLevel} .
+ Zdobyty przedmiot: ${winnerDrop} .
+ Misja zakończona - zgłoś się do świątyni po nagrodę.
+
+
+
+ Walkę wygrywa ${monsterName} .
+ ${activeCharacter/name} traci powłokę cielesną.
+
+
+
+
+
+
+Przebieg walki
+
diff --git a/2013/daemon/tpl/news.xml b/2013/daemon/tpl/news.xml
new file mode 100644
index 0000000..255a340
--- /dev/null
+++ b/2013/daemon/tpl/news.xml
@@ -0,0 +1,19 @@
+
+
+${feedId}
+${feedTitle}
+${feedUpdated}
+Daemon-Info
+
+Making the game since 2008 (-_-;)
+
+ ${item/id}
+ ${item/title}
+ ${item/updated}
+ ${item/published}
+ ${item/author}
+
+
+
+
+
diff --git a/2013/daemon/tpl/register.xml b/2013/daemon/tpl/register.xml
new file mode 100644
index 0000000..c298945
--- /dev/null
+++ b/2013/daemon/tpl/register.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+Rejestracja
+Login:
+Hasło:
+Powtórz hasło:
+rejestruj
+
+
+
+
+
+Admistracja nigdy nie będzie prosić o hasła do kont.
+W ramach jednego konta można posiadać kilka postaci do gry.
+
+
+
+
diff --git a/2013/daemon/tpl/reset-password.xml b/2013/daemon/tpl/reset-password.xml
new file mode 100644
index 0000000..0ad4a72
--- /dev/null
+++ b/2013/daemon/tpl/reset-password.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+Reset hasła
+Login:
+Email:
+
+Hasło:
+Powtórz hasło:
+resetuj hasło
+
+
+
+
+
+Podaj swój login oraz email ustawiony w danych konta.
+
+
+
+
diff --git a/2013/daemon/tpl/respawn.xml b/2013/daemon/tpl/respawn.xml
new file mode 100644
index 0000000..a4b9c44
--- /dev/null
+++ b/2013/daemon/tpl/respawn.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+ Wojna dobiegła końca, nie słyszysz już jej zewu. A może nigdy się nie rozpoczęła?
+ Nieważne, nie dbasz już o to. Powoli, nieubłaganie zanurzasz się z powrotem w sen...
+
+
+
+
+
+ Złe czasy nadeszły dla starożytnego cesarstwa Xin.
+ Nie dość że niedawno musiało odeprzeć najazd barbarzyńców i kilkuletnie oblężenie Wielkiego Muru,
+ nie dość że chłopi raz jeszcze zrobili powstanie buntując się przeciwko podatkom i świętej władzy Cesarza,
+ nie dość że wszelkiej maści wywrotowcy zjednoczyli się ostatnio pod wspólnym sztandarem,
+ tworząc samozwańczą Armię Czerwonej Gwiazdy i grożąc obaleniem Stolicy
+ - to jeszcze astrologowie kraczą o przepowiedni wielkiej wojny i powrotu daemonów
+ a jakiś głupiec uwolnił Nekromantę i horda nieumarłych rośnie właśnie w siłę na wschodzie grożąc zagładą wszystkiego co żywe...
+ Zaiste, rację ma pradawne przekleństwo: Obyś żył w ciekawych czasach...
+
+
+
+ przebudzenie
+
+
+
+
+ Odrodzenie: ${item}
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/rules.xml b/2013/daemon/tpl/rules.xml
new file mode 100644
index 0000000..d92bf6f
--- /dev/null
+++ b/2013/daemon/tpl/rules.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+Ostatnia zmiana: ${lastModified} .
+
+
+
+Regulamin
+
+Drogi Graczu! Witamy w świecie Daemona. Niniejszy dokument opisuje zasady obowiązujące w grze Daemon 2 , w tym praktyki zabronione lub niezgodne z duchem gry i działające na niekorzyść społeczności graczy.
+
+Postanowienia ogólne
+
+Korzystanie z gry jest równoznaczne z akceptacją niniejszego regulaminu.
+
+Konta i postacie
+
+Zabronione są nazwy postaci:
+
+składające się z wyrażeń typu "brak nazwy" albo bezsensownych kombinacji liter lub cyfr
+podobne do nazw już istniejących postaci, zawierające trudne do wpisania znaki lub w inny sposób utrudniające grę innym graczom
+reklamujące produkt lub stronę WWW, za wyjątkiem nazw zezwolonych przez Administrację
+łamiące zasady prywatności lub praw autorskich (ścigane na wniosek osoby poszkodowanej)
+
+
+Administracja
+
+Termin Administracja oznacza zarówno twórców gry jak i wszelkie inne osoby wyznaczone przez nich do zarządzania grą i światem gry. Głównym zadaniem Administracji jest dbanie o odpowiedni poziom rozrywki, kulturę oraz dobro wszystkich graczy.
+
+Postacie należące do Administracji oznaczone są tytułami Administrator lub Moderator .
+
+Administracja ma prawo wglądu do wszelkich informacji przechowywanych w bazie danych gry, w tym zawartości poczty i tablicy ogłoszeń.
+
+Administracja, kierując się dobrem gry, ma prawo do przeprowadzania działań nie zapisanych w Regulaminie. Dotyczy to przede wszystkim pojawienia się nowych zagrań umożliwiających oszustwa niekorzystne dla gry, a także prób obejścia przepisów Regulaminu.
+
+
+Kultura
+
+Administracja nie będzie ingerować w konflikty między graczami dopóki nie nastąpi naruszenie regulaminu.
+
+Zabronione jest:
+
+wyzywanie, słowne poniżanie innych graczy lub Administracji w obrębie całej gry
+używanie słów powszechnie uznawanych za obraźliwe, zamieszczanie w swoich wypowiedziach treści wulgarnych, pornograficznych i innych niezgodnych z obowiązującym w Polsce prawem
+umieszczanie w grze ogłoszeń reklamowych (w tym linków do innych stron WWW) bez pozwolenia Administracji
+
+
+Oszustwa w grze
+
+Zabronione jest podszywanie się pod Administrację, zarówno poprzez imiona tworzonych postaci jak i wypowiedzi w grze.
+
+Znalezione w grze błędy (bugi) należy natychmiast po ich wykryciu zgłosić do Administracji.
+
+Zabronione jest nieuczciwe wzmacnianie postaci, poprzez ustawianie wyników walk czy wszelkie inne nadużycia mechaniki. Dotyczy to zarówno postaci jednego gracza jak i współpracy między kilkoma graczami.
+
+W razie jakichkolwiek wątpliwości należy uzyskać od Administracji informację czy planowane działanie jest zgodne z zasadami gry i nie zostanie ukarane.
+
+Kary
+
+Administracja ma prawo swobodnego doboru rodzaju stosowanej kary, także nieproporcjonalnie do skali przewinienia. Administracja ma także prawo odstąpienia od wymierzenia kary.
+
+Administracja ma prawo zablokowania dostępu do gry danej osobie bez podania przyczyny, jeśli uzna że jej działalność szkodzi grze.
+
+Postanowienia końcowe
+
+Administracja ma prawo do dokonywania zmian w Regulaminie w reakcji na zmiany zachodzące w grze, pod warunkiem że fakt dokonania zmian zostanie ogłoszony w grze - za pomocą tablicy ogłoszeń lub w inny wybrany przez Administrację sposób.
+
+Obowiązkiem graczy jest śledzenie zmian w Regulaminie, a nieznajomość Regulaminu nie zwalnia od odpowiedzialności za dokonywane wykroczenia.
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/arena.xml b/2013/daemon/tpl/scyzoryk/arena.xml
new file mode 100644
index 0000000..f9ab6e6
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/arena.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+Arena
+
+Tryb:
+ potwór vs potwór
+ postać vs potwór
+ postać vs postać
+Przełącz
+
+
+
+ ${row/name}
+
+
+ <${row/combat_unit_id}> ${row/name}
+
+
+VS
+
+
+ <${row/combat_unit_id}> ${row/name}
+
+
+ ${row/name}
+
+
+
+
+FIGHT!
+Ilość:
+
+
+
+
+
+
+ Win A
+ Win B
+ Remis
+ 2xKO
+ Zdrowie A
+ Zdrowie B
+
+
+ AVG
+ MIN
+ MAX
+ AVG
+ MIN
+ MAX
+
+
+ ${winsA}%
+ ${winsB}%
+ ${draws}%
+ ${doubleKOs}%
+ ${healthSumA}%
+ ${healthMinA}%
+ ${healthMaxA}%
+ ${healthSumB}%
+ ${healthMinB}%
+ ${healthMaxB}%
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/character-edit.xml b/2013/daemon/tpl/scyzoryk/character-edit.xml
new file mode 100644
index 0000000..c4e6f22
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/character-edit.xml
@@ -0,0 +1,178 @@
+
+
+
+
+
+
+
+
+Dane trwałe
+
+
+
+
+
+
+
+Dane związane z erą
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/characters.xml b/2013/daemon/tpl/scyzoryk/characters.xml
new file mode 100644
index 0000000..5674419
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/characters.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+ ID
+ Imię
+ Gracz
+ Ostatnia akcja
+
+
+
+
+
+ ${item/character_id}
+ ${item/name}
+ ${item/player_login}
+ porzucona
+ ${item/last_action}
+ edytuj
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/combat-unit-edit.xml b/2013/daemon/tpl/scyzoryk/combat-unit-edit.xml
new file mode 100644
index 0000000..7bb8425
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/combat-unit-edit.xml
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+
+Dane jednostki
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/combat-units.xml b/2013/daemon/tpl/scyzoryk/combat-units.xml
new file mode 100644
index 0000000..f0ecf40
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/combat-units.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+Nowa jednostka
+ID:
+Nazwa:
+dodaj
+
+
+
+
+
+ID:
+Nazwa:
+szukaj
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/config-generator.xml b/2013/daemon/tpl/scyzoryk/config-generator.xml
new file mode 100644
index 0000000..c63f592
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/config-generator.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/config.xml b/2013/daemon/tpl/scyzoryk/config.xml
new file mode 100644
index 0000000..f63bc06
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/config.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/event-edit.xml b/2013/daemon/tpl/scyzoryk/event-edit.xml
new file mode 100644
index 0000000..5054e25
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/event-edit.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+Dane zdarzenia
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/events.xml b/2013/daemon/tpl/scyzoryk/events.xml
new file mode 100644
index 0000000..78b5474
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/events.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+Nowe zdarzenie specjalne
+ID:
+Nazwa:
+dodaj
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/faction-edit.xml b/2013/daemon/tpl/scyzoryk/faction-edit.xml
new file mode 100644
index 0000000..bc2f8f7
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/faction-edit.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+Dane frakcji
+
+
+
+
+Rangi
+
+
+
+Nowa ranga
+Numer:
+Wymagane punkty:
+dodaj
+
+ Tytuł:
+ <brak>
+ <${item/title_id}> ${item/name_f} / ${item/name_m} / ${item/name_n}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/factions.xml b/2013/daemon/tpl/scyzoryk/factions.xml
new file mode 100644
index 0000000..7fd2f91
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/factions.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+Nowa frakcja
+ID:
+Nazwa:
+dodaj
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/generator.xml b/2013/daemon/tpl/scyzoryk/generator.xml
new file mode 100644
index 0000000..6c27f64
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/generator.xml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+Generator
+
+
+
+
+
+
+
+Mieszator
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/index.xml b/2013/daemon/tpl/scyzoryk/index.xml
new file mode 100644
index 0000000..d776cc0
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/index.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+Ciekawostki
+Wygrzebane z archiwalnego kodu...
+
+
+
+
+ Ile kasy za przedmiot (od poziomu potwora)
+
+ poziom cena
+
+ ${repeat/row/key} ${row} zł
+
+
+
+
+
+ Ile bonusu powinien mieć przedmiot za potwora
+
+ bonus % bonus stały cena
+
+ ${row/bonusp} ${row/bonusc} ${row/price} zł
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/item-edit.xml b/2013/daemon/tpl/scyzoryk/item-edit.xml
new file mode 100644
index 0000000..c8b4bb5
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/item-edit.xml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+Dane przedmiotu
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/item-template-edit.xml b/2013/daemon/tpl/scyzoryk/item-template-edit.xml
new file mode 100644
index 0000000..26af54e
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/item-template-edit.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+Dane szablonu
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/item-templates.xml b/2013/daemon/tpl/scyzoryk/item-templates.xml
new file mode 100644
index 0000000..a1371e8
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/item-templates.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+Nowy szablon
+ID:
+Nazwa:
+dodaj
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/items.xml b/2013/daemon/tpl/scyzoryk/items.xml
new file mode 100644
index 0000000..3aded00
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/items.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+Nowy przedmiot
+ID:
+Nazwa:
+Typ:
+
+
+ ${item}
+
+
+dodaj
+
+
+
+
+
+ID:
+Nazwa:
+Typ:
+
+ <wszystkie>
+ ${item}
+
+
+szukaj
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/location-edit.xml b/2013/daemon/tpl/scyzoryk/location-edit.xml
new file mode 100644
index 0000000..f6e63e6
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/location-edit.xml
@@ -0,0 +1,259 @@
+
+
+
+
+
+
+
+
+Dane lokacji
+
+
+
+
+Wędrówka
+
+
+
+Nowa ścieżka
+ID celu:
+
+ dodaj także odwrotną
+dodaj
+Może nadpisać istniejące ścieżki.
+
+
+
+
+
+
+
+Potwory
+
+
+
+Nowy potwór
+ID:
+
+dodaj
+
+
+
+
+
+
+
+Zdarzenia
+
+
+
+Nowe zdarzenie specjalne
+Zdarzenie:
+
+ ${item/name}
+
+dodaj
+
+
+
+
+
+
+
+Usługi
+
+
+
+Nowa usługa
+Usługa:
+
+ <${item/type}> ${item/name}
+
+dodaj
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/location-event-edit.xml b/2013/daemon/tpl/scyzoryk/location-event-edit.xml
new file mode 100644
index 0000000..8c2219a
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/location-event-edit.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+Dane zdarzenia specjalnego
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/location-monster-edit.xml b/2013/daemon/tpl/scyzoryk/location-monster-edit.xml
new file mode 100644
index 0000000..2c6ac4b
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/location-monster-edit.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+Dane zdarzenia-potwora
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/location-path-edit.xml b/2013/daemon/tpl/scyzoryk/location-path-edit.xml
new file mode 100644
index 0000000..46408f4
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/location-path-edit.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+Dane ścieżki
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/locations.xml b/2013/daemon/tpl/scyzoryk/locations.xml
new file mode 100644
index 0000000..e56db48
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/locations.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+Nowa lokacja
+ID:
+Nazwa:
+Region:
+
+
+ ${item/name}
+
+
+dodaj
+Nazwa Otchłań Narodzin jest zarezerwowana dla strony respawnu.
+
+
+
+
+
+ID:
+Nazwa:
+Region:
+
+ <wszystkie>
+ ${item/name}
+
+
+szukaj
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/macros.xml b/2013/daemon/tpl/scyzoryk/macros.xml
new file mode 100644
index 0000000..3aa9e0a
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/macros.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/map-edit.xml b/2013/daemon/tpl/scyzoryk/map-edit.xml
new file mode 100644
index 0000000..0c8df76
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/map-edit.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+Dane mapu
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/maps.xml b/2013/daemon/tpl/scyzoryk/maps.xml
new file mode 100644
index 0000000..478792f
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/maps.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+Nowa mapa
+ID:
+Nazwa:
+dodaj
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/monster-drop-edit.xml b/2013/daemon/tpl/scyzoryk/monster-drop-edit.xml
new file mode 100644
index 0000000..a25b16e
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/monster-drop-edit.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+Dane dropu
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/monster-edit.xml b/2013/daemon/tpl/scyzoryk/monster-edit.xml
new file mode 100644
index 0000000..485b0a4
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/monster-edit.xml
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+Dane potwora
+
+
+
+
+Upuszczane przedmioty
+
+
+
+Nowy przedmiot
+
+ID:
+
+dodaj
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/monsters.xml b/2013/daemon/tpl/scyzoryk/monsters.xml
new file mode 100644
index 0000000..1ba3cb9
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/monsters.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+Nowy potwór
+ID:
+Nazwa:
+dodaj
+
+
+
+
+
+ID:
+Nazwa:
+Klasa:
+
+ <wszystkie>
+ ${item}
+
+
+szukaj
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/news.xml b/2013/daemon/tpl/scyzoryk/news.xml
new file mode 100644
index 0000000..6861fc3
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/news.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+${item/title}
+
+
+ Dodany: ${item/published} Ostatnio zmieniany: ${item/updated} Autor: ${item/author}
+
+ usuń
+
+
+${item/content}
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/player-edit.xml b/2013/daemon/tpl/scyzoryk/player-edit.xml
new file mode 100644
index 0000000..2660413
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/player-edit.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+Dane gracza
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/players.xml b/2013/daemon/tpl/scyzoryk/players.xml
new file mode 100644
index 0000000..3110f27
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/players.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+ ID
+ Login
+ Rejestracja
+ Ostatni login
+ Prawa
+
+ Postacie
+
+
+
+
+ ${item/player_id}
+ ${item/login}
+ ${item/date_created}
+ ${item/last_login}
+ ${item/roles}
+ edytuj
+ ${x}
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/region-edit.xml b/2013/daemon/tpl/scyzoryk/region-edit.xml
new file mode 100644
index 0000000..b30b89d
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/region-edit.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+Dane regionu
+
+
+
+
+Lokacje
+
+
+
+
+
+
+ pokaż lokacje
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/regions.xml b/2013/daemon/tpl/scyzoryk/regions.xml
new file mode 100644
index 0000000..1797eca
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/regions.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+Nowy region
+ID:
+Nazwa:
+dodaj
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/reset.xml b/2013/daemon/tpl/scyzoryk/reset.xml
new file mode 100644
index 0000000..5b161f5
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/reset.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+Armageddon
+
+postacie
+Kasuje większość statów postaci, zachowuje jedynie imiona, płeć itp.
+
+historia
+Czyści pocztę, ogłoszenia oraz historię przeliczeń i pojedynków.
+
+
+
+
+
+
+
+Przeliczenia statów
+
+Wszystkie operacje są czasochłonne, nie odpalać zbyt często...
+
+przedmioty
+Masowo waliduje przedmioty i uaktualnia wycenę.
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/search.xml b/2013/daemon/tpl/scyzoryk/search.xml
new file mode 100644
index 0000000..64af14e
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/search.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+ID:
+Nazwa:
+szukaj
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/service-edit.xml b/2013/daemon/tpl/scyzoryk/service-edit.xml
new file mode 100644
index 0000000..4ca8bc7
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/service-edit.xml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+Dane usługi
+
+
+
+
+Oferta sklepu
+
+
+
+Nowy przedmiot
+
+ID:
+
+dodaj
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/services.xml b/2013/daemon/tpl/scyzoryk/services.xml
new file mode 100644
index 0000000..e38c996
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/services.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+Nowa usługa
+ID:
+Nazwa:
+dodaj
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/title-edit.xml b/2013/daemon/tpl/scyzoryk/title-edit.xml
new file mode 100644
index 0000000..20f26eb
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/title-edit.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+Dane tytułu
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/scyzoryk/titles.xml b/2013/daemon/tpl/scyzoryk/titles.xml
new file mode 100644
index 0000000..eb83a24
--- /dev/null
+++ b/2013/daemon/tpl/scyzoryk/titles.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+Nowy tytuł
+ID:
+dodaj
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/service.xml b/2013/daemon/tpl/service.xml
new file mode 100644
index 0000000..5ab8bf9
--- /dev/null
+++ b/2013/daemon/tpl/service.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/service/bank.xml b/2013/daemon/tpl/service/bank.xml
new file mode 100644
index 0000000..f1cb69a
--- /dev/null
+++ b/2013/daemon/tpl/service/bank.xml
@@ -0,0 +1,47 @@
+
+
+
+Schowek
+Twój schowek jest pusty.
+
+
+
+
+ ${row/item/name} (przypisany)
+
+
+ wyjmij
+
+
+
+
+
+Plecak
+Twój schowek jest pełny.
+
+ Nie masz co schować.
+
+
+
+
+ ${row/item/name} (przypisany)
+
+
+ schowaj
+
+
+
+
diff --git a/2013/daemon/tpl/service/healer.xml b/2013/daemon/tpl/service/healer.xml
new file mode 100644
index 0000000..2fd0c5c
--- /dev/null
+++ b/2013/daemon/tpl/service/healer.xml
@@ -0,0 +1,30 @@
+
+Leczenie
+
+
+ W sakiewce masz ${characterData/gold_purse} sztuk złota.
+
+
+ Na koncie masz ${characterData/gold_bank} sztuk złota,
+ w sakiewce ${characterData/gold_purse} sztuk złota.
+ Możesz zapłacić przelewem.
+
+
+
+ opłać leczenie
+ ${deltaHealthMin}-${deltaHealthMax} zdrowia i ${deltaManaMin}-${deltaManaMax} many za każdą sztukę złota
+
+
+
+
+
+Odpoczynek
+
+
+ Zdrowie: ${characterData/health} / ${characterData/health_max}
+ Mana: ${characterData/mana} / ${characterData/mana_max}
+ odpocznij 1 turę
+ Bezpieczniej niż na zewnątrz...
+
+
+
diff --git a/2013/daemon/tpl/service/shop.xml b/2013/daemon/tpl/service/shop.xml
new file mode 100644
index 0000000..4a278ec
--- /dev/null
+++ b/2013/daemon/tpl/service/shop.xml
@@ -0,0 +1,86 @@
+
+ ${shopName}
+
+
+ W sakiewce masz ${goldPurse} sztuk złota.
+
+
+ Na koncie masz ${goldBank} sztuk złota,
+ w sakiewce ${goldPurse} sztuk złota.
+ Możesz zapłacić przelewem.
+
+
+
+
+ Sprzedaż
+
+
+
+
+ [${row/_price} zł] ${row/item/name}
+ (przypisany)
+ (zident.)
+
+
+
+
+ [${row/_price} zł] ${row/item/name}
+ (przypisany)
+ (zident.)
+
+
+
+
+ [${row/_price} zł] ${row/item/name}
+ (przypisany)
+ (zident.)
+
+
+
+
+ sprzedaj
+ Możesz wybrać kilka przedmiotów na raz (SHIFT,CTRL).
+
+
+
+
+${group/name}
+
+
+
diff --git a/2013/daemon/tpl/service/temple.xml b/2013/daemon/tpl/service/temple.xml
new file mode 100644
index 0000000..819fd69
--- /dev/null
+++ b/2013/daemon/tpl/service/temple.xml
@@ -0,0 +1,83 @@
+
+ Zdrowie: ${characterData/health} / ${characterData/health_max} ,
+ mana: ${characterData/mana} / ${characterData/mana_max} .
+
+ W sakiewce masz ${characterData/gold_purse} sztuk złota.
+
+
+ Na koncie masz ${characterData/gold_bank} sztuk złota,
+ w sakiewce ${characterData/gold_purse} sztuk złota.
+ Możesz zapłacić przelewem.
+
+
+
+
+Przypisanie
+
+
+
+
+
+ [${row/value} zł] ${row/name}
+ (zident.)
+
+
+
+
+ [${row/value} zł] ${row/name}
+ (zident.)
+
+
+
+
+ [${row/value} zł] ${row/name}
+ (zident.)
+
+
+
+
+ przypisz
+ Połącz przedmiot ze swoją duszą aby nie tracić go po śmierci...
+
+
+
+
+
+
+
+
+Obecna misja to ${lastMission/_name} ,
+otrzymana w świątyni ???
+w przeliczeniu nr ${lastMission/rollover_id} .
+
+porzuć misję
+Nie dostaniesz nowej misji w tym samym przeliczeniu.
+
+
diff --git a/2013/daemon/tpl/spell/scancharacter.xml b/2013/daemon/tpl/spell/scancharacter.xml
new file mode 100644
index 0000000..b0aa894
--- /dev/null
+++ b/2013/daemon/tpl/spell/scancharacter.xml
@@ -0,0 +1,33 @@
+
+
+ Imię postaci:
+ rzuć zaklęcie (${cost} MP)
+
+
+
+
+${result/char/name}
+
+
+ Zdrowie
+ ${result/cdata/health} / ${result/cdata/health_max}
+
+
+ Mana
+ ${result/cdata/mana} / ${result/cdata/mana_max}
+
+
+ Sakiewka
+ ${result/cdata/gold_purse} złota
+
+
+ Lokacja
+ ${result/locationName}
+
+
+ Ekwipunek
+ brak
+ ${result/equipment}
+
+
+
diff --git a/2013/daemon/tpl/spell/scanitem.xml b/2013/daemon/tpl/spell/scanitem.xml
new file mode 100644
index 0000000..0c890ca
--- /dev/null
+++ b/2013/daemon/tpl/spell/scanitem.xml
@@ -0,0 +1,39 @@
+
+
+ Nazwa przedmiotu:
+ rzuć zaklęcie (${cost} MP)
+
+
+
+
+${result/item/name}
+
+
+ Typ
+ ${result/typeName}
+
+
+ Obrażenia
+ ${result/damageType}
+
+
+ Wartość
+ ${result/item/value} złota
+
+
+ Opis
+ ${result/item/description}
+
+
+Występowanie
+
+
+ Potwory
+ brak
+
+
+ Sklepy
+ brak
+
+
+
diff --git a/2013/daemon/tpl/spell/scanmonster.xml b/2013/daemon/tpl/spell/scanmonster.xml
new file mode 100644
index 0000000..2f9e4af
--- /dev/null
+++ b/2013/daemon/tpl/spell/scanmonster.xml
@@ -0,0 +1,46 @@
+
+
+ Nazwa potwora:
+ rzuć zaklęcie (${cost} MP)
+
+
+
+
+
+${result/monster/name}
+
+
+ Klasa
+ ${result/className}
+
+
+ Poziom
+ ${result/monster/level}
+
+
+ Zdrowie
+ ${result/unit/health_max}
+
+
+
+ Złoto
+ ${result/monster/gold}
+
+
+ Szansa na przedmiot
+ ${result/monster/chance1} / ${result/monster/chance2}
+
+
+ Tytuł
+ ${result/title/name_f} / ${result/title/name_m} / ${result/title/name_n}
+ brak
+
+
+
+Przedmioty
+brak
+${result/items}.
+Występowanie
+brak
+${result/locations}.
+
diff --git a/2013/daemon/tpl/spell/scout.xml b/2013/daemon/tpl/spell/scout.xml
new file mode 100644
index 0000000..be969ab
--- /dev/null
+++ b/2013/daemon/tpl/spell/scout.xml
@@ -0,0 +1,25 @@
+
+
+
+ Lokacja
+ Szansa na zdarzenie
+ Zdarzenia
+
+
+
+
+ ${location/name}
+ ${location/chance1} / ${location/chance2}
+
+
+ ${x}
+ ${x}
+
+
+
+
diff --git a/2013/daemon/tpl/stats-battle.xml b/2013/daemon/tpl/stats-battle.xml
new file mode 100644
index 0000000..4c0e7bf
--- /dev/null
+++ b/2013/daemon/tpl/stats-battle.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+Wybrany log nie istnieje.
+
+
+ Lokacja: ${battle/location_name}
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/stats-battles.xml b/2013/daemon/tpl/stats-battles.xml
new file mode 100644
index 0000000..b63d227
--- /dev/null
+++ b/2013/daemon/tpl/stats-battles.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+Nr
+Prz.
+Lokacja
+Typ walki
+Log walki
+
+
+
+${item/battle_id}
+${item/rollover_id}
+${item/location_name}
+${item/type}
+pokaż
+
+
+
+
+następna strona...
+
+
+
+
diff --git a/2013/daemon/tpl/stats-character.xml b/2013/daemon/tpl/stats-character.xml
new file mode 100644
index 0000000..6002c87
--- /dev/null
+++ b/2013/daemon/tpl/stats-character.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+Wybrana postać nie istnieje.
+
+
+
+
+
+
+ Gracz ${character/player_name}
+ Postać ${character/name}
+ Data narodzin ${character/date_created}
+ Płeć ${genderName}
+ Poziom ${character/level}
+ Doświadczenie ${character/xp_used}
+
+ Frakcja
+ brak
+ ${character/faction_name}
+
+
+ Ranga
+ ${character/rank_name} (${character/rank_id})
+
+
+ Klan
+ brak
+
+ ${character/clan_name}
+
+
+ Pojedynki pokaż pojedynki postaci
+ Kontakt wyślij wiadomość
+ Tytuły ${character/titles}
+ Motto ${character/quote}
+
+
+
+ Statystyki
+ Wykonane misje ${s/missions}
+ Wygrane pojedynki ${s/duel_wins}
+ Przegrane pojedynki ${s/duel_losses}
+ Pokonane słabe potwory ${s/kills_mob1}
+ Pokonane średnie potwory ${s/kills_mob2}
+ Pokonane silne potwory ${s/kills_mob3}
+ Pokonane potwory epickie ${s/kills_mob4}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/stats-characters.xml b/2013/daemon/tpl/stats-characters.xml
new file mode 100644
index 0000000..0b86d37
--- /dev/null
+++ b/2013/daemon/tpl/stats-characters.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+następna strona...
+
+
+
+
diff --git a/2013/daemon/tpl/stats-clan.xml b/2013/daemon/tpl/stats-clan.xml
new file mode 100644
index 0000000..f3a8d28
--- /dev/null
+++ b/2013/daemon/tpl/stats-clan.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+Wybrany klan nie istnieje.
+
+
+
+
+
+ ID ${clan/clan_id}
+ Nazwa ${clan/name}
+ Przywódca ${clan/leader_name}
+ Data założenia ${clan/date_created}
+ Liczebność ${clan/members}
+
+ Postacie
+ pokaż listę
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/stats-clans.xml b/2013/daemon/tpl/stats-clans.xml
new file mode 100644
index 0000000..02f037b
--- /dev/null
+++ b/2013/daemon/tpl/stats-clans.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+Tag
+Nazwa
+Przywódca
+Wielkość
+Data założenia
+
+
+
+${item/clan_id}
+${item/name}
+brak
+${item/leader_name}
+${item/members}
+${item/date_created}
+
+
+
+
+następna strona...
+
+
+
+
diff --git a/2013/daemon/tpl/stats-duel.xml b/2013/daemon/tpl/stats-duel.xml
new file mode 100644
index 0000000..451f035
--- /dev/null
+++ b/2013/daemon/tpl/stats-duel.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+Wybrany log jest niedostępny.
+
+
+ ${duel/attacker_name} vs ${duel/defender_name}
+
+
+
+
+
+
diff --git a/2013/daemon/tpl/stats-duels.xml b/2013/daemon/tpl/stats-duels.xml
new file mode 100644
index 0000000..4b684c7
--- /dev/null
+++ b/2013/daemon/tpl/stats-duels.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+Nr
+Data pojedynku
+Prz.
+Ataker
+Obrońca
+Typ walki
+Zwycięzca
+Log walki
+
+
+
+${item/duel_id}
+${item/date_added}
+${item/rollover_id}
+postać usunięta
+${item/attacker_name}
+postać usunięta
+${item/defender_name}
+${item/type}
+${item/winner}
+
+ niedostępny
+ pokaż
+
+
+
+
+
+następna strona...
+
+
+
+
diff --git a/2013/daemon/tpl/stats.xml b/2013/daemon/tpl/stats.xml
new file mode 100644
index 0000000..0290561
--- /dev/null
+++ b/2013/daemon/tpl/stats.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+Logowanie dostępne wyłączone
+Rejestracja dostępna wyłączona
+Przeliczenia włączone wyłączone
+Limit tur ${turnLimit}
+Przyrost tur ${turnDelta} dziennie
+Oblegane caerny brak
+
+
+
+Frakcje
+
+ ID
+ Nazwa
+ Siła
+ Mnożnik
+ Członkowie
+ Posiadane caerny
+
+
+ ${repeat/row/key}
+ ${row/name}
+ ${row/power}
+ ${row/powerMult}%
+ ${row/chars}
+ brak
+
+
+
+
+Ostatnie przeliczenia
+
+ Nr
+ Data
+ Gracze
+ Postacie
+ Klany
+ Bitwy
+
+
+ ${row/rollover_id}
+ ${row/date_added}
+ ${row/players_total}
+ ${row/characters_total}
+ ${row/clans_total}
+
+
+ ${x}
+
+
+
+ brak
+
+
+
+
+
+
diff --git a/2021/nexus-archive/browser-extension/.editorconfig b/2021/nexus-archive/browser-extension/.editorconfig
new file mode 100644
index 0000000..998f5ad
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/.editorconfig
@@ -0,0 +1,19 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_size = 2
+indent_style = space
+insert_final_newline = true
+max_line_length = 80
+tab_width = 2
+
+[*.json]
+max_line_length = unset
+
+[options/index.html]
+max_line_length = unset
+
+[src/*.js]
+max_line_length = unset
diff --git a/2021/nexus-archive/browser-extension/.eslintrc.json b/2021/nexus-archive/browser-extension/.eslintrc.json
new file mode 100644
index 0000000..dd23b73
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/.eslintrc.json
@@ -0,0 +1,45 @@
+{
+ "env": {
+ "browser": true,
+ "webextensions": true,
+ "es2021": true
+ },
+ "extends": "eslint:recommended",
+ "parserOptions": {
+ "ecmaVersion": 12,
+ "sourceType": "script"
+ },
+ "root": true,
+ "parser": "@babel/eslint-parser",
+ "rules": {
+ "curly": ["error", "all"],
+ "eqeqeq": ["error", "always"],
+ "indent": [
+ "error",
+ 2
+ ],
+ "linebreak-style": [
+ "error",
+ "unix"
+ ],
+ "quotes": [
+ "error",
+ "single"
+ ],
+ "semi": [
+ "error",
+ "never",
+ {
+ "beforeStatementContinuationChars": "never"
+ }
+ ],
+ "strict": [
+ "error",
+ "global"
+ ],
+ "yoda": [
+ "error",
+ "always"
+ ]
+ }
+}
diff --git a/2021/nexus-archive/browser-extension/.gitattributes b/2021/nexus-archive/browser-extension/.gitattributes
new file mode 100644
index 0000000..a8cca15
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/.gitattributes
@@ -0,0 +1,9 @@
+* text=auto
+*.css text eol=lf
+*.editorconfig text eol=lf
+*.html text eol=lf
+*.js text eol=lf
+*.json text eol=lf
+*.md text eol=lf
+*.txt text eol=lf
+*.png binary
diff --git a/2021/nexus-archive/browser-extension/.gitignore b/2021/nexus-archive/browser-extension/.gitignore
new file mode 100644
index 0000000..4a82283
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/.gitignore
@@ -0,0 +1,3 @@
+/node_modules
+/web-ext-artifacts
+/.web-extension-id
diff --git a/2021/nexus-archive/browser-extension/CHANGELOG.md b/2021/nexus-archive/browser-extension/CHANGELOG.md
new file mode 100644
index 0000000..b880982
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/CHANGELOG.md
@@ -0,0 +1,13 @@
+# Version 1.1.1
+
+- Fix version definition in manifest file
+
+# Version 1.1.0
+
+- Removed unnecessary entry for "unlimited storage" from required permissions
+- Removed unnecessary properties from submitted data
+- Removed some forgotten debugging code
+
+# Version 1.0.0
+
+- Created basic extension to automatically submit network traffic to the website
diff --git a/2021/nexus-archive/browser-extension/LICENSE.txt b/2021/nexus-archive/browser-extension/LICENSE.txt
new file mode 100644
index 0000000..4153cd3
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/LICENSE.txt
@@ -0,0 +1,287 @@
+ EUROPEAN UNION PUBLIC LICENCE v. 1.2
+ EUPL © the European Union 2007, 2016
+
+This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined
+below) which is provided under the terms of this Licence. Any use of the Work,
+other than as authorised under this Licence is prohibited (to the extent such
+use is covered by a right of the copyright holder of the Work).
+
+The Work is provided under the terms of this Licence when the Licensor (as
+defined below) has placed the following notice immediately following the
+copyright notice for the Work:
+
+ Licensed under the EUPL
+
+or has expressed by any other means his willingness to license under the EUPL.
+
+1. Definitions
+
+In this Licence, the following terms have the following meaning:
+
+- ‘The Licence’: this Licence.
+
+- ‘The Original Work’: the work or software distributed or communicated by the
+ Licensor under this Licence, available as Source Code and also as Executable
+ Code as the case may be.
+
+- ‘Derivative Works’: the works or software that could be created by the
+ Licensee, based upon the Original Work or modifications thereof. This Licence
+ does not define the extent of modification or dependence on the Original Work
+ required in order to classify a work as a Derivative Work; this extent is
+ determined by copyright law applicable in the country mentioned in Article 15.
+
+- ‘The Work’: the Original Work or its Derivative Works.
+
+- ‘The Source Code’: the human-readable form of the Work which is the most
+ convenient for people to study and modify.
+
+- ‘The Executable Code’: any code which has generally been compiled and which is
+ meant to be interpreted by a computer as a program.
+
+- ‘The Licensor’: the natural or legal person that distributes or communicates
+ the Work under the Licence.
+
+- ‘Contributor(s)’: any natural or legal person who modifies the Work under the
+ Licence, or otherwise contributes to the creation of a Derivative Work.
+
+- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of
+ the Work under the terms of the Licence.
+
+- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending,
+ renting, distributing, communicating, transmitting, or otherwise making
+ available, online or offline, copies of the Work or providing access to its
+ essential functionalities at the disposal of any other natural or legal
+ person.
+
+2. Scope of the rights granted by the Licence
+
+The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
+sublicensable licence to do the following, for the duration of copyright vested
+in the Original Work:
+
+- use the Work in any circumstance and for all usage,
+- reproduce the Work,
+- modify the Work, and make Derivative Works based upon the Work,
+- communicate to the public, including the right to make available or display
+ the Work or copies thereof to the public and perform publicly, as the case may
+ be, the Work,
+- distribute the Work or copies thereof,
+- lend and rent the Work or copies thereof,
+- sublicense rights in the Work or copies thereof.
+
+Those rights can be exercised on any media, supports and formats, whether now
+known or later invented, as far as the applicable law permits so.
+
+In the countries where moral rights apply, the Licensor waives his right to
+exercise his moral right to the extent allowed by law in order to make effective
+the licence of the economic rights here above listed.
+
+The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to
+any patents held by the Licensor, to the extent necessary to make use of the
+rights granted on the Work under this Licence.
+
+3. Communication of the Source Code
+
+The Licensor may provide the Work either in its Source Code form, or as
+Executable Code. If the Work is provided as Executable Code, the Licensor
+provides in addition a machine-readable copy of the Source Code of the Work
+along with each copy of the Work that the Licensor distributes or indicates, in
+a notice following the copyright notice attached to the Work, a repository where
+the Source Code is easily and freely accessible for as long as the Licensor
+continues to distribute or communicate the Work.
+
+4. Limitations on copyright
+
+Nothing in this Licence is intended to deprive the Licensee of the benefits from
+any exception or limitation to the exclusive rights of the rights owners in the
+Work, of the exhaustion of those rights or of other applicable limitations
+thereto.
+
+5. Obligations of the Licensee
+
+The grant of the rights mentioned above is subject to some restrictions and
+obligations imposed on the Licensee. Those obligations are the following:
+
+Attribution right: The Licensee shall keep intact all copyright, patent or
+trademarks notices and all notices that refer to the Licence and to the
+disclaimer of warranties. The Licensee must include a copy of such notices and a
+copy of the Licence with every copy of the Work he/she distributes or
+communicates. The Licensee must cause any Derivative Work to carry prominent
+notices stating that the Work has been modified and the date of modification.
+
+Copyleft clause: If the Licensee distributes or communicates copies of the
+Original Works or Derivative Works, this Distribution or Communication will be
+done under the terms of this Licence or of a later version of this Licence
+unless the Original Work is expressly distributed only under this version of the
+Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee
+(becoming Licensor) cannot offer or impose any additional terms or conditions on
+the Work or Derivative Work that alter or restrict the terms of the Licence.
+
+Compatibility clause: If the Licensee Distributes or Communicates Derivative
+Works or copies thereof based upon both the Work and another work licensed under
+a Compatible Licence, this Distribution or Communication can be done under the
+terms of this Compatible Licence. For the sake of this clause, ‘Compatible
+Licence’ refers to the licences listed in the appendix attached to this Licence.
+Should the Licensee's obligations under the Compatible Licence conflict with
+his/her obligations under this Licence, the obligations of the Compatible
+Licence shall prevail.
+
+Provision of Source Code: When distributing or communicating copies of the Work,
+the Licensee will provide a machine-readable copy of the Source Code or indicate
+a repository where this Source will be easily and freely available for as long
+as the Licensee continues to distribute or communicate the Work.
+
+Legal Protection: This Licence does not grant permission to use the trade names,
+trademarks, service marks, or names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the copyright notice.
+
+6. Chain of Authorship
+
+The original Licensor warrants that the copyright in the Original Work granted
+hereunder is owned by him/her or licensed to him/her and that he/she has the
+power and authority to grant the Licence.
+
+Each Contributor warrants that the copyright in the modifications he/she brings
+to the Work are owned by him/her or licensed to him/her and that he/she has the
+power and authority to grant the Licence.
+
+Each time You accept the Licence, the original Licensor and subsequent
+Contributors grant You a licence to their contributions to the Work, under the
+terms of this Licence.
+
+7. Disclaimer of Warranty
+
+The Work is a work in progress, which is continuously improved by numerous
+Contributors. It is not a finished work and may therefore contain defects or
+‘bugs’ inherent to this type of development.
+
+For the above reason, the Work is provided under the Licence on an ‘as is’ basis
+and without warranties of any kind concerning the Work, including without
+limitation merchantability, fitness for a particular purpose, absence of defects
+or errors, accuracy, non-infringement of intellectual property rights other than
+copyright as stated in Article 6 of this Licence.
+
+This disclaimer of warranty is an essential part of the Licence and a condition
+for the grant of any rights to the Work.
+
+8. Disclaimer of Liability
+
+Except in the cases of wilful misconduct or damages directly caused to natural
+persons, the Licensor will in no event be liable for any direct or indirect,
+material or moral, damages of any kind, arising out of the Licence or of the use
+of the Work, including without limitation, damages for loss of goodwill, work
+stoppage, computer failure or malfunction, loss of data or any commercial
+damage, even if the Licensor has been advised of the possibility of such damage.
+However, the Licensor will be liable under statutory product liability laws as
+far such laws apply to the Work.
+
+9. Additional agreements
+
+While distributing the Work, You may choose to conclude an additional agreement,
+defining obligations or services consistent with this Licence. However, if
+accepting obligations, You may act only on your own behalf and on your sole
+responsibility, not on behalf of the original Licensor or any other Contributor,
+and only if You agree to indemnify, defend, and hold each Contributor harmless
+for any liability incurred by, or claims asserted against such Contributor by
+the fact You have accepted any warranty or additional liability.
+
+10. Acceptance of the Licence
+
+The provisions of this Licence can be accepted by clicking on an icon ‘I agree’
+placed under the bottom of a window displaying the text of this Licence or by
+affirming consent in any other similar way, in accordance with the rules of
+applicable law. Clicking on that icon indicates your clear and irrevocable
+acceptance of this Licence and all of its terms and conditions.
+
+Similarly, you irrevocably accept this Licence and all of its terms and
+conditions by exercising any rights granted to You by Article 2 of this Licence,
+such as the use of the Work, the creation by You of a Derivative Work or the
+Distribution or Communication by You of the Work or copies thereof.
+
+11. Information to the public
+
+In case of any Distribution or Communication of the Work by means of electronic
+communication by You (for example, by offering to download the Work from a
+remote location) the distribution channel or media (for example, a website) must
+at least provide to the public the information requested by the applicable law
+regarding the Licensor, the Licence and the way it may be accessible, concluded,
+stored and reproduced by the Licensee.
+
+12. Termination of the Licence
+
+The Licence and the rights granted hereunder will terminate automatically upon
+any breach by the Licensee of the terms of the Licence.
+
+Such a termination will not terminate the licences of any person who has
+received the Work from the Licensee under the Licence, provided such persons
+remain in full compliance with the Licence.
+
+13. Miscellaneous
+
+Without prejudice of Article 9 above, the Licence represents the complete
+agreement between the Parties as to the Work.
+
+If any provision of the Licence is invalid or unenforceable under applicable
+law, this will not affect the validity or enforceability of the Licence as a
+whole. Such provision will be construed or reformed so as necessary to make it
+valid and enforceable.
+
+The European Commission may publish other linguistic versions or new versions of
+this Licence or updated versions of the Appendix, so far this is required and
+reasonable, without reducing the scope of the rights granted by the Licence. New
+versions of the Licence will be published with a unique version number.
+
+All linguistic versions of this Licence, approved by the European Commission,
+have identical value. Parties can take advantage of the linguistic version of
+their choice.
+
+14. Jurisdiction
+
+Without prejudice to specific agreement between parties,
+
+- any litigation resulting from the interpretation of this License, arising
+ between the European Union institutions, bodies, offices or agencies, as a
+ Licensor, and any Licensee, will be subject to the jurisdiction of the Court
+ of Justice of the European Union, as laid down in article 272 of the Treaty on
+ the Functioning of the European Union,
+
+- any litigation arising between other parties and resulting from the
+ interpretation of this License, will be subject to the exclusive jurisdiction
+ of the competent court where the Licensor resides or conducts its primary
+ business.
+
+15. Applicable Law
+
+Without prejudice to specific agreement between parties,
+
+- this Licence shall be governed by the law of the European Union Member State
+ where the Licensor has his seat, resides or has his registered office,
+
+- this licence shall be governed by Belgian law if the Licensor has no seat,
+ residence or registered office inside a European Union Member State.
+
+Appendix
+
+‘Compatible Licences’ according to Article 5 EUPL are:
+
+- GNU General Public License (GPL) v. 2, v. 3
+- GNU Affero General Public License (AGPL) v. 3
+- Open Software License (OSL) v. 2.1, v. 3.0
+- Eclipse Public License (EPL) v. 1.0
+- CeCILL v. 2.0, v. 2.1
+- Mozilla Public Licence (MPL) v. 2
+- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
+- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
+ works other than software
+- European Union Public Licence (EUPL) v. 1.1, v. 1.2
+- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong
+ Reciprocity (LiLiQ-R+).
+
+The European Commission may update this Appendix to later versions of the above
+licences without producing a new version of the EUPL, as long as they provide
+the rights granted in Article 2 of this Licence and protect the covered Source
+Code from exclusive appropriation.
+
+All other changes or additions to this Appendix require the production of a new
+EUPL version.
diff --git a/2021/nexus-archive/browser-extension/README.md b/2021/nexus-archive/browser-extension/README.md
new file mode 100644
index 0000000..476e03b
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/README.md
@@ -0,0 +1,21 @@
+# Nexus Archive browser extension
+
+A simple browser extension to submit network traffic to the Nexus Archive
+website.
+
+## Licence
+
+This project is licensed under [European Union Public Licence (EUPL)][EUPL].
+
+For convenience an English text of the licence is included
+in [LICENSE.txt](LICENSE.txt) file.
+
+## Changelog
+
+You can read changelog in a [separate file][CHANGELOG].
+
+[EUPL]:
+https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+
+[CHANGELOG]:
+CHANGELOG.md
diff --git a/2021/nexus-archive/browser-extension/icons/icon.png b/2021/nexus-archive/browser-extension/icons/icon.png
new file mode 100644
index 0000000..063cfa8
Binary files /dev/null and b/2021/nexus-archive/browser-extension/icons/icon.png differ
diff --git a/2021/nexus-archive/browser-extension/manifest.json b/2021/nexus-archive/browser-extension/manifest.json
new file mode 100644
index 0000000..0c9a7ce
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/manifest.json
@@ -0,0 +1,38 @@
+{
+ "author": "Krzysztof Andrzej Sikorski",
+ "background": {
+ "persistent": true,
+ "scripts": [
+ "src/preferences.js",
+ "src/nexusData.js",
+ "src/nexusDataQueue.js",
+ "src/nexusDataSender.js",
+ "src/webRequestMonitor.js",
+ "src/background.js"
+ ]
+ },
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "nexus-archive-tracker@zerozero.pl"
+ }
+ },
+ "description": "A browser extension to automatically submit Nexus Clash network traffic to the \"Nexus Archive\" website.",
+ "homepage_url": "https://discord.gg/zBVwzD3f8v",
+ "icons": {
+ "64": "icons/icon.png"
+ },
+ "manifest_version": 2,
+ "name": "Nexus Archive Tracker",
+ "options_ui": {
+ "browser_style": true,
+ "page": "options/index.html"
+ },
+ "permissions": [
+ "storage",
+ "webRequest",
+ "webRequestBlocking",
+ "*://*.nexusclash.com/*"
+ ],
+ "short_name": "NA Tracker",
+ "version": "1.1.1"
+}
diff --git a/2021/nexus-archive/browser-extension/options/index.html b/2021/nexus-archive/browser-extension/options/index.html
new file mode 100644
index 0000000..f17ef56
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/options/index.html
@@ -0,0 +1,32 @@
+
+
+
+
+ Options - Nexus Archive Tracker
+
+
+
+
+
+ Tracker options
+
+
+ User access token:
+
+
+
+
+
+ Submit form's URL:
+
+
+
+
+
+ Save
+
+
+
+
+
+
diff --git a/2021/nexus-archive/browser-extension/options/style.css b/2021/nexus-archive/browser-extension/options/style.css
new file mode 100644
index 0000000..e181b68
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/options/style.css
@@ -0,0 +1,3 @@
+body {
+ padding: 0.5em 2ex;
+}
diff --git a/2021/nexus-archive/browser-extension/package-lock.json b/2021/nexus-archive/browser-extension/package-lock.json
new file mode 100644
index 0000000..c684684
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/package-lock.json
@@ -0,0 +1,6466 @@
+{
+ "name": "nexus-archive-browser-extension",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "devDependencies": {
+ "@babel/core": "^7.21.3",
+ "@babel/eslint-parser": "^7.21.3",
+ "eslint": "^8.36.0",
+ "request": "^2.88.2",
+ "web-ext": "^7.5.0"
+ }
+ },
+ "node_modules/@ampproject/remapping": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
+ "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.1.0",
+ "@jridgewell/trace-mapping": "^0.3.9"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
+ "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz",
+ "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.21.3",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz",
+ "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==",
+ "dev": true,
+ "dependencies": {
+ "@ampproject/remapping": "^2.2.0",
+ "@babel/code-frame": "^7.18.6",
+ "@babel/generator": "^7.21.3",
+ "@babel/helper-compilation-targets": "^7.20.7",
+ "@babel/helper-module-transforms": "^7.21.2",
+ "@babel/helpers": "^7.21.0",
+ "@babel/parser": "^7.21.3",
+ "@babel/template": "^7.20.7",
+ "@babel/traverse": "^7.21.3",
+ "@babel/types": "^7.21.3",
+ "convert-source-map": "^1.7.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.2",
+ "semver": "^6.3.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/eslint-parser": {
+ "version": "7.21.3",
+ "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.21.3.tgz",
+ "integrity": "sha512-kfhmPimwo6k4P8zxNs8+T7yR44q1LdpsZdE1NkCsVlfiuTPRfnGgjaF8Qgug9q9Pou17u6wneYF0lDCZJATMFg==",
+ "dev": true,
+ "dependencies": {
+ "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1",
+ "eslint-visitor-keys": "^2.1.0",
+ "semver": "^6.3.0"
+ },
+ "engines": {
+ "node": "^10.13.0 || ^12.13.0 || >=14.0.0"
+ },
+ "peerDependencies": {
+ "@babel/core": ">=7.11.0",
+ "eslint": "^7.5.0 || ^8.0.0"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.21.3",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz",
+ "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.21.3",
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "@jridgewell/trace-mapping": "^0.3.17",
+ "jsesc": "^2.5.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
+ "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/set-array": "^1.0.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.9"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.20.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
+ "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/compat-data": "^7.20.5",
+ "@babel/helper-validator-option": "^7.18.6",
+ "browserslist": "^4.21.3",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-environment-visitor": {
+ "version": "7.18.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
+ "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-function-name": {
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
+ "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.20.7",
+ "@babel/types": "^7.21.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-hoist-variables": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
+ "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
+ "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.21.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz",
+ "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-environment-visitor": "^7.18.9",
+ "@babel/helper-module-imports": "^7.18.6",
+ "@babel/helper-simple-access": "^7.20.2",
+ "@babel/helper-split-export-declaration": "^7.18.6",
+ "@babel/helper-validator-identifier": "^7.19.1",
+ "@babel/template": "^7.20.7",
+ "@babel/traverse": "^7.21.2",
+ "@babel/types": "^7.21.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-simple-access": {
+ "version": "7.20.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
+ "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.20.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-split-export-declaration": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
+ "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.19.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
+ "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.19.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
+ "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz",
+ "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz",
+ "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.20.7",
+ "@babel/traverse": "^7.21.0",
+ "@babel/types": "^7.21.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+ "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.18.6",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.21.3",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz",
+ "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==",
+ "dev": true,
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.20.13",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz",
+ "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==",
+ "dev": true,
+ "dependencies": {
+ "regenerator-runtime": "^0.13.11"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.20.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
+ "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.18.6",
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.21.3",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz",
+ "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.18.6",
+ "@babel/generator": "^7.21.3",
+ "@babel/helper-environment-visitor": "^7.18.9",
+ "@babel/helper-function-name": "^7.21.0",
+ "@babel/helper-hoist-variables": "^7.18.6",
+ "@babel/helper-split-export-declaration": "^7.18.6",
+ "@babel/parser": "^7.21.3",
+ "@babel/types": "^7.21.3",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.21.3",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz",
+ "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.19.4",
+ "@babel/helper-validator-identifier": "^7.19.1",
+ "to-fast-properties": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@devicefarmer/adbkit": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/@devicefarmer/adbkit/-/adbkit-3.2.3.tgz",
+ "integrity": "sha512-wK9rVrabs4QU0oK8Jnwi+HRBEm+s1x/o63kgthUe0y7K1bfcYmgLuQf41/adsj/5enddlSxzkJavl2EwOu+r1g==",
+ "dev": true,
+ "dependencies": {
+ "@devicefarmer/adbkit-logcat": "^2.1.2",
+ "@devicefarmer/adbkit-monkey": "~1.2.0",
+ "bluebird": "~3.7",
+ "commander": "^9.1.0",
+ "debug": "~4.3.1",
+ "node-forge": "^1.3.1",
+ "split": "~1.0.1"
+ },
+ "bin": {
+ "adbkit": "bin/adbkit"
+ },
+ "engines": {
+ "node": ">= 0.10.4"
+ }
+ },
+ "node_modules/@devicefarmer/adbkit-logcat": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@devicefarmer/adbkit-logcat/-/adbkit-logcat-2.1.2.tgz",
+ "integrity": "sha512-G4grpEa5s9s9wCRs8YB9LjFSnz0Os3g3RYIwZSxH3JFfV3aejL5xlu4hHMH4JY+d4oCCwImcEZJcFPY9BEP21w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/@devicefarmer/adbkit-monkey": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@devicefarmer/adbkit-monkey/-/adbkit-monkey-1.2.1.tgz",
+ "integrity": "sha512-ZzZY/b66W2Jd6NHbAhLyDWOEIBWC11VizGFk7Wx7M61JZRz7HR9Cq5P+65RKWUU7u6wgsE8Lmh9nE4Mz+U2eTg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.10.4"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz",
+ "integrity": "sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==",
+ "dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+ "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz",
+ "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==",
+ "dev": true,
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz",
+ "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.5.0",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/globals": {
+ "version": "13.20.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
+ "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "8.36.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz",
+ "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.11.8",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
+ "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+ "dev": true,
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^1.2.1",
+ "debug": "^4.1.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/object-schema": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+ "dev": true
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
+ "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/set-array": "^1.0.0",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/set-array": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.4.14",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+ "dev": true
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.17",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
+ "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "3.1.0",
+ "@jridgewell/sourcemap-codec": "1.4.14"
+ }
+ },
+ "node_modules/@mdn/browser-compat-data": {
+ "version": "5.2.29",
+ "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.2.29.tgz",
+ "integrity": "sha512-bEBrkTWbDAs/PB4IdRg4CtU750oBRytXHK/wC2oIDkgKZqnt76nACSooQQuHF11mK5k43f/IgFUMO5t5quRPVA==",
+ "dev": true
+ },
+ "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
+ "version": "5.1.1-v1",
+ "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
+ "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==",
+ "dev": true,
+ "dependencies": {
+ "eslint-scope": "5.1.1"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@pnpm/config.env-replace": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.0.0.tgz",
+ "integrity": "sha512-ZVPVDi1E8oeXlYqkGRtX0CkzLTwE2zt62bjWaWKaAvI8NZqHzlMvGeSNDpW+JB3+aKanYb4UETJOF1/CxGPemA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.22.0"
+ }
+ },
+ "node_modules/@pnpm/network.ca-file": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz",
+ "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "4.2.10"
+ },
+ "engines": {
+ "node": ">=12.22.0"
+ }
+ },
+ "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": {
+ "version": "4.2.10",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
+ "dev": true
+ },
+ "node_modules/@pnpm/npm-conf": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.1.0.tgz",
+ "integrity": "sha512-Oe6ntvgsMTE3hDIqy6sajqHF+MnzJrOF06qC2QSiUEybLL7cp6tjoKUa32gpd9+KPVl4QyMs3E3nsXrx/Vdnlw==",
+ "dev": true,
+ "dependencies": {
+ "@pnpm/config.env-replace": "^1.0.0",
+ "@pnpm/network.ca-file": "^1.0.1",
+ "config-chain": "^1.1.11"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@sindresorhus/is": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.3.0.tgz",
+ "integrity": "sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/is?sponsor=1"
+ }
+ },
+ "node_modules/@szmarczak/http-timer": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz",
+ "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==",
+ "dev": true,
+ "dependencies": {
+ "defer-to-connect": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=14.16"
+ }
+ },
+ "node_modules/@types/http-cache-semantics": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz",
+ "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==",
+ "dev": true
+ },
+ "node_modules/@types/minimatch": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz",
+ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==",
+ "dev": true
+ },
+ "node_modules/@types/node": {
+ "version": "18.15.3",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.3.tgz",
+ "integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==",
+ "dev": true
+ },
+ "node_modules/@types/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/abort-controller": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+ "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+ "dev": true,
+ "dependencies": {
+ "event-target-shim": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6.5"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.8.2",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
+ "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/addons-linter": {
+ "version": "5.27.0",
+ "resolved": "https://registry.npmjs.org/addons-linter/-/addons-linter-5.27.0.tgz",
+ "integrity": "sha512-gDgl0FcmhZ5cs3St0qAaO9J1BoektwnY+p4dVgcvPu8WaBqH9MG2fk0gL/evCpoHSXeSw15GA87n8Y7zy7raVQ==",
+ "dev": true,
+ "dependencies": {
+ "@mdn/browser-compat-data": "5.2.29",
+ "addons-moz-compare": "1.3.0",
+ "addons-scanner-utils": "8.3.0",
+ "ajv": "8.12.0",
+ "chalk": "4.1.2",
+ "cheerio": "1.0.0-rc.12",
+ "columnify": "1.6.0",
+ "common-tags": "1.8.2",
+ "deepmerge": "4.2.2",
+ "eslint": "8.32.0",
+ "eslint-plugin-no-unsanitized": "4.0.2",
+ "eslint-visitor-keys": "3.3.0",
+ "espree": "9.4.1",
+ "esprima": "4.0.1",
+ "fast-json-patch": "3.1.1",
+ "fluent-syntax": "0.14.0",
+ "glob": "8.1.0",
+ "image-size": "1.0.2",
+ "is-mergeable-object": "1.1.1",
+ "jed": "1.1.1",
+ "json-merge-patch": "1.0.2",
+ "os-locale": "5.0.0",
+ "pino": "8.8.0",
+ "postcss": "8.4.21",
+ "relaxed-json": "1.0.3",
+ "semver": "7.3.8",
+ "sha.js": "2.4.11",
+ "source-map-support": "0.5.21",
+ "tosource": "1.0.0",
+ "upath": "2.0.1",
+ "yargs": "17.6.2",
+ "yauzl": "2.10.0"
+ },
+ "bin": {
+ "addons-linter": "bin/addons-linter"
+ },
+ "engines": {
+ "node": ">=12.21.0"
+ }
+ },
+ "node_modules/addons-linter/node_modules/@eslint/eslintrc": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
+ "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.4.0",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/addons-linter/node_modules/@eslint/eslintrc/node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/addons-linter/node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/addons-linter/node_modules/addons-scanner-utils": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/addons-scanner-utils/-/addons-scanner-utils-8.3.0.tgz",
+ "integrity": "sha512-XP+2kxhZxlxiVFXVJ7lyJEuxpUS8ryrolUDqnUEnvOZ/3p8qt9hWCYSliXhI2W+Swf/hZ3F4CLAG6tBnqdxDYA==",
+ "dev": true,
+ "dependencies": {
+ "@types/yauzl": "2.10.0",
+ "common-tags": "1.8.2",
+ "first-chunk-stream": "3.0.0",
+ "strip-bom-stream": "4.0.0",
+ "upath": "2.0.1",
+ "yauzl": "2.10.0"
+ },
+ "peerDependencies": {
+ "body-parser": "1.20.1",
+ "express": "4.18.2",
+ "node-fetch": "2.6.7",
+ "safe-compare": "1.1.4"
+ },
+ "peerDependenciesMeta": {
+ "body-parser": {
+ "optional": true
+ },
+ "express": {
+ "optional": true
+ },
+ "node-fetch": {
+ "optional": true
+ },
+ "safe-compare": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/addons-linter/node_modules/ajv": {
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/addons-linter/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/addons-linter/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/addons-linter/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/addons-linter/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/addons-linter/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/addons-linter/node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/addons-linter/node_modules/eslint": {
+ "version": "8.32.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.32.0.tgz",
+ "integrity": "sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==",
+ "dev": true,
+ "dependencies": {
+ "@eslint/eslintrc": "^1.4.1",
+ "@humanwhocodes/config-array": "^0.11.8",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.1.1",
+ "eslint-utils": "^3.0.0",
+ "eslint-visitor-keys": "^3.3.0",
+ "espree": "^9.4.0",
+ "esquery": "^1.4.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "grapheme-splitter": "^1.0.4",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-sdsl": "^4.1.4",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "regexpp": "^3.2.0",
+ "strip-ansi": "^6.0.1",
+ "strip-json-comments": "^3.1.0",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/addons-linter/node_modules/eslint-scope": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+ "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/addons-linter/node_modules/eslint-visitor-keys": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+ "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/addons-linter/node_modules/eslint/node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/addons-linter/node_modules/eslint/node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/addons-linter/node_modules/espree": {
+ "version": "9.4.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
+ "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.8.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/addons-linter/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/addons-linter/node_modules/glob": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
+ "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^5.0.1",
+ "once": "^1.3.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/addons-linter/node_modules/glob/node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/addons-linter/node_modules/globals": {
+ "version": "13.20.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
+ "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/addons-linter/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/addons-linter/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ },
+ "node_modules/addons-linter/node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/addons-linter/node_modules/node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "dev": true,
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/addons-linter/node_modules/semver": {
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/addons-linter/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/addons-linter/node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/addons-linter/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "node_modules/addons-moz-compare": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/addons-moz-compare/-/addons-moz-compare-1.3.0.tgz",
+ "integrity": "sha512-/rXpQeaY0nOKhNx00pmZXdk5Mu+KhVlL3/pSBuAYwrxRrNiTvI/9xfQI8Lmm7DMMl+PDhtfAHY/0ibTpdeoQQQ==",
+ "dev": true
+ },
+ "node_modules/adm-zip": {
+ "version": "0.5.10",
+ "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz",
+ "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-align": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
+ "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.1.0"
+ }
+ },
+ "node_modules/ansi-align/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "node_modules/ansi-align/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
+ "dev": true
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "node_modules/array-differ": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-4.0.0.tgz",
+ "integrity": "sha512-Q6VPTLMsmXZ47ENG3V+wQyZS1ZxXMxFyYzA+Z/GMrJ6yIutAIEf9wTyroTzmGjNfox9/h3GdGBCVh43GVFx4Uw==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/array-union": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz",
+ "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/asn1": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
+ "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
+ "dev": true,
+ "dependencies": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "node_modules/assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/async": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
+ "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
+ "dev": true
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "dev": true
+ },
+ "node_modules/at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/atomic-sleep": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
+ "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/aws4": {
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz",
+ "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==",
+ "dev": true
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
+ "dev": true,
+ "dependencies": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "node_modules/bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+ "dev": true
+ },
+ "node_modules/boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+ "dev": true
+ },
+ "node_modules/boxen": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.2.tgz",
+ "integrity": "sha512-1Z4UJabXUP1/R9rLpoU3O2lEMnG3pPLAs/ZD2lF3t2q7qD5lM8rqbtnvtvm4N0wEyNlE+9yZVTVAGmd1V5jabg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-align": "^3.0.1",
+ "camelcase": "^7.0.0",
+ "chalk": "^5.0.1",
+ "cli-boxes": "^3.0.0",
+ "string-width": "^5.1.2",
+ "type-fest": "^2.13.0",
+ "widest-line": "^4.0.1",
+ "wrap-ansi": "^8.0.1"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/boxen/node_modules/chalk": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz",
+ "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.21.5",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
+ "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ }
+ ],
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001449",
+ "electron-to-chromium": "^1.4.284",
+ "node-releases": "^2.0.8",
+ "update-browserslist-db": "^1.0.10"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
+ "dev": true
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true
+ },
+ "node_modules/bunyan": {
+ "version": "1.8.15",
+ "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz",
+ "integrity": "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==",
+ "dev": true,
+ "engines": [
+ "node >=0.10.0"
+ ],
+ "bin": {
+ "bunyan": "bin/bunyan"
+ },
+ "optionalDependencies": {
+ "dtrace-provider": "~0.8",
+ "moment": "^2.19.3",
+ "mv": "~2",
+ "safe-json-stringify": "~1"
+ }
+ },
+ "node_modules/cacheable-lookup": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz",
+ "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.16"
+ }
+ },
+ "node_modules/cacheable-request": {
+ "version": "10.2.8",
+ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.8.tgz",
+ "integrity": "sha512-IDVO5MJ4LItE6HKFQTqT2ocAQsisOoCTUDu1ddCmnhyiwFQjXNPp4081Xj23N4tO+AFEFNzGuNEf/c8Gwwt15A==",
+ "dev": true,
+ "dependencies": {
+ "@types/http-cache-semantics": "^4.0.1",
+ "get-stream": "^6.0.1",
+ "http-cache-semantics": "^4.1.1",
+ "keyv": "^4.5.2",
+ "mimic-response": "^4.0.0",
+ "normalize-url": "^8.0.0",
+ "responselike": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=14.16"
+ }
+ },
+ "node_modules/cacheable-request/node_modules/get-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelcase": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz",
+ "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001466",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001466.tgz",
+ "integrity": "sha512-ewtFBSfWjEmxUgNBSZItFSmVtvk9zkwkl1OfRZlKA8slltRN+/C/tuGVrF9styXkN36Yu3+SeJ1qkXxDEyNZ5w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ }
+ ]
+ },
+ "node_modules/caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==",
+ "dev": true
+ },
+ "node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cheerio": {
+ "version": "1.0.0-rc.12",
+ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
+ "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
+ "dev": true,
+ "dependencies": {
+ "cheerio-select": "^2.1.0",
+ "dom-serializer": "^2.0.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1",
+ "htmlparser2": "^8.0.1",
+ "parse5": "^7.0.0",
+ "parse5-htmlparser2-tree-adapter": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+ }
+ },
+ "node_modules/cheerio-select": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+ "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+ "dev": true,
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-select": "^5.1.0",
+ "css-what": "^6.1.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/chrome-launcher": {
+ "version": "0.15.1",
+ "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.1.tgz",
+ "integrity": "sha512-UugC8u59/w2AyX5sHLZUHoxBAiSiunUhZa3zZwMH6zPVis0C3dDKiRWyUGIo14tTbZHGVviWxv3PQWZ7taZ4fg==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*",
+ "escape-string-regexp": "^4.0.0",
+ "is-wsl": "^2.2.0",
+ "lighthouse-logger": "^1.0.0"
+ },
+ "bin": {
+ "print-chrome-path": "bin/print-chrome-path.js"
+ },
+ "engines": {
+ "node": ">=12.13.0"
+ }
+ },
+ "node_modules/chrome-launcher/node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ci-info": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz",
+ "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/sibiraj-s"
+ }
+ ],
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-boxes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz",
+ "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/cliui/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/cliui/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/cliui/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/cliui/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "node_modules/cliui/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cliui/node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "node_modules/columnify": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz",
+ "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==",
+ "dev": true,
+ "dependencies": {
+ "strip-ansi": "^6.0.1",
+ "wcwidth": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dev": true,
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/commander": {
+ "version": "9.5.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
+ "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || >=14"
+ }
+ },
+ "node_modules/common-tags": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz",
+ "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "dev": true,
+ "engines": [
+ "node >= 0.8"
+ ],
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "node_modules/concat-stream/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dev": true,
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/concat-stream/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "node_modules/config-chain": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
+ "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
+ "dev": true,
+ "dependencies": {
+ "ini": "^1.3.4",
+ "proto-list": "~1.2.1"
+ }
+ },
+ "node_modules/config-chain/node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "dev": true
+ },
+ "node_modules/configstore": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz",
+ "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==",
+ "dev": true,
+ "dependencies": {
+ "dot-prop": "^6.0.1",
+ "graceful-fs": "^4.2.6",
+ "unique-string": "^3.0.0",
+ "write-file-atomic": "^3.0.3",
+ "xdg-basedir": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/yeoman/configstore?sponsor=1"
+ }
+ },
+ "node_modules/convert-source-map": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+ "dev": true
+ },
+ "node_modules/core-js": {
+ "version": "3.27.1",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.27.1.tgz",
+ "integrity": "sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww==",
+ "dev": true,
+ "hasInstallScript": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/core-js"
+ }
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
+ "dev": true
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/crypto-random-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz",
+ "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/crypto-random-string/node_modules/type-fest": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
+ "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/css-select": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
+ "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
+ "dev": true,
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-what": "^6.1.0",
+ "domhandler": "^5.0.2",
+ "domutils": "^3.0.1",
+ "nth-check": "^2.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/css-what": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+ "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/data-uri-to-buffer": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
+ "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/debounce": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
+ "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==",
+ "dev": true
+ },
+ "node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/decamelize": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz",
+ "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/decompress-response": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+ "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+ "dev": true,
+ "dependencies": {
+ "mimic-response": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/decompress-response/node_modules/mimic-response": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+ "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true
+ },
+ "node_modules/deepcopy": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/deepcopy/-/deepcopy-2.1.0.tgz",
+ "integrity": "sha512-8cZeTb1ZKC3bdSCP6XOM1IsTczIO73fdqtwa2B0N15eAz7gmyhQo+mc5gnFuulsgN3vIQYmTgbmQVKalH1dKvQ==",
+ "dev": true,
+ "dependencies": {
+ "type-detect": "^4.0.8"
+ }
+ },
+ "node_modules/deepmerge": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
+ "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/defaults": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
+ "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
+ "dev": true,
+ "dependencies": {
+ "clone": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/defer-to-connect": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
+ "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/define-lazy-prop": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
+ "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+ "dev": true,
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ]
+ },
+ "node_modules/domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "dev": true,
+ "dependencies": {
+ "domelementtype": "^2.3.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
+ "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
+ "dev": true,
+ "dependencies": {
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
+ "node_modules/dot-prop": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz",
+ "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==",
+ "dev": true,
+ "dependencies": {
+ "is-obj": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/dtrace-provider": {
+ "version": "0.8.8",
+ "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz",
+ "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "dependencies": {
+ "nan": "^2.14.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+ "dev": true
+ },
+ "node_modules/ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
+ "dev": true,
+ "dependencies": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "node_modules/ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.4.332",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.332.tgz",
+ "integrity": "sha512-c1Vbv5tuUlBFp0mb3mCIjw+REEsgthRgNE8BlbEDKmvzb8rxjcVki6OkQP83vLN34s0XCxpSkq7AZNep1a6xhw==",
+ "dev": true
+ },
+ "node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "dev": true
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/entities": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
+ "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "node_modules/es6-error": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
+ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
+ "dev": true
+ },
+ "node_modules/es6-promisify": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-7.0.0.tgz",
+ "integrity": "sha512-ginqzK3J90Rd4/Yz7qRrqUeIpe3TwSXTPPZtPne7tGBPeAaQiU8qt4fpKApnxHcq1AwtUdHVg5P77x/yrggG8Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-goat": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz",
+ "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "8.36.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz",
+ "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.4.0",
+ "@eslint/eslintrc": "^2.0.1",
+ "@eslint/js": "8.36.0",
+ "@humanwhocodes/config-array": "^0.11.8",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.1.1",
+ "eslint-visitor-keys": "^3.3.0",
+ "espree": "^9.5.0",
+ "esquery": "^1.4.2",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "grapheme-splitter": "^1.0.4",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-sdsl": "^4.1.4",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "strip-ansi": "^6.0.1",
+ "strip-json-comments": "^3.1.0",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-plugin-no-unsanitized": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-4.0.2.tgz",
+ "integrity": "sha512-Pry0S9YmHoz8NCEMRQh7N0Yexh2MYCNPIlrV52hTmS7qXnTghWsjXouF08bgsrrZqaW9tt1ZiK3j5NEmPE+EjQ==",
+ "dev": true,
+ "peerDependencies": {
+ "eslint": "^6 || ^7 || ^8"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/eslint-utils": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
+ "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+ "dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^2.0.0"
+ },
+ "engines": {
+ "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ },
+ "peerDependencies": {
+ "eslint": ">=5"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+ "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/eslint/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/eslint/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/eslint/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/eslint/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/eslint/node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint/node_modules/eslint-scope": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+ "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/eslint/node_modules/eslint-visitor-keys": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+ "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/eslint/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/eslint/node_modules/globals": {
+ "version": "13.20.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
+ "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/eslint/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/eslint/node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/espree": {
+ "version": "9.5.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz",
+ "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.8.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/espree/node_modules/eslint-visitor-keys": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+ "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true,
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
+ "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esquery/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/event-target-shim": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
+ "node_modules/execa": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
+ "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^7.0.0",
+ "get-stream": "^5.0.0",
+ "human-signals": "^1.1.1",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.0",
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2",
+ "strip-final-newline": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "node_modules/extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ]
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "node_modules/fast-json-patch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz",
+ "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==",
+ "dev": true
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true
+ },
+ "node_modules/fast-redact": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.1.2.tgz",
+ "integrity": "sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/fastq": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+ "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+ "dev": true,
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+ "dev": true,
+ "dependencies": {
+ "pend": "~1.2.0"
+ }
+ },
+ "node_modules/fetch-blob": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
+ "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "dependencies": {
+ "node-domexception": "^1.0.0",
+ "web-streams-polyfill": "^3.0.3"
+ },
+ "engines": {
+ "node": "^12.20 || >= 14.13"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/firefox-profile": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/firefox-profile/-/firefox-profile-4.2.2.tgz",
+ "integrity": "sha512-3kI17Xl9dL9AeRkpV1yahsJ+UbekkPtlQswKrIsTY1NLgxtEOR4R19rjGGz5+7/rP8Jt6fvxHk+Bai9R6Eai3w==",
+ "dev": true,
+ "dependencies": {
+ "adm-zip": "~0.5.x",
+ "fs-extra": "~9.0.1",
+ "ini": "~2.0.0",
+ "minimist": "^1.2.5",
+ "xml2js": "~0.4.23"
+ },
+ "bin": {
+ "firefox-profile": "lib/cli.js"
+ }
+ },
+ "node_modules/firefox-profile/node_modules/fs-extra": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
+ "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
+ "dev": true,
+ "dependencies": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/firefox-profile/node_modules/universalify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
+ "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/first-chunk-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-3.0.0.tgz",
+ "integrity": "sha512-LNRvR4hr/S8cXXkIY5pTgVP7L3tq6LlYWcg9nWBuW7o1NMxKZo6oOVa/6GIekMGI0Iw7uC+HWimMe9u/VAeKqw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+ "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+ "dev": true,
+ "dependencies": {
+ "flatted": "^3.1.0",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+ "dev": true
+ },
+ "node_modules/fluent-syntax": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/fluent-syntax/-/fluent-syntax-0.14.0.tgz",
+ "integrity": "sha512-+k8uXWfRpSrE33764RbpjIKMzIX6R9EnSjFBgaA1s0Mboc3KnW9sYe0c6vjIoZQY1C4Gst1VFvAOP6YGJjTJuA==",
+ "deprecated": "Renamed to @fluent/syntax 0.14.0",
+ "dev": true,
+ "engines": {
+ "node": ">=8.9.0"
+ }
+ },
+ "node_modules/forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "dev": true,
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 0.12"
+ }
+ },
+ "node_modules/form-data-encoder": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz",
+ "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 14.17"
+ }
+ },
+ "node_modules/formdata-polyfill": {
+ "version": "4.0.10",
+ "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
+ "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+ "dev": true,
+ "dependencies": {
+ "fetch-blob": "^3.1.2"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/fs-extra": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz",
+ "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "node_modules/fx-runner": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/fx-runner/-/fx-runner-1.3.0.tgz",
+ "integrity": "sha512-5b37H4GCyhF+Nf8xk9mylXoDq4wb7pbGAXxlCXp/631UTeeZomWSYcEGXumY4wk8g2QAqjPMGdWW+RbNt8PUcA==",
+ "dev": true,
+ "dependencies": {
+ "commander": "2.9.0",
+ "shell-quote": "1.7.3",
+ "spawn-sync": "1.0.15",
+ "when": "3.7.7",
+ "which": "1.2.4",
+ "winreg": "0.0.12"
+ },
+ "bin": {
+ "fx-runner": "bin/fx-runner"
+ }
+ },
+ "node_modules/fx-runner/node_modules/commander": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
+ "integrity": "sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A==",
+ "dev": true,
+ "dependencies": {
+ "graceful-readlink": ">= 1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6.x"
+ }
+ },
+ "node_modules/fx-runner/node_modules/isexe": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz",
+ "integrity": "sha512-d2eJzK691yZwPHcv1LbeAOa91yMJ9QmfTgSO1oXB65ezVhXQsxBac2vEB4bMVms9cGzaA99n6V2viHMq82VLDw==",
+ "dev": true
+ },
+ "node_modules/fx-runner/node_modules/which": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.2.4.tgz",
+ "integrity": "sha512-zDRAqDSBudazdfM9zpiI30Fu9ve47htYXcGi3ln0wfKu2a7SmrT6F3VDoYONu//48V8Vz4TdCRNPjtvyRO3yBA==",
+ "dev": true,
+ "dependencies": {
+ "is-absolute": "^0.1.7",
+ "isexe": "^1.1.1"
+ },
+ "bin": {
+ "which": "bin/which"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/glob-to-regexp": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+ "dev": true
+ },
+ "node_modules/global-dirs": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz",
+ "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==",
+ "dev": true,
+ "dependencies": {
+ "ini": "2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/got": {
+ "version": "12.6.0",
+ "resolved": "https://registry.npmjs.org/got/-/got-12.6.0.tgz",
+ "integrity": "sha512-WTcaQ963xV97MN3x0/CbAriXFZcXCfgxVp91I+Ze6pawQOa7SgzwSx2zIJJsX+kTajMnVs0xcFD1TxZKFqhdnQ==",
+ "dev": true,
+ "dependencies": {
+ "@sindresorhus/is": "^5.2.0",
+ "@szmarczak/http-timer": "^5.0.1",
+ "cacheable-lookup": "^7.0.0",
+ "cacheable-request": "^10.2.8",
+ "decompress-response": "^6.0.0",
+ "form-data-encoder": "^2.1.2",
+ "get-stream": "^6.0.1",
+ "http2-wrapper": "^2.1.10",
+ "lowercase-keys": "^3.0.0",
+ "p-cancelable": "^3.0.0",
+ "responselike": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/got?sponsor=1"
+ }
+ },
+ "node_modules/got/node_modules/get-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true
+ },
+ "node_modules/graceful-readlink": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
+ "integrity": "sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==",
+ "dev": true
+ },
+ "node_modules/grapheme-splitter": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+ "dev": true
+ },
+ "node_modules/growly": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
+ "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==",
+ "dev": true
+ },
+ "node_modules/har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/har-validator": {
+ "version": "5.1.5",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
+ "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
+ "deprecated": "this library is no longer supported",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.3",
+ "har-schema": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/has-yarn": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz",
+ "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/htmlparser2": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz",
+ "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==",
+ "dev": true,
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "domutils": "^3.0.1",
+ "entities": "^4.3.0"
+ }
+ },
+ "node_modules/http-cache-semantics": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
+ "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
+ "dev": true
+ },
+ "node_modules/http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ },
+ "engines": {
+ "node": ">=0.8",
+ "npm": ">=1.3.7"
+ }
+ },
+ "node_modules/http2-wrapper": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz",
+ "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==",
+ "dev": true,
+ "dependencies": {
+ "quick-lru": "^5.1.1",
+ "resolve-alpn": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=10.19.0"
+ }
+ },
+ "node_modules/human-signals": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
+ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.12.0"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/ignore": {
+ "version": "5.2.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+ "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/image-size": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz",
+ "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==",
+ "dev": true,
+ "dependencies": {
+ "queue": "6.0.2"
+ },
+ "bin": {
+ "image-size": "bin/image-size.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
+ "dev": true
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/import-lazy": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz",
+ "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/ini": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
+ "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/invert-kv": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-3.0.1.tgz",
+ "integrity": "sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/invert-kv?sponsor=1"
+ }
+ },
+ "node_modules/is-absolute": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
+ "integrity": "sha512-Xi9/ZSn4NFapG8RP98iNPMOeaV3mXPisxKxzKtHVqr3g56j/fBn+yZmnxSVAA8lmZbl2J9b/a4kJvfU3hqQYgA==",
+ "dev": true,
+ "dependencies": {
+ "is-relative": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "dev": true
+ },
+ "node_modules/is-ci": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz",
+ "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==",
+ "dev": true,
+ "dependencies": {
+ "ci-info": "^3.2.0"
+ },
+ "bin": {
+ "is-ci": "bin.js"
+ }
+ },
+ "node_modules/is-docker": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+ "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+ "dev": true,
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-installed-globally": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
+ "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==",
+ "dev": true,
+ "dependencies": {
+ "global-dirs": "^3.0.0",
+ "is-path-inside": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-mergeable-object": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-mergeable-object/-/is-mergeable-object-1.1.1.tgz",
+ "integrity": "sha512-CPduJfuGg8h8vW74WOxHtHmtQutyQBzR+3MjQ6iDHIYdbOnm1YC7jv43SqCoU8OPGTJD4nibmiryA4kmogbGrA==",
+ "dev": true
+ },
+ "node_modules/is-npm": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz",
+ "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-relative": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz",
+ "integrity": "sha512-wBOr+rNM4gkAZqoLRJI4myw5WzzIdQosFAAbnvfXP5z1LyzgAI3ivOKehC5KfqlQJZoihVhirgtCBj378Eg8GA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
+ "dev": true
+ },
+ "node_modules/is-utf8": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==",
+ "dev": true
+ },
+ "node_modules/is-wsl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+ "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+ "dev": true,
+ "dependencies": {
+ "is-docker": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-yarn-global": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz",
+ "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "dev": true
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true
+ },
+ "node_modules/isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==",
+ "dev": true
+ },
+ "node_modules/jed": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/jed/-/jed-1.1.1.tgz",
+ "integrity": "sha512-z35ZSEcXHxLW4yumw0dF6L464NT36vmx3wxJw8MDpraBcWuNVgUPZgPJKcu1HekNgwlMFNqol7i/IpSbjhqwqA==",
+ "dev": true
+ },
+ "node_modules/jose": {
+ "version": "4.11.2",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-4.11.2.tgz",
+ "integrity": "sha512-njj0VL2TsIxCtgzhO+9RRobBvws4oYyCM8TpvoUQwl/MbIM3NFJRR9+e6x0sS5xXaP1t6OCBkaBME98OV9zU5A==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
+ "node_modules/js-sdsl": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
+ "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
+ "dev": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/js-sdsl"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==",
+ "dev": true
+ },
+ "node_modules/jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true
+ },
+ "node_modules/json-merge-patch": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-merge-patch/-/json-merge-patch-1.0.2.tgz",
+ "integrity": "sha512-M6Vp2GN9L7cfuMXiWOmHj9bEFbeC250iVtcKQbqVgEsDVYnIsrNsbU+h/Y/PkbBQCtEa4Bez+Ebv0zfbC8ObLg==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3"
+ }
+ },
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true
+ },
+ "node_modules/json-schema": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
+ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
+ "dev": true
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true
+ },
+ "node_modules/json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
+ "dev": true
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/jsonwebtoken": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
+ "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==",
+ "dev": true,
+ "dependencies": {
+ "jws": "^3.2.2",
+ "lodash": "^4.17.21",
+ "ms": "^2.1.1",
+ "semver": "^7.3.8"
+ },
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ }
+ },
+ "node_modules/jsonwebtoken/node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/jsonwebtoken/node_modules/semver": {
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/jsonwebtoken/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "node_modules/jsprim": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
+ "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.4.0",
+ "verror": "1.10.0"
+ },
+ "engines": {
+ "node": ">=0.6.0"
+ }
+ },
+ "node_modules/jszip": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
+ "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
+ "dev": true,
+ "dependencies": {
+ "lie": "~3.3.0",
+ "pako": "~1.0.2",
+ "readable-stream": "~2.3.6",
+ "setimmediate": "^1.0.5"
+ }
+ },
+ "node_modules/jszip/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dev": true,
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/jszip/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "node_modules/jwa": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "dev": true,
+ "dependencies": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "dev": true,
+ "dependencies": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz",
+ "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==",
+ "dev": true,
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/latest-version": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz",
+ "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==",
+ "dev": true,
+ "dependencies": {
+ "package-json": "^8.1.0"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lcid": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/lcid/-/lcid-3.1.1.tgz",
+ "integrity": "sha512-M6T051+5QCGLBQb8id3hdvIW8+zeFV2FyBGFS9IEK5H9Wt4MueD4bW1eWikpHgZp+5xR3l5c8pZUkQsIA0BFZg==",
+ "dev": true,
+ "dependencies": {
+ "invert-kv": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lie": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+ "dev": true,
+ "dependencies": {
+ "immediate": "~3.0.5"
+ }
+ },
+ "node_modules/lighthouse-logger": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.3.0.tgz",
+ "integrity": "sha512-BbqAKApLb9ywUli+0a+PcV04SyJ/N1q/8qgCNe6U97KbPCS1BTksEuHFLYdvc8DltuhfxIUBqDZsC0bBGtl3lA==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^2.6.9",
+ "marky": "^1.2.2"
+ }
+ },
+ "node_modules/lighthouse-logger/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/lighthouse-logger/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true
+ },
+ "node_modules/lines-and-columns": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz",
+ "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "node_modules/lowercase-keys": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
+ "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "dev": true
+ },
+ "node_modules/map-age-cleaner": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
+ "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
+ "dev": true,
+ "dependencies": {
+ "p-defer": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/marky": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz",
+ "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==",
+ "dev": true
+ },
+ "node_modules/mem": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/mem/-/mem-5.1.1.tgz",
+ "integrity": "sha512-qvwipnozMohxLXG1pOqoLiZKNkC4r4qqRucSoDwXowsNGDSULiqFTRUF05vcZWnwJSG22qTsynQhxbaMtnX9gw==",
+ "dev": true,
+ "dependencies": {
+ "map-age-cleaner": "^0.1.3",
+ "mimic-fn": "^2.1.0",
+ "p-is-promise": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dev": true,
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/mimic-response": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz",
+ "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true,
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/moment": {
+ "version": "2.29.4",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/multimatch": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-6.0.0.tgz",
+ "integrity": "sha512-I7tSVxHGPlmPN/enE3mS1aOSo6bWBfls+3HmuEeCUBCE7gWnm3cBXCBkpurzFjVRwC6Kld8lLaZ1Iv5vOcjvcQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/minimatch": "^3.0.5",
+ "array-differ": "^4.0.0",
+ "array-union": "^3.0.1",
+ "minimatch": "^3.0.4"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/mv": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz",
+ "integrity": "sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "mkdirp": "~0.5.1",
+ "ncp": "~2.0.0",
+ "rimraf": "~2.4.0"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/mv/node_modules/glob": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
+ "integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "2 || 3",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/mv/node_modules/mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "minimist": "^1.2.6"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/mv/node_modules/rimraf": {
+ "version": "2.4.5",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz",
+ "integrity": "sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "glob": "^6.0.1"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "node_modules/mz": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+ "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+ "dev": true,
+ "dependencies": {
+ "any-promise": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "thenify-all": "^1.0.0"
+ }
+ },
+ "node_modules/nan": {
+ "version": "2.17.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz",
+ "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==",
+ "dev": true,
+ "optional": true
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
+ "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
+ "dev": true,
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true
+ },
+ "node_modules/ncp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
+ "integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==",
+ "dev": true,
+ "optional": true,
+ "bin": {
+ "ncp": "bin/ncp"
+ }
+ },
+ "node_modules/node-domexception": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "github",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "engines": {
+ "node": ">=10.5.0"
+ }
+ },
+ "node_modules/node-fetch": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz",
+ "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==",
+ "dev": true,
+ "dependencies": {
+ "data-uri-to-buffer": "^4.0.0",
+ "fetch-blob": "^3.1.4",
+ "formdata-polyfill": "^4.0.10"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/node-fetch"
+ }
+ },
+ "node_modules/node-forge": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
+ "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6.13.0"
+ }
+ },
+ "node_modules/node-notifier": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-10.0.1.tgz",
+ "integrity": "sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ==",
+ "dev": true,
+ "dependencies": {
+ "growly": "^1.3.0",
+ "is-wsl": "^2.2.0",
+ "semver": "^7.3.5",
+ "shellwords": "^0.1.1",
+ "uuid": "^8.3.2",
+ "which": "^2.0.2"
+ }
+ },
+ "node_modules/node-notifier/node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/node-notifier/node_modules/semver": {
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/node-notifier/node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "dev": true,
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/node-notifier/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
+ "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==",
+ "dev": true
+ },
+ "node_modules/normalize-url": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz",
+ "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "dev": true,
+ "dependencies": {
+ "boolbase": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/nth-check?sponsor=1"
+ }
+ },
+ "node_modules/oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/on-exit-leak-free": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz",
+ "integrity": "sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==",
+ "dev": true
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/open": {
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz",
+ "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==",
+ "dev": true,
+ "dependencies": {
+ "define-lazy-prop": "^2.0.0",
+ "is-docker": "^2.1.1",
+ "is-wsl": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+ "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+ "dev": true,
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/os-locale": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-5.0.0.tgz",
+ "integrity": "sha512-tqZcNEDAIZKBEPnHPlVDvKrp7NzgLi7jRmhKiUoa2NUmhl13FtkAGLUVR+ZsYvApBQdBfYm43A4tXXQ4IrYLBA==",
+ "dev": true,
+ "dependencies": {
+ "execa": "^4.0.0",
+ "lcid": "^3.0.0",
+ "mem": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/os-shim": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz",
+ "integrity": "sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/p-cancelable": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz",
+ "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.20"
+ }
+ },
+ "node_modules/p-defer": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
+ "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/p-is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
+ "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/package-json": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.0.tgz",
+ "integrity": "sha512-hySwcV8RAWeAfPsXb9/HGSPn8lwDnv6fabH+obUZKX169QknRkRhPxd1yMubpKDskLFATkl3jHpNtVtDPFA0Wg==",
+ "dev": true,
+ "dependencies": {
+ "got": "^12.1.0",
+ "registry-auth-token": "^5.0.1",
+ "registry-url": "^6.0.0",
+ "semver": "^7.3.7"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/package-json/node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/package-json/node_modules/semver": {
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/package-json/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "node_modules/pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
+ "dev": true
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-json": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-6.0.2.tgz",
+ "integrity": "sha512-SA5aMiaIjXkAiBrW/yPgLgQAQg42f7K3ACO+2l/zOvtQBwX58DMUsFJXelW2fx3yMBmWOVkR6j1MGsdSbCA4UA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.16.0",
+ "error-ex": "^1.3.2",
+ "json-parse-even-better-errors": "^2.3.1",
+ "lines-and-columns": "^2.0.2"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parse5": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
+ "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+ "dev": true,
+ "dependencies": {
+ "entities": "^4.4.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5-htmlparser2-tree-adapter": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
+ "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
+ "dev": true,
+ "dependencies": {
+ "domhandler": "^5.0.2",
+ "parse5": "^7.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+ "dev": true
+ },
+ "node_modules/performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
+ "dev": true
+ },
+ "node_modules/picocolors": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+ "dev": true
+ },
+ "node_modules/pino": {
+ "version": "8.8.0",
+ "resolved": "https://registry.npmjs.org/pino/-/pino-8.8.0.tgz",
+ "integrity": "sha512-cF8iGYeu2ODg2gIwgAHcPrtR63ILJz3f7gkogaHC/TXVVXxZgInmNYiIpDYEwgEkxZti2Se6P2W2DxlBIZe6eQ==",
+ "dev": true,
+ "dependencies": {
+ "atomic-sleep": "^1.0.0",
+ "fast-redact": "^3.1.1",
+ "on-exit-leak-free": "^2.1.0",
+ "pino-abstract-transport": "v1.0.0",
+ "pino-std-serializers": "^6.0.0",
+ "process-warning": "^2.0.0",
+ "quick-format-unescaped": "^4.0.3",
+ "real-require": "^0.2.0",
+ "safe-stable-stringify": "^2.3.1",
+ "sonic-boom": "^3.1.0",
+ "thread-stream": "^2.0.0"
+ },
+ "bin": {
+ "pino": "bin.js"
+ }
+ },
+ "node_modules/pino-abstract-transport": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz",
+ "integrity": "sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "^4.0.0",
+ "split2": "^4.0.0"
+ }
+ },
+ "node_modules/pino-std-serializers": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.1.0.tgz",
+ "integrity": "sha512-KO0m2f1HkrPe9S0ldjx7za9BJjeHqBku5Ch8JyxETxT8dEFGz1PwgrHaOQupVYitpzbFSYm7nnljxD8dik2c+g==",
+ "dev": true
+ },
+ "node_modules/postcss": {
+ "version": "8.4.21",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
+ "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ }
+ ],
+ "dependencies": {
+ "nanoid": "^3.3.4",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "node_modules/process-warning": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.1.0.tgz",
+ "integrity": "sha512-9C20RLxrZU/rFnxWncDkuF6O999NdIf3E1ws4B0ZeY3sRVPzWBMsYDE2lxjxhiXxg464cQTgKUGm8/i6y2YGXg==",
+ "dev": true
+ },
+ "node_modules/promise-toolbox": {
+ "version": "0.21.0",
+ "resolved": "https://registry.npmjs.org/promise-toolbox/-/promise-toolbox-0.21.0.tgz",
+ "integrity": "sha512-NV8aTmpwrZv+Iys54sSFOBx3tuVaOBvvrft5PNppnxy9xpU/akHbaWIril22AB22zaPgrgwKdD0KsrM0ptUtpg==",
+ "dev": true,
+ "dependencies": {
+ "make-error": "^1.3.2"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/proto-list": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
+ "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==",
+ "dev": true
+ },
+ "node_modules/psl": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
+ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
+ "dev": true
+ },
+ "node_modules/pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dev": true,
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
+ "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/pupa": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz",
+ "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==",
+ "dev": true,
+ "dependencies": {
+ "escape-goat": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.5.3",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
+ "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/queue": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
+ "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "~2.0.3"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/quick-format-unescaped": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
+ "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==",
+ "dev": true
+ },
+ "node_modules/quick-lru": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "dev": true,
+ "dependencies": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "bin": {
+ "rc": "cli.js"
+ }
+ },
+ "node_modules/rc/node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "dev": true
+ },
+ "node_modules/rc/node_modules/strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.3.0.tgz",
+ "integrity": "sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==",
+ "dev": true,
+ "dependencies": {
+ "abort-controller": "^3.0.0",
+ "buffer": "^6.0.3",
+ "events": "^3.3.0",
+ "process": "^0.11.10"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/real-require": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz",
+ "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 12.13.0"
+ }
+ },
+ "node_modules/regenerator-runtime": {
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
+ "dev": true
+ },
+ "node_modules/regexpp": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ }
+ },
+ "node_modules/registry-auth-token": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz",
+ "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==",
+ "dev": true,
+ "dependencies": {
+ "@pnpm/npm-conf": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/registry-url": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz",
+ "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==",
+ "dev": true,
+ "dependencies": {
+ "rc": "1.2.8"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/relaxed-json": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/relaxed-json/-/relaxed-json-1.0.3.tgz",
+ "integrity": "sha512-b7wGPo7o2KE/g7SqkJDDbav6zmrEeP4TK2VpITU72J/M949TLe/23y/ZHJo+pskcGM52xIfFoT9hydwmgr1AEg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.2",
+ "commander": "^2.6.0"
+ },
+ "bin": {
+ "rjson": "bin/rjson.js"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/relaxed-json/node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
+ "node_modules/request": {
+ "version": "2.88.2",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+ "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+ "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
+ "dev": true,
+ "dependencies": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.3",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.5.0",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve-alpn": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
+ "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==",
+ "dev": true
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/responselike": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz",
+ "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==",
+ "dev": true,
+ "dependencies": {
+ "lowercase-keys": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true,
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/safe-json-stringify": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz",
+ "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==",
+ "dev": true,
+ "optional": true
+ },
+ "node_modules/safe-stable-stringify": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz",
+ "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "node_modules/sax": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+ "dev": true
+ },
+ "node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/semver-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz",
+ "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==",
+ "dev": true,
+ "dependencies": {
+ "semver": "^7.3.5"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/semver-diff/node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/semver-diff/node_modules/semver": {
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/semver-diff/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "node_modules/setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
+ "dev": true
+ },
+ "node_modules/sha.js": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ },
+ "bin": {
+ "sha.js": "bin.js"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shell-quote": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz",
+ "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==",
+ "dev": true
+ },
+ "node_modules/shellwords": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
+ "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
+ "dev": true
+ },
+ "node_modules/sign-addon": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/sign-addon/-/sign-addon-5.2.0.tgz",
+ "integrity": "sha512-t5CZ4MSKAd3uJBUfjgWfSyKYC1pQS6BMUbgI5OytzMkTOQ9NkdkFE8bB0AJLQIGqDrNS2b1+/ghAP56iuCUE+g==",
+ "dev": true,
+ "dependencies": {
+ "common-tags": "1.8.2",
+ "core-js": "3.27.1",
+ "deepcopy": "2.1.0",
+ "es6-error": "4.1.1",
+ "es6-promisify": "7.0.0",
+ "jsonwebtoken": "9.0.0",
+ "mz": "2.7.0",
+ "request": "2.88.2",
+ "source-map-support": "0.5.21",
+ "stream-to-promise": "3.0.0"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "dev": true
+ },
+ "node_modules/sonic-boom": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.2.1.tgz",
+ "integrity": "sha512-iITeTHxy3B9FGu8aVdiDXUVAcHMF9Ss0cCsAOo2HfCrmVGT3/DT5oYaeu0M/YKZDlKTvChEyPq0zI9Hf33EX6A==",
+ "dev": true,
+ "dependencies": {
+ "atomic-sleep": "^1.0.0"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "dev": true,
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/spawn-sync": {
+ "version": "1.0.15",
+ "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz",
+ "integrity": "sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "concat-stream": "^1.4.7",
+ "os-shim": "^0.1.2"
+ }
+ },
+ "node_modules/split": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
+ "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
+ "dev": true,
+ "dependencies": {
+ "through": "2"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/split2": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz",
+ "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.x"
+ }
+ },
+ "node_modules/sshpk": {
+ "version": "1.17.0",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
+ "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==",
+ "dev": true,
+ "dependencies": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ },
+ "bin": {
+ "sshpk-conv": "bin/sshpk-conv",
+ "sshpk-sign": "bin/sshpk-sign",
+ "sshpk-verify": "bin/sshpk-verify"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/stream-to-array": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/stream-to-array/-/stream-to-array-2.3.0.tgz",
+ "integrity": "sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA==",
+ "dev": true,
+ "dependencies": {
+ "any-promise": "^1.1.0"
+ }
+ },
+ "node_modules/stream-to-promise": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/stream-to-promise/-/stream-to-promise-3.0.0.tgz",
+ "integrity": "sha512-h+7wLeFiYegOdgTfTxjRsrT7/Op7grnKEIHWgaO1RTHwcwk7xRreMr3S8XpDfDMesSxzgM2V4CxNCFAGo6ssnA==",
+ "dev": true,
+ "dependencies": {
+ "any-promise": "~1.3.0",
+ "end-of-stream": "~1.4.1",
+ "stream-to-array": "~2.3.0"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/string_decoder/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "dev": true,
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/string-width/node_modules/ansi-regex": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/string-width/node_modules/strip-ansi": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
+ "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-bom": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-5.0.0.tgz",
+ "integrity": "sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/strip-bom-buf": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom-buf/-/strip-bom-buf-2.0.0.tgz",
+ "integrity": "sha512-gLFNHucd6gzb8jMsl5QmZ3QgnUJmp7qn4uUSHNwEXumAp7YizoGYw19ZUVfuq4aBOQUtyn2k8X/CwzWB73W2lQ==",
+ "dev": true,
+ "dependencies": {
+ "is-utf8": "^0.2.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-bom-stream": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-4.0.0.tgz",
+ "integrity": "sha512-0ApK3iAkHv6WbgLICw/J4nhwHeDZsBxIIsOD+gHgZICL6SeJ0S9f/WZqemka9cjkTyMN5geId6e8U5WGFAn3cQ==",
+ "dev": true,
+ "dependencies": {
+ "first-chunk-stream": "^3.0.0",
+ "strip-bom-buf": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true
+ },
+ "node_modules/thenify": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+ "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+ "dev": true,
+ "dependencies": {
+ "any-promise": "^1.0.0"
+ }
+ },
+ "node_modules/thenify-all": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+ "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+ "dev": true,
+ "dependencies": {
+ "thenify": ">= 3.1.0 < 4"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/thread-stream": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.3.0.tgz",
+ "integrity": "sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA==",
+ "dev": true,
+ "dependencies": {
+ "real-require": "^0.2.0"
+ }
+ },
+ "node_modules/through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+ "dev": true
+ },
+ "node_modules/tmp": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+ "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+ "dev": true,
+ "dependencies": {
+ "rimraf": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8.17.0"
+ }
+ },
+ "node_modules/to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/tosource": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/tosource/-/tosource-1.0.0.tgz",
+ "integrity": "sha512-N6g8eQ1eerw6Y1pBhdgkubWIiPFwXa2POSUrlL8jth5CyyEWNWzoGKRkO3CaO7Jx27hlJP54muB3btIAbx4MPg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "dev": true,
+ "dependencies": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "dev": true,
+ "optional": true,
+ "peer": true
+ },
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==",
+ "dev": true
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-detect": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+ "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
+ "dev": true
+ },
+ "node_modules/typedarray-to-buffer": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+ "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+ "dev": true,
+ "dependencies": {
+ "is-typedarray": "^1.0.0"
+ }
+ },
+ "node_modules/unique-string": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz",
+ "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==",
+ "dev": true,
+ "dependencies": {
+ "crypto-random-string": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/upath": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz",
+ "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==",
+ "dev": true,
+ "engines": {
+ "node": ">=4",
+ "yarn": "*"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
+ "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ }
+ ],
+ "dependencies": {
+ "escalade": "^3.1.1",
+ "picocolors": "^1.0.0"
+ },
+ "bin": {
+ "browserslist-lint": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/update-notifier": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz",
+ "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==",
+ "dev": true,
+ "dependencies": {
+ "boxen": "^7.0.0",
+ "chalk": "^5.0.1",
+ "configstore": "^6.0.0",
+ "has-yarn": "^3.0.0",
+ "import-lazy": "^4.0.0",
+ "is-ci": "^3.0.1",
+ "is-installed-globally": "^0.4.0",
+ "is-npm": "^6.0.0",
+ "is-yarn-global": "^0.4.0",
+ "latest-version": "^7.0.0",
+ "pupa": "^3.1.0",
+ "semver": "^7.3.7",
+ "semver-diff": "^4.0.0",
+ "xdg-basedir": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/yeoman/update-notifier?sponsor=1"
+ }
+ },
+ "node_modules/update-notifier/node_modules/chalk": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz",
+ "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/update-notifier/node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/update-notifier/node_modules/semver": {
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/update-notifier/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
+ },
+ "node_modules/uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+ "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
+ "dev": true,
+ "bin": {
+ "uuid": "bin/uuid"
+ }
+ },
+ "node_modules/verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "node_modules/watchpack": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
+ "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
+ "dev": true,
+ "dependencies": {
+ "glob-to-regexp": "^0.4.1",
+ "graceful-fs": "^4.1.2"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/wcwidth": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
+ "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
+ "dev": true,
+ "dependencies": {
+ "defaults": "^1.0.3"
+ }
+ },
+ "node_modules/web-ext": {
+ "version": "7.5.0",
+ "resolved": "https://registry.npmjs.org/web-ext/-/web-ext-7.5.0.tgz",
+ "integrity": "sha512-Ymflj7Aq/LOD+zGoyvwRbAPx/yMJeig2OEb/rRXYrWl6NWRI5E0c2iWGqlBcnL45iKrOzz70H438dVeJk0w2ug==",
+ "dev": true,
+ "dependencies": {
+ "@babel/runtime": "7.20.13",
+ "@devicefarmer/adbkit": "3.2.3",
+ "addons-linter": "5.27.0",
+ "bunyan": "1.8.15",
+ "camelcase": "7.0.1",
+ "chrome-launcher": "0.15.1",
+ "debounce": "1.2.1",
+ "decamelize": "6.0.0",
+ "es6-error": "4.1.1",
+ "firefox-profile": "4.2.2",
+ "fs-extra": "11.1.0",
+ "fx-runner": "1.3.0",
+ "import-fresh": "3.3.0",
+ "jose": "4.11.2",
+ "mkdirp": "1.0.4",
+ "multimatch": "6.0.0",
+ "mz": "2.7.0",
+ "node-fetch": "3.3.0",
+ "node-notifier": "10.0.1",
+ "open": "8.4.0",
+ "parse-json": "6.0.2",
+ "promise-toolbox": "0.21.0",
+ "sign-addon": "5.2.0",
+ "source-map-support": "0.5.21",
+ "strip-bom": "5.0.0",
+ "strip-json-comments": "5.0.0",
+ "tmp": "0.2.1",
+ "update-notifier": "6.0.2",
+ "watchpack": "2.4.0",
+ "ws": "8.12.0",
+ "yargs": "17.6.2",
+ "zip-dir": "2.0.0"
+ },
+ "bin": {
+ "web-ext": "bin/web-ext.js"
+ },
+ "engines": {
+ "node": ">=14.0.0",
+ "npm": ">=6.9.0"
+ }
+ },
+ "node_modules/web-ext/node_modules/strip-json-comments": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.0.tgz",
+ "integrity": "sha512-V1LGY4UUo0jgwC+ELQ2BNWfPa17TIuwBLg+j1AA/9RPzKINl1lhxVEu2r+ZTTO8aetIsUzE5Qj6LMSBkoGYKKw==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/web-streams-polyfill": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
+ "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "dev": true,
+ "optional": true,
+ "peer": true
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "dev": true,
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "node_modules/when": {
+ "version": "3.7.7",
+ "resolved": "https://registry.npmjs.org/when/-/when-3.7.7.tgz",
+ "integrity": "sha512-9lFZp/KHoqH6bPKjbWqa+3Dg/K/r2v0X/3/G2x4DBGchVS2QX2VXL3cZV994WQVnTM1/PD71Az25nAzryEUugw==",
+ "dev": true
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/widest-line": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz",
+ "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/winreg": {
+ "version": "0.0.12",
+ "resolved": "https://registry.npmjs.org/winreg/-/winreg-0.0.12.tgz",
+ "integrity": "sha512-typ/+JRmi7RqP1NanzFULK36vczznSNN8kWVA9vIqXyv8GhghUlwhGp1Xj3Nms1FsPcNnsQrJOR10N58/nQ9hQ==",
+ "dev": true
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/ansi-regex": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/strip-ansi": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
+ "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true
+ },
+ "node_modules/write-file-atomic": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
+ "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
+ "dev": true,
+ "dependencies": {
+ "imurmurhash": "^0.1.4",
+ "is-typedarray": "^1.0.0",
+ "signal-exit": "^3.0.2",
+ "typedarray-to-buffer": "^3.1.5"
+ }
+ },
+ "node_modules/ws": {
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz",
+ "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==",
+ "dev": true,
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xdg-basedir": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz",
+ "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/xml2js": {
+ "version": "0.4.23",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
+ "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
+ "dev": true,
+ "dependencies": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~11.0.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/xmlbuilder": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true
+ },
+ "node_modules/yargs": {
+ "version": "17.6.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz",
+ "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "node_modules/yargs/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+ "dev": true,
+ "dependencies": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/zip-dir": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/zip-dir/-/zip-dir-2.0.0.tgz",
+ "integrity": "sha512-uhlsJZWz26FLYXOD6WVuq+fIcZ3aBPGo/cFdiLlv3KNwpa52IF3ISV8fLhQLiqVu5No3VhlqlgthN6gehil1Dg==",
+ "dev": true,
+ "dependencies": {
+ "async": "^3.2.0",
+ "jszip": "^3.2.2"
+ }
+ }
+ }
+}
diff --git a/2021/nexus-archive/browser-extension/package.json b/2021/nexus-archive/browser-extension/package.json
new file mode 100644
index 0000000..045345e
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/package.json
@@ -0,0 +1,16 @@
+{
+ "babel": {},
+ "devDependencies": {
+ "@babel/core": "^7.21.3",
+ "@babel/eslint-parser": "^7.21.3",
+ "eslint": "^8.36.0",
+ "request": "^2.88.2",
+ "web-ext": "^7.5.0"
+ },
+ "webExt": {
+ "ignoreFiles": [
+ "package.json",
+ "package-lock.json"
+ ]
+ }
+}
diff --git a/2021/nexus-archive/browser-extension/src/background.js b/2021/nexus-archive/browser-extension/src/background.js
new file mode 100644
index 0000000..cf6460e
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/src/background.js
@@ -0,0 +1,13 @@
+/* global NexusDataQueue, NexusDataSender, Preferences, WebRequestMonitor */
+'use strict'
+
+const preferences = new Preferences()
+preferences.load()
+preferences.listenForStorageChanges()
+
+const nexusDataQueue = new NexusDataQueue()
+
+const nexusDataSender = new NexusDataSender(preferences)
+
+const webRequestMonitor = new WebRequestMonitor(nexusDataQueue, nexusDataSender)
+webRequestMonitor.addListeners()
diff --git a/2021/nexus-archive/browser-extension/src/nexusData.js b/2021/nexus-archive/browser-extension/src/nexusData.js
new file mode 100644
index 0000000..ccfd28a
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/src/nexusData.js
@@ -0,0 +1,81 @@
+/* exported NexusData */
+'use strict'
+
+class NexusData {
+ constructor() {
+ this._requestId = null
+ this._requestStartedAt = null
+ this._responseCompletedAt = null
+ this._method = null
+ this._url = null
+ this._formData = null
+ this._responseBodyParts = []
+ }
+
+ get requestId() {
+ return this._requestId
+ }
+
+ set requestId(value) {
+ this._requestId = value
+ }
+
+ get requestStartedAt() {
+ return this._requestStartedAt
+ }
+
+ set requestStartedAt(value) {
+ if (!(value instanceof Date)) {
+ value = new Date(value)
+ }
+ this._requestStartedAt = value
+ }
+
+ get responseCompletedAt() {
+ return this._responseCompletedAt
+ }
+
+ set responseCompletedAt(value) {
+ if (!(value instanceof Date)) {
+ value = new Date(value)
+ }
+ this._responseCompletedAt = value
+ }
+
+ get method() {
+ return this._method
+ }
+
+ set method(value) {
+ this._method = value
+ }
+
+ get url() {
+ return this._url
+ }
+
+ set url(value) {
+ this._url = value
+ }
+
+ get formData() {
+ return this._formData
+ }
+
+ set formData(value) {
+ this._formData = value
+ }
+
+ get responseBody() {
+ return this._responseBodyParts.join('')
+ }
+
+ set responseBody(value) {
+ this._responseBodyParts = []
+ this.appendResponseBodyPart(value)
+ }
+
+ appendResponseBodyPart(value) {
+ this._responseBodyParts.push(value)
+ }
+}
diff --git a/2021/nexus-archive/browser-extension/src/nexusDataQueue.js b/2021/nexus-archive/browser-extension/src/nexusDataQueue.js
new file mode 100644
index 0000000..2abeca2
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/src/nexusDataQueue.js
@@ -0,0 +1,33 @@
+/* exported NexusDataQueue */
+/* global NexusData */
+'use strict'
+
+class NexusDataQueue {
+ constructor() {
+ this._data = new Map()
+ }
+
+ push(nexusData) {
+ if (!(nexusData instanceof NexusData)) {
+ window.console.error('[NexusDataQueue] push: argument is not an instance of NexusData!')
+ }
+ this._data.set(nexusData.requestId, nexusData)
+ }
+
+ get(requestId) {
+ if (this._data.has(requestId)) {
+ return this._data.get(requestId)
+ }
+ return null
+ }
+
+ has(requestId) {
+ return this._data.has(requestId)
+ }
+
+ delete(requestId) {
+ if (this._data.has(requestId)) {
+ this._data.delete(requestId)
+ }
+ }
+}
diff --git a/2021/nexus-archive/browser-extension/src/nexusDataSender.js b/2021/nexus-archive/browser-extension/src/nexusDataSender.js
new file mode 100644
index 0000000..2d363fa
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/src/nexusDataSender.js
@@ -0,0 +1,52 @@
+/* exported NexusDataSender */
+/* global NexusData, Preferences */
+'use strict'
+
+class NexusDataSender {
+ constructor(preferences) {
+ if (!(preferences instanceof Preferences)) {
+ window.console.error('[NexusDataSender] constructor: argument is not an instance of Preferences!')
+ }
+ this._preferences = preferences
+ }
+
+ _formatDate(value) {
+ return value instanceof Date ? value.toISOString() : null
+ }
+
+ send(nexusData) {
+ if (!(nexusData instanceof NexusData)) {
+ window.console.error('[NexusDataSender] send: argument is not an instance of NexusData!')
+ }
+
+ if (false === this._preferences.isConfigured()) {
+ window.console.error('[NexusDataSender] send: preferences are not configured!')
+ return
+ }
+
+ const jsonData = {
+ requestStartedAt: this._formatDate(nexusData.requestStartedAt),
+ responseCompletedAt: this._formatDate(nexusData.responseCompletedAt),
+ method: nexusData.method,
+ url: nexusData.url,
+ formData: nexusData.formData,
+ responseBody: nexusData.responseBody,
+ }
+
+ const formData = new FormData()
+ formData.append('userAccessToken', this._preferences.userAccessToken)
+ formData.append('jsonData', JSON.stringify(jsonData, null, 2))
+
+ const fetchOptions = {
+ method: 'POST',
+ body: formData,
+ mode: 'no-cors',
+ }
+
+ window.fetch(this._preferences.trackerSubmitUrl, fetchOptions).catch(
+ error => {
+ window.console.error(`[NexusDataSender] Failed to send data: ${error}`)
+ }
+ )
+ }
+}
diff --git a/2021/nexus-archive/browser-extension/src/options.js b/2021/nexus-archive/browser-extension/src/options.js
new file mode 100644
index 0000000..7ae4946
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/src/options.js
@@ -0,0 +1,29 @@
+/* global Preferences */
+'use strict'
+
+const preferences = new Preferences()
+
+const getOptionsForm = () => document.getElementById('optionsForm')
+
+const saveForm = event => {
+ event.preventDefault()
+
+ const optionsForm = getOptionsForm()
+ preferences.userAccessToken = optionsForm.elements['userAccessToken'].value
+ preferences.trackerSubmitUrl = optionsForm.elements['trackerSubmitUrl'].value
+ preferences.save()
+}
+
+const initForm = () => {
+ const optionsForm = getOptionsForm()
+ optionsForm.addEventListener('submit', saveForm)
+
+ preferences.load().then(
+ () => {
+ optionsForm.elements['userAccessToken'].value = preferences.userAccessToken
+ optionsForm.elements['trackerSubmitUrl'].value = preferences.trackerSubmitUrl
+ }
+ )
+}
+
+document.addEventListener('DOMContentLoaded', initForm)
diff --git a/2021/nexus-archive/browser-extension/src/preferences.js b/2021/nexus-archive/browser-extension/src/preferences.js
new file mode 100644
index 0000000..fc704b3
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/src/preferences.js
@@ -0,0 +1,93 @@
+/* exported Preferences */
+'use strict'
+
+class Preferences {
+ constructor() {
+ this._userAccessToken = null
+ this._trackerSubmitUrl = null
+ }
+
+ get userAccessToken() {
+ return this._userAccessToken
+ }
+
+ set userAccessToken(value) {
+ this._userAccessToken = value
+ }
+
+ get trackerSubmitUrl() {
+ return this._trackerSubmitUrl
+ }
+
+ set trackerSubmitUrl(value) {
+ this._trackerSubmitUrl = value
+ }
+
+ get _storage() {
+ return browser.storage.sync
+ }
+
+ hasUserAccessToken() {
+ return null !== this._userAccessToken && 0 < this._userAccessToken.length
+ }
+
+ hasTrackerSubmitUrl() {
+ return null !== this._trackerSubmitUrl && 0 < this._trackerSubmitUrl.length
+ }
+
+ isConfigured() {
+ return this.hasUserAccessToken() && this.hasTrackerSubmitUrl()
+ }
+
+ load() {
+ const storageGetter = this._storage.get(null)
+
+ storageGetter.then(
+ results => {
+ if (Object.prototype.hasOwnProperty.call(results, 'userAccessToken')) {
+ this.userAccessToken = results.userAccessToken
+ }
+ if (Object.prototype.hasOwnProperty.call(results, 'trackerSubmitUrl')) {
+ this.trackerSubmitUrl = results.trackerSubmitUrl
+ }
+ },
+ error => {
+ const message = `Error loading preferences: ${error}`
+ window.console.error(message)
+ window.alert(message)
+ }
+ )
+
+ return storageGetter
+ }
+
+ save() {
+ const storageSetter = this._storage.set({
+ userAccessToken: this.userAccessToken,
+ trackerSubmitUrl: this.trackerSubmitUrl
+ })
+
+ storageSetter.catch(
+ error => {
+ const message = `Error saving preferences: ${error}`
+ window.console.error(message)
+ window.alert(message)
+ }
+ )
+
+ return storageSetter
+ }
+
+ listenForStorageChanges() {
+ browser.storage.onChanged.addListener((changes, areaName) => {
+ if ('sync' === areaName) {
+ if (Object.prototype.hasOwnProperty.call(changes, 'userAccessToken')) {
+ this.userAccessToken = changes.userAccessToken.newValue
+ }
+ if (Object.prototype.hasOwnProperty.call(changes, 'trackerSubmitUrl')) {
+ this.trackerSubmitUrl = changes.trackerSubmitUrl.newValue
+ }
+ }
+ })
+ }
+}
diff --git a/2021/nexus-archive/browser-extension/src/webRequestMonitor.js b/2021/nexus-archive/browser-extension/src/webRequestMonitor.js
new file mode 100644
index 0000000..05d75c3
--- /dev/null
+++ b/2021/nexus-archive/browser-extension/src/webRequestMonitor.js
@@ -0,0 +1,86 @@
+/* exported WebRequestMonitor */
+/* global NexusData, NexusDataQueue, NexusDataSender */
+'use strict'
+
+class WebRequestMonitor {
+ constructor(nexusDataQueue, nexusDataSender) {
+ if (!(nexusDataQueue instanceof NexusDataQueue)) {
+ window.console.error('[NexusDataSender] constructor: argument is not an instance of NexusDataQueue!')
+ }
+ if (!(nexusDataSender instanceof NexusDataSender)) {
+ window.console.error('[NexusDataSender] constructor: argument is not an instance of NexusDataSender!')
+ }
+ this._nexusDataQueue = nexusDataQueue
+ this._nexusDataSender = nexusDataSender
+ }
+
+ _attachResponseDataFilter(nexusData) {
+ const decoder = new TextDecoder('utf-8')
+ const encoder = new TextEncoder()
+ const responseDataFilter = browser.webRequest.filterResponseData(nexusData.requestId)
+ responseDataFilter.ondata = event => {
+ const bodyPart = decoder.decode(event.data, {stream: true})
+ responseDataFilter.write(encoder.encode(bodyPart))
+ nexusData.appendResponseBodyPart(bodyPart)
+ }
+ responseDataFilter.onstop = event => {
+ const bodyPart = decoder.decode(event.data, {stream: false})
+ responseDataFilter.write(encoder.encode(bodyPart))
+ responseDataFilter.close()
+ nexusData.appendResponseBodyPart(bodyPart)
+ }
+ }
+
+ _onBeforeRequest(details) {
+ const nexusData = new NexusData()
+ nexusData.requestId = details.requestId
+ nexusData.requestStartedAt = details.timeStamp
+ nexusData.method = details.method
+ nexusData.url = details.url
+ if (
+ null !== details.requestBody &&
+ Object.prototype.hasOwnProperty.call(details.requestBody, 'formData')
+ ) {
+ nexusData.formData = details.requestBody.formData
+ }
+ this._nexusDataQueue.push(nexusData)
+ this._attachResponseDataFilter(nexusData)
+ }
+
+ _onCompleted(details) {
+ const requestId = details.requestId
+ if (false !== this._nexusDataQueue.has(requestId)) {
+ const nexusData = this._nexusDataQueue.get(requestId)
+ nexusData.responseCompletedAt = details.timeStamp
+ this._nexusDataQueue.delete(requestId)
+ this._nexusDataSender.send(nexusData)
+ }
+ }
+
+ _onErrorOccurred(details) {
+ this._nexusDataQueue.delete(details.requestId)
+ window.console.error('[WebRequestMonitor] Error has occurred: ' + details.error)
+ }
+
+ addListeners() {
+ const requestFilters = {
+ types: ['main_frame'],
+ urls: [
+ '*://*.nexusclash.com/*'
+ ]
+ }
+ browser.webRequest.onBeforeRequest.addListener(
+ this._onBeforeRequest.bind(this),
+ requestFilters,
+ ['blocking', 'requestBody']
+ )
+ browser.webRequest.onCompleted.addListener(
+ this._onCompleted.bind(this),
+ requestFilters
+ )
+ browser.webRequest.onErrorOccurred.addListener(
+ this._onErrorOccurred.bind(this),
+ requestFilters
+ )
+ }
+}
diff --git a/2021/nexus-archive/website/.editorconfig b/2021/nexus-archive/website/.editorconfig
new file mode 100644
index 0000000..d430af2
--- /dev/null
+++ b/2021/nexus-archive/website/.editorconfig
@@ -0,0 +1,35 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = LF
+insert_final_newline = true
+trim_trailing_whitespace = true
+indent_style = space
+indent_size = 2
+
+[*.md]
+max_line_length = 80
+
+[*.html]
+indent_size = 4
+
+[*.php]
+# settings required by PSR-12 standard
+end_of_line = LF
+indent_style = space
+indent_size = 4
+max_line_length = 120
+
+[*.twig]
+indent_size = 4
+
+[*.yaml]
+indent_size = 4
+
+[README.md]
+max_line_length = 120
+
+[public/css/combined.css] # generated file
+insert_final_newline = unset
+max_line_length = unset
diff --git a/2021/nexus-archive/website/.env b/2021/nexus-archive/website/.env
new file mode 100644
index 0000000..cb11951
--- /dev/null
+++ b/2021/nexus-archive/website/.env
@@ -0,0 +1,12 @@
+# essential framework settings
+APP_ENV=dev
+APP_SECRET=
+APP_WORKER_PARSER_BATCH_SIZE=1
+APP_WORKER_PARSER_MAX_ITERATIONS=1
+APP_WORKER_PARSER_MAX_DURATION="1 second"
+
+# doctrine settings
+DATABASE_URL="postgresql://symfony:ChangeMe@127.0.0.1:5432/app?serverVersion=13&charset=utf8"
+
+# lock component settings
+LOCK_DSN=semaphore
diff --git a/2021/nexus-archive/website/.gitignore b/2021/nexus-archive/website/.gitignore
new file mode 100644
index 0000000..563e65c
--- /dev/null
+++ b/2021/nexus-archive/website/.gitignore
@@ -0,0 +1,8 @@
+/.env.local
+/.env.local.php
+/.env.*.local
+/config/secrets/prod/prod.decrypt.private.php
+/node_modules/
+/public/bundles/
+/var/
+/vendor/
diff --git a/2021/nexus-archive/website/CHANGELOG.md b/2021/nexus-archive/website/CHANGELOG.md
new file mode 100644
index 0000000..4d80e10
--- /dev/null
+++ b/2021/nexus-archive/website/CHANGELOG.md
@@ -0,0 +1,41 @@
+# Version 1.0.0
+
+- create interfaces and classes to represent leaderboard table as seen in game
+- create Doctrine entities to persist these leaderboard tables in database
+- implement general parser infrastructure to handle stored page views
+- implement parser for Breath 4 final leaderboards
+- implement a public page for browsing leaderboards
+- create and apply basic UI theme/styling, based on Tailwind CSS
+- some more internal code cleanups
+
+# Version 0.5.0
+
+- fix crash in token command on empty username input
+- create basic admin panel
+- convert all config files to PHP format
+- general code cleanup and refactoring
+- update installed dependencies to newer versions
+- update Symfony recipes metadata, port changes to appropriate files
+- start using Doctrine Migrations: create initial migration for existing tables
+
+# Version 0.4.0
+
+- remove unnecessary properties from NexusRawData
+
+# Version 0.3.0
+
+- remove NexusRequestLog entity and all related code (form, repository, etc)
+
+# Version 0.2.0
+
+- create new form to handle data format expected from browser extension
+
+# Version 0.1.1
+
+- fix parsing of JSON fields at cost of ignoring JSON syntax errors
+
+# Version 0.1.0
+
+- basic submit form to store request logs for further processing
+- primitive authentication via access tokens
+- simple console commands to create user accounts and access tokens
diff --git a/2021/nexus-archive/website/LICENSE.txt b/2021/nexus-archive/website/LICENSE.txt
new file mode 100644
index 0000000..4153cd3
--- /dev/null
+++ b/2021/nexus-archive/website/LICENSE.txt
@@ -0,0 +1,287 @@
+ EUROPEAN UNION PUBLIC LICENCE v. 1.2
+ EUPL © the European Union 2007, 2016
+
+This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined
+below) which is provided under the terms of this Licence. Any use of the Work,
+other than as authorised under this Licence is prohibited (to the extent such
+use is covered by a right of the copyright holder of the Work).
+
+The Work is provided under the terms of this Licence when the Licensor (as
+defined below) has placed the following notice immediately following the
+copyright notice for the Work:
+
+ Licensed under the EUPL
+
+or has expressed by any other means his willingness to license under the EUPL.
+
+1. Definitions
+
+In this Licence, the following terms have the following meaning:
+
+- ‘The Licence’: this Licence.
+
+- ‘The Original Work’: the work or software distributed or communicated by the
+ Licensor under this Licence, available as Source Code and also as Executable
+ Code as the case may be.
+
+- ‘Derivative Works’: the works or software that could be created by the
+ Licensee, based upon the Original Work or modifications thereof. This Licence
+ does not define the extent of modification or dependence on the Original Work
+ required in order to classify a work as a Derivative Work; this extent is
+ determined by copyright law applicable in the country mentioned in Article 15.
+
+- ‘The Work’: the Original Work or its Derivative Works.
+
+- ‘The Source Code’: the human-readable form of the Work which is the most
+ convenient for people to study and modify.
+
+- ‘The Executable Code’: any code which has generally been compiled and which is
+ meant to be interpreted by a computer as a program.
+
+- ‘The Licensor’: the natural or legal person that distributes or communicates
+ the Work under the Licence.
+
+- ‘Contributor(s)’: any natural or legal person who modifies the Work under the
+ Licence, or otherwise contributes to the creation of a Derivative Work.
+
+- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of
+ the Work under the terms of the Licence.
+
+- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending,
+ renting, distributing, communicating, transmitting, or otherwise making
+ available, online or offline, copies of the Work or providing access to its
+ essential functionalities at the disposal of any other natural or legal
+ person.
+
+2. Scope of the rights granted by the Licence
+
+The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
+sublicensable licence to do the following, for the duration of copyright vested
+in the Original Work:
+
+- use the Work in any circumstance and for all usage,
+- reproduce the Work,
+- modify the Work, and make Derivative Works based upon the Work,
+- communicate to the public, including the right to make available or display
+ the Work or copies thereof to the public and perform publicly, as the case may
+ be, the Work,
+- distribute the Work or copies thereof,
+- lend and rent the Work or copies thereof,
+- sublicense rights in the Work or copies thereof.
+
+Those rights can be exercised on any media, supports and formats, whether now
+known or later invented, as far as the applicable law permits so.
+
+In the countries where moral rights apply, the Licensor waives his right to
+exercise his moral right to the extent allowed by law in order to make effective
+the licence of the economic rights here above listed.
+
+The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to
+any patents held by the Licensor, to the extent necessary to make use of the
+rights granted on the Work under this Licence.
+
+3. Communication of the Source Code
+
+The Licensor may provide the Work either in its Source Code form, or as
+Executable Code. If the Work is provided as Executable Code, the Licensor
+provides in addition a machine-readable copy of the Source Code of the Work
+along with each copy of the Work that the Licensor distributes or indicates, in
+a notice following the copyright notice attached to the Work, a repository where
+the Source Code is easily and freely accessible for as long as the Licensor
+continues to distribute or communicate the Work.
+
+4. Limitations on copyright
+
+Nothing in this Licence is intended to deprive the Licensee of the benefits from
+any exception or limitation to the exclusive rights of the rights owners in the
+Work, of the exhaustion of those rights or of other applicable limitations
+thereto.
+
+5. Obligations of the Licensee
+
+The grant of the rights mentioned above is subject to some restrictions and
+obligations imposed on the Licensee. Those obligations are the following:
+
+Attribution right: The Licensee shall keep intact all copyright, patent or
+trademarks notices and all notices that refer to the Licence and to the
+disclaimer of warranties. The Licensee must include a copy of such notices and a
+copy of the Licence with every copy of the Work he/she distributes or
+communicates. The Licensee must cause any Derivative Work to carry prominent
+notices stating that the Work has been modified and the date of modification.
+
+Copyleft clause: If the Licensee distributes or communicates copies of the
+Original Works or Derivative Works, this Distribution or Communication will be
+done under the terms of this Licence or of a later version of this Licence
+unless the Original Work is expressly distributed only under this version of the
+Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee
+(becoming Licensor) cannot offer or impose any additional terms or conditions on
+the Work or Derivative Work that alter or restrict the terms of the Licence.
+
+Compatibility clause: If the Licensee Distributes or Communicates Derivative
+Works or copies thereof based upon both the Work and another work licensed under
+a Compatible Licence, this Distribution or Communication can be done under the
+terms of this Compatible Licence. For the sake of this clause, ‘Compatible
+Licence’ refers to the licences listed in the appendix attached to this Licence.
+Should the Licensee's obligations under the Compatible Licence conflict with
+his/her obligations under this Licence, the obligations of the Compatible
+Licence shall prevail.
+
+Provision of Source Code: When distributing or communicating copies of the Work,
+the Licensee will provide a machine-readable copy of the Source Code or indicate
+a repository where this Source will be easily and freely available for as long
+as the Licensee continues to distribute or communicate the Work.
+
+Legal Protection: This Licence does not grant permission to use the trade names,
+trademarks, service marks, or names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the copyright notice.
+
+6. Chain of Authorship
+
+The original Licensor warrants that the copyright in the Original Work granted
+hereunder is owned by him/her or licensed to him/her and that he/she has the
+power and authority to grant the Licence.
+
+Each Contributor warrants that the copyright in the modifications he/she brings
+to the Work are owned by him/her or licensed to him/her and that he/she has the
+power and authority to grant the Licence.
+
+Each time You accept the Licence, the original Licensor and subsequent
+Contributors grant You a licence to their contributions to the Work, under the
+terms of this Licence.
+
+7. Disclaimer of Warranty
+
+The Work is a work in progress, which is continuously improved by numerous
+Contributors. It is not a finished work and may therefore contain defects or
+‘bugs’ inherent to this type of development.
+
+For the above reason, the Work is provided under the Licence on an ‘as is’ basis
+and without warranties of any kind concerning the Work, including without
+limitation merchantability, fitness for a particular purpose, absence of defects
+or errors, accuracy, non-infringement of intellectual property rights other than
+copyright as stated in Article 6 of this Licence.
+
+This disclaimer of warranty is an essential part of the Licence and a condition
+for the grant of any rights to the Work.
+
+8. Disclaimer of Liability
+
+Except in the cases of wilful misconduct or damages directly caused to natural
+persons, the Licensor will in no event be liable for any direct or indirect,
+material or moral, damages of any kind, arising out of the Licence or of the use
+of the Work, including without limitation, damages for loss of goodwill, work
+stoppage, computer failure or malfunction, loss of data or any commercial
+damage, even if the Licensor has been advised of the possibility of such damage.
+However, the Licensor will be liable under statutory product liability laws as
+far such laws apply to the Work.
+
+9. Additional agreements
+
+While distributing the Work, You may choose to conclude an additional agreement,
+defining obligations or services consistent with this Licence. However, if
+accepting obligations, You may act only on your own behalf and on your sole
+responsibility, not on behalf of the original Licensor or any other Contributor,
+and only if You agree to indemnify, defend, and hold each Contributor harmless
+for any liability incurred by, or claims asserted against such Contributor by
+the fact You have accepted any warranty or additional liability.
+
+10. Acceptance of the Licence
+
+The provisions of this Licence can be accepted by clicking on an icon ‘I agree’
+placed under the bottom of a window displaying the text of this Licence or by
+affirming consent in any other similar way, in accordance with the rules of
+applicable law. Clicking on that icon indicates your clear and irrevocable
+acceptance of this Licence and all of its terms and conditions.
+
+Similarly, you irrevocably accept this Licence and all of its terms and
+conditions by exercising any rights granted to You by Article 2 of this Licence,
+such as the use of the Work, the creation by You of a Derivative Work or the
+Distribution or Communication by You of the Work or copies thereof.
+
+11. Information to the public
+
+In case of any Distribution or Communication of the Work by means of electronic
+communication by You (for example, by offering to download the Work from a
+remote location) the distribution channel or media (for example, a website) must
+at least provide to the public the information requested by the applicable law
+regarding the Licensor, the Licence and the way it may be accessible, concluded,
+stored and reproduced by the Licensee.
+
+12. Termination of the Licence
+
+The Licence and the rights granted hereunder will terminate automatically upon
+any breach by the Licensee of the terms of the Licence.
+
+Such a termination will not terminate the licences of any person who has
+received the Work from the Licensee under the Licence, provided such persons
+remain in full compliance with the Licence.
+
+13. Miscellaneous
+
+Without prejudice of Article 9 above, the Licence represents the complete
+agreement between the Parties as to the Work.
+
+If any provision of the Licence is invalid or unenforceable under applicable
+law, this will not affect the validity or enforceability of the Licence as a
+whole. Such provision will be construed or reformed so as necessary to make it
+valid and enforceable.
+
+The European Commission may publish other linguistic versions or new versions of
+this Licence or updated versions of the Appendix, so far this is required and
+reasonable, without reducing the scope of the rights granted by the Licence. New
+versions of the Licence will be published with a unique version number.
+
+All linguistic versions of this Licence, approved by the European Commission,
+have identical value. Parties can take advantage of the linguistic version of
+their choice.
+
+14. Jurisdiction
+
+Without prejudice to specific agreement between parties,
+
+- any litigation resulting from the interpretation of this License, arising
+ between the European Union institutions, bodies, offices or agencies, as a
+ Licensor, and any Licensee, will be subject to the jurisdiction of the Court
+ of Justice of the European Union, as laid down in article 272 of the Treaty on
+ the Functioning of the European Union,
+
+- any litigation arising between other parties and resulting from the
+ interpretation of this License, will be subject to the exclusive jurisdiction
+ of the competent court where the Licensor resides or conducts its primary
+ business.
+
+15. Applicable Law
+
+Without prejudice to specific agreement between parties,
+
+- this Licence shall be governed by the law of the European Union Member State
+ where the Licensor has his seat, resides or has his registered office,
+
+- this licence shall be governed by Belgian law if the Licensor has no seat,
+ residence or registered office inside a European Union Member State.
+
+Appendix
+
+‘Compatible Licences’ according to Article 5 EUPL are:
+
+- GNU General Public License (GPL) v. 2, v. 3
+- GNU Affero General Public License (AGPL) v. 3
+- Open Software License (OSL) v. 2.1, v. 3.0
+- Eclipse Public License (EPL) v. 1.0
+- CeCILL v. 2.0, v. 2.1
+- Mozilla Public Licence (MPL) v. 2
+- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
+- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
+ works other than software
+- European Union Public Licence (EUPL) v. 1.1, v. 1.2
+- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong
+ Reciprocity (LiLiQ-R+).
+
+The European Commission may update this Appendix to later versions of the above
+licences without producing a new version of the EUPL, as long as they provide
+the rights granted in Article 2 of this Licence and protect the covered Source
+Code from exclusive appropriation.
+
+All other changes or additions to this Appendix require the production of a new
+EUPL version.
diff --git a/2021/nexus-archive/website/README.md b/2021/nexus-archive/website/README.md
new file mode 100644
index 0000000..e9d27e1
--- /dev/null
+++ b/2021/nexus-archive/website/README.md
@@ -0,0 +1,77 @@
+# Nexus Archive
+
+The Nexus Archive website, based on Symfony framework.
+
+## Licence
+
+This project is licensed under [European Union Public Licence (EUPL)][EUPL].
+
+For convenience an English text of the licence is included
+in [LICENSE.txt](./LICENSE.txt) file.
+
+## Repositories
+
+Source code is primarily hosted
+on [my private Git server](https://git.zerozero.pl/nexus-archive), but for
+convenience and redundancy it is also mirrored to a few popular code hosting
+portals:
+
+- [Gitlab mirror](https://gitlab.com/krzysztof-sikorski/nexus-archive)
+- [GitHub mirror](https://github.com/krzysztof-sikorski/nexus-archive)
+- [Launchpad mirror](https://git.launchpad.net/nexus-archive)
+
+## Installation and deployment
+
+This is a standard Symfony-based web application, requiring only a standard
+software stack of:
+
+- an http server (e.g. Nginx)
+- PHP binaries and some standard extensions (
+ see [composer.json file](./composer.json) for details)
+- [Composer][Composer] tool (for fetching and installing third-party PHP
+ libraries)
+- a relational database server supporting SQL language (e.g. PostgreSQL)
+
+You can find some generic advice in Symfony documentation,
+in [installation][SymfonyInstallation]
+and [deployment][SymfonyDeployment] chapters.
+
+The application was only tested on PostgreSQL, but it should theoretically work
+on any database engine that is supported by Doctrine library.
+Check [Doctrine documentation][DoctrineVendors] for details.
+
+On Linux Mint (and probably also Ubuntu or Debian) you can use following
+commands to install required system packages:
+
+```shell
+sudo apt-get install php-cli php-fpm postgresql # basic packages
+sudo apt-get install php-xml php-mbstring php-intl php-xml # required or recommended by Symfony
+sudo apt-get install php-pgsql # required by application design
+```
+
+Remember to also configure periodic execution of following console commands
+(e.g. via cron jobs or systemd timers):
+
+- `bin/console app:worker:parser` for parsing submitted data
+- `bin/console app:worker:prune-database` for pruning unwanted rows from db
+
+## Development notes
+
+- some classes are loaded from `var\cache` directory, so you have to
+ execute `bin/console cache:warmup` to have them available for IDE
+ autocompletion
+
+[EUPL]:
+https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+
+[Composer]:
+https://getcomposer.org/
+
+[SymfonyInstallation]:
+https://symfony.com/doc/current/setup.html
+
+[SymfonyDeployment]:
+https://symfony.com/doc/current/deployment.html
+
+[DoctrineVendors]:
+https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/introduction.html
diff --git a/2021/nexus-archive/website/assets/PageViewSubmissionJsonSchema.json b/2021/nexus-archive/website/assets/PageViewSubmissionJsonSchema.json
new file mode 100644
index 0000000..eab5b6d
--- /dev/null
+++ b/2021/nexus-archive/website/assets/PageViewSubmissionJsonSchema.json
@@ -0,0 +1,45 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://nexus-archive.zerozero.pl/submit-json",
+ "type": "object",
+ "properties": {
+ "requestStartedAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "responseCompletedAt": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "method": {
+ "type": "string",
+ "enum": [
+ "GET",
+ "POST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "format": "uri"
+ },
+ "formData": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": true
+ },
+ "responseBody": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "requestStartedAt",
+ "responseCompletedAt",
+ "method",
+ "url",
+ "formData",
+ "responseBody"
+ ],
+ "additionalProperties": false
+}
diff --git a/2021/nexus-archive/website/assets/tailwindcss/input.css b/2021/nexus-archive/website/assets/tailwindcss/input.css
new file mode 100644
index 0000000..d76a936
--- /dev/null
+++ b/2021/nexus-archive/website/assets/tailwindcss/input.css
@@ -0,0 +1,65 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+a {
+ @apply tw-text-blue-900;
+}
+
+a[rel="external"]:after {
+ content: ' ↗';
+}
+
+button[type="submit"] {
+ @apply tw-px-4 tw-py-2 tw-font-bold tw-text-white tw-bg-black tw-rounded-lg;
+}
+
+body > * {
+ @apply tw-mx-8 tw-my-4;
+}
+
+header {
+ @apply tw-flex;
+}
+
+header a {
+ @apply tw-text-white;
+}
+
+header menu {
+ @apply tw-flex
+ tw-text-xl tw-font-bold tw-leading-loose
+ tw-text-white tw-bg-black
+ tw-border-solid tw-rounded-xl
+ tw-divide-x-4 tw-divide-dotted tw-divide-white
+ tw-shadow-lg;
+}
+
+header menu > li {
+ @apply tw-px-8 tw-py-2;
+}
+
+main h1 {
+ @apply tw-text-4xl tw-font-bold tw-leading-loose;
+}
+
+table {
+ @apply tw-my-4 tw-border-collapse;
+}
+
+table th, table td {
+ @apply tw-border-solid tw-border-2 tw-border-black tw-px-4 tw-py-2;
+}
+
+section.leaderboard-grid {
+ @apply tw-grid tw-gap-x-8 tw-gap-y-4
+ tw-grid-cols-1 md:tw-grid-cols-2 xl:tw-grid-cols-3;
+}
+
+section.leaderboard-grid caption {
+ @apply tw-text-lg tw-font-bold;
+}
+
+section.leaderboard-grid article.error {
+ @apply tw-my-4 tw-text-red-500 tw-text-lg tw-font-bold;
+}
diff --git a/2021/nexus-archive/website/bin/console b/2021/nexus-archive/website/bin/console
new file mode 100755
index 0000000..1196119
--- /dev/null
+++ b/2021/nexus-archive/website/bin/console
@@ -0,0 +1,18 @@
+#!/usr/bin/env php
+2.2,<2.4"
+ },
+ "require-dev": {
+ "cache/integration-tests": "dev-master",
+ "doctrine/coding-standard": "^9",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+ "psr/cache": "^1.0 || ^2.0 || ^3.0",
+ "symfony/cache": "^4.4 || ^5.4 || ^6",
+ "symfony/var-exporter": "^4.4 || ^5.4 || ^6"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com"
+ }
+ ],
+ "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.",
+ "homepage": "https://www.doctrine-project.org/projects/cache.html",
+ "keywords": [
+ "abstraction",
+ "apcu",
+ "cache",
+ "caching",
+ "couchdb",
+ "memcached",
+ "php",
+ "redis",
+ "xcache"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/cache/issues",
+ "source": "https://github.com/doctrine/cache/tree/2.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-05-20T20:07:39+00:00"
+ },
+ {
+ "name": "doctrine/collections",
+ "version": "2.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/collections.git",
+ "reference": "db8cda536a034337f7dd63febecc713d4957f9ee"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/collections/zipball/db8cda536a034337f7dd63febecc713d4957f9ee",
+ "reference": "db8cda536a034337f7dd63febecc713d4957f9ee",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/deprecations": "^1",
+ "php": "^8.1"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^10.0",
+ "ext-json": "*",
+ "phpstan/phpstan": "^1.8",
+ "phpstan/phpstan-phpunit": "^1.0",
+ "phpunit/phpunit": "^9.5",
+ "vimeo/psalm": "^4.22"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Common\\Collections\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com"
+ }
+ ],
+ "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.",
+ "homepage": "https://www.doctrine-project.org/projects/collections.html",
+ "keywords": [
+ "array",
+ "collections",
+ "iterators",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/collections/issues",
+ "source": "https://github.com/doctrine/collections/tree/2.1.2"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcollections",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-12-27T23:41:38+00:00"
+ },
+ {
+ "name": "doctrine/common",
+ "version": "3.4.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/common.git",
+ "reference": "8b5e5650391f851ed58910b3e3d48a71062eeced"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/common/zipball/8b5e5650391f851ed58910b3e3d48a71062eeced",
+ "reference": "8b5e5650391f851ed58910b3e3d48a71062eeced",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/persistence": "^2.0 || ^3.0",
+ "php": "^7.1 || ^8.0"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^9.0 || ^10.0",
+ "doctrine/collections": "^1",
+ "phpstan/phpstan": "^1.4.1",
+ "phpstan/phpstan-phpunit": "^1",
+ "phpunit/phpunit": "^7.5.20 || ^8.5 || ^9.0",
+ "squizlabs/php_codesniffer": "^3.0",
+ "symfony/phpunit-bridge": "^6.1",
+ "vimeo/psalm": "^4.4"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Common\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com"
+ },
+ {
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com"
+ }
+ ],
+ "description": "PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, proxies and much more.",
+ "homepage": "https://www.doctrine-project.org/projects/common.html",
+ "keywords": [
+ "common",
+ "doctrine",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/common/issues",
+ "source": "https://github.com/doctrine/common/tree/3.4.3"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcommon",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-10-09T11:47:59+00:00"
+ },
+ {
+ "name": "doctrine/dbal",
+ "version": "3.6.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/dbal.git",
+ "reference": "57815c7bbcda3cd18871d253c1dd8cbe56f8526e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/dbal/zipball/57815c7bbcda3cd18871d253c1dd8cbe56f8526e",
+ "reference": "57815c7bbcda3cd18871d253c1dd8cbe56f8526e",
+ "shasum": ""
+ },
+ "require": {
+ "composer-runtime-api": "^2",
+ "doctrine/cache": "^1.11|^2.0",
+ "doctrine/deprecations": "^0.5.3|^1",
+ "doctrine/event-manager": "^1|^2",
+ "php": "^7.4 || ^8.0",
+ "psr/cache": "^1|^2|^3",
+ "psr/log": "^1|^2|^3"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "11.1.0",
+ "fig/log-test": "^1",
+ "jetbrains/phpstorm-stubs": "2022.3",
+ "phpstan/phpstan": "1.10.3",
+ "phpstan/phpstan-strict-rules": "^1.5",
+ "phpunit/phpunit": "9.6.4",
+ "psalm/plugin-phpunit": "0.18.4",
+ "squizlabs/php_codesniffer": "3.7.2",
+ "symfony/cache": "^5.4|^6.0",
+ "symfony/console": "^4.4|^5.4|^6.0",
+ "vimeo/psalm": "4.30.0"
+ },
+ "suggest": {
+ "symfony/console": "For helpful console commands such as SQL execution and import of files."
+ },
+ "bin": [
+ "bin/doctrine-dbal"
+ ],
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\DBAL\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ }
+ ],
+ "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
+ "homepage": "https://www.doctrine-project.org/projects/dbal.html",
+ "keywords": [
+ "abstraction",
+ "database",
+ "db2",
+ "dbal",
+ "mariadb",
+ "mssql",
+ "mysql",
+ "oci8",
+ "oracle",
+ "pdo",
+ "pgsql",
+ "postgresql",
+ "queryobject",
+ "sasql",
+ "sql",
+ "sqlite",
+ "sqlserver",
+ "sqlsrv"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/dbal/issues",
+ "source": "https://github.com/doctrine/dbal/tree/3.6.1"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-03-02T19:26:24+00:00"
+ },
+ {
+ "name": "doctrine/deprecations",
+ "version": "v1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/deprecations.git",
+ "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
+ "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1|^8.0"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^9",
+ "phpunit/phpunit": "^7.5|^8.5|^9.5",
+ "psr/log": "^1|^2|^3"
+ },
+ "suggest": {
+ "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
+ "homepage": "https://www.doctrine-project.org/",
+ "support": {
+ "issues": "https://github.com/doctrine/deprecations/issues",
+ "source": "https://github.com/doctrine/deprecations/tree/v1.0.0"
+ },
+ "time": "2022-05-02T15:47:09+00:00"
+ },
+ {
+ "name": "doctrine/doctrine-bundle",
+ "version": "2.8.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/DoctrineBundle.git",
+ "reference": "fd67ba64db3c806f626a33dcab15a4db0c77652e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/fd67ba64db3c806f626a33dcab15a4db0c77652e",
+ "reference": "fd67ba64db3c806f626a33dcab15a4db0c77652e",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/cache": "^1.11 || ^2.0",
+ "doctrine/dbal": "^3.4.0",
+ "doctrine/persistence": "^2.2 || ^3",
+ "doctrine/sql-formatter": "^1.0.1",
+ "php": "^7.4 || ^8.0",
+ "symfony/cache": "^5.4 || ^6.0",
+ "symfony/config": "^5.4 || ^6.0",
+ "symfony/console": "^5.4 || ^6.0",
+ "symfony/dependency-injection": "^5.4 || ^6.0",
+ "symfony/deprecation-contracts": "^2.1 || ^3",
+ "symfony/doctrine-bridge": "^5.4.19 || ^6.0.7",
+ "symfony/framework-bundle": "^5.4 || ^6.0",
+ "symfony/service-contracts": "^1.1.1 || ^2.0 || ^3"
+ },
+ "conflict": {
+ "doctrine/annotations": ">=3.0",
+ "doctrine/orm": "<2.11 || >=3.0",
+ "twig/twig": "<1.34 || >=2.0,<2.4"
+ },
+ "require-dev": {
+ "doctrine/annotations": "^1 || ^2",
+ "doctrine/coding-standard": "^9.0",
+ "doctrine/orm": "^2.11 || ^3.0",
+ "friendsofphp/proxy-manager-lts": "^1.0",
+ "phpunit/phpunit": "^9.5.26 || ^10.0",
+ "psalm/plugin-phpunit": "^0.18.4",
+ "psalm/plugin-symfony": "^4",
+ "psr/log": "^1.1.4 || ^2.0 || ^3.0",
+ "symfony/phpunit-bridge": "^6.1",
+ "symfony/property-info": "^5.4 || ^6.0",
+ "symfony/proxy-manager-bridge": "^5.4 || ^6.0",
+ "symfony/security-bundle": "^5.4 || ^6.0",
+ "symfony/twig-bridge": "^5.4 || ^6.0",
+ "symfony/validator": "^5.4 || ^6.0",
+ "symfony/web-profiler-bundle": "^5.4 || ^6.0",
+ "symfony/yaml": "^5.4 || ^6.0",
+ "twig/twig": "^1.34 || ^2.12 || ^3.0",
+ "vimeo/psalm": "^4.30"
+ },
+ "suggest": {
+ "doctrine/orm": "The Doctrine ORM integration is optional in the bundle.",
+ "ext-pdo": "*",
+ "symfony/web-profiler-bundle": "To use the data collector."
+ },
+ "type": "symfony-bundle",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Bundle\\DoctrineBundle\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ },
+ {
+ "name": "Doctrine Project",
+ "homepage": "https://www.doctrine-project.org/"
+ }
+ ],
+ "description": "Symfony DoctrineBundle",
+ "homepage": "https://www.doctrine-project.org",
+ "keywords": [
+ "database",
+ "dbal",
+ "orm",
+ "persistence"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/DoctrineBundle/issues",
+ "source": "https://github.com/doctrine/DoctrineBundle/tree/2.8.3"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdoctrine-bundle",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-02-03T09:32:42+00:00"
+ },
+ {
+ "name": "doctrine/doctrine-migrations-bundle",
+ "version": "3.2.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/DoctrineMigrationsBundle.git",
+ "reference": "3393f411ba25ade21969c33f2053220044854d01"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/3393f411ba25ade21969c33f2053220044854d01",
+ "reference": "3393f411ba25ade21969c33f2053220044854d01",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/doctrine-bundle": "~1.0|~2.0",
+ "doctrine/migrations": "^3.2",
+ "php": "^7.2|^8.0",
+ "symfony/framework-bundle": "~3.4|~4.0|~5.0|~6.0"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^8.0",
+ "doctrine/orm": "^2.6",
+ "doctrine/persistence": "^1.3||^2.0",
+ "phpstan/phpstan": "^0.12",
+ "phpstan/phpstan-deprecation-rules": "^0.12",
+ "phpstan/phpstan-phpunit": "^0.12",
+ "phpstan/phpstan-strict-rules": "^0.12",
+ "phpunit/phpunit": "^8.0|^9.0",
+ "vimeo/psalm": "^4.11"
+ },
+ "type": "symfony-bundle",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Bundle\\MigrationsBundle\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Doctrine Project",
+ "homepage": "https://www.doctrine-project.org"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony DoctrineMigrationsBundle",
+ "homepage": "https://www.doctrine-project.org",
+ "keywords": [
+ "dbal",
+ "migrations",
+ "schema"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/DoctrineMigrationsBundle/issues",
+ "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/3.2.2"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdoctrine-migrations-bundle",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-02-01T18:08:07+00:00"
+ },
+ {
+ "name": "doctrine/event-manager",
+ "version": "2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/event-manager.git",
+ "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/event-manager/zipball/750671534e0241a7c50ea5b43f67e23eb5c96f32",
+ "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^8.1"
+ },
+ "conflict": {
+ "doctrine/common": "<2.9"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^10",
+ "phpstan/phpstan": "^1.8.8",
+ "phpunit/phpunit": "^9.5",
+ "vimeo/psalm": "^4.28"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Common\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com"
+ },
+ {
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com"
+ }
+ ],
+ "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.",
+ "homepage": "https://www.doctrine-project.org/projects/event-manager.html",
+ "keywords": [
+ "event",
+ "event dispatcher",
+ "event manager",
+ "event system",
+ "events"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/event-manager/issues",
+ "source": "https://github.com/doctrine/event-manager/tree/2.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-10-12T20:59:15+00:00"
+ },
+ {
+ "name": "doctrine/inflector",
+ "version": "2.0.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/inflector.git",
+ "reference": "d9d313a36c872fd6ee06d9a6cbcf713eaa40f024"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/inflector/zipball/d9d313a36c872fd6ee06d9a6cbcf713eaa40f024",
+ "reference": "d9d313a36c872fd6ee06d9a6cbcf713eaa40f024",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^10",
+ "phpstan/phpstan": "^1.8",
+ "phpstan/phpstan-phpunit": "^1.1",
+ "phpstan/phpstan-strict-rules": "^1.3",
+ "phpunit/phpunit": "^8.5 || ^9.5",
+ "vimeo/psalm": "^4.25"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Inflector\\": "lib/Doctrine/Inflector"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com"
+ }
+ ],
+ "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.",
+ "homepage": "https://www.doctrine-project.org/projects/inflector.html",
+ "keywords": [
+ "inflection",
+ "inflector",
+ "lowercase",
+ "manipulation",
+ "php",
+ "plural",
+ "singular",
+ "strings",
+ "uppercase",
+ "words"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/inflector/issues",
+ "source": "https://github.com/doctrine/inflector/tree/2.0.6"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-10-20T09:10:12+00:00"
+ },
+ {
+ "name": "doctrine/instantiator",
+ "version": "1.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/instantiator.git",
+ "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b",
+ "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^9 || ^11",
+ "ext-pdo": "*",
+ "ext-phar": "*",
+ "phpbench/phpbench": "^0.16 || ^1",
+ "phpstan/phpstan": "^1.4",
+ "phpstan/phpstan-phpunit": "^1",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+ "vimeo/psalm": "^4.30 || ^5.4"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com",
+ "homepage": "https://ocramius.github.io/"
+ }
+ ],
+ "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
+ "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
+ "keywords": [
+ "constructor",
+ "instantiate"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/instantiator/issues",
+ "source": "https://github.com/doctrine/instantiator/tree/1.5.0"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-12-30T00:15:36+00:00"
+ },
+ {
+ "name": "doctrine/lexer",
+ "version": "2.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/lexer.git",
+ "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124",
+ "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/deprecations": "^1.0",
+ "php": "^7.1 || ^8.0"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^9 || ^10",
+ "phpstan/phpstan": "^1.3",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+ "psalm/plugin-phpunit": "^0.18.3",
+ "vimeo/psalm": "^4.11 || ^5.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Common\\Lexer\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com"
+ }
+ ],
+ "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
+ "homepage": "https://www.doctrine-project.org/projects/lexer.html",
+ "keywords": [
+ "annotations",
+ "docblock",
+ "lexer",
+ "parser",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/lexer/issues",
+ "source": "https://github.com/doctrine/lexer/tree/2.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-12-14T08:49:07+00:00"
+ },
+ {
+ "name": "doctrine/migrations",
+ "version": "3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/migrations.git",
+ "reference": "e542ad8bcd606d7a18d0875babb8a6d963c9c059"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/migrations/zipball/e542ad8bcd606d7a18d0875babb8a6d963c9c059",
+ "reference": "e542ad8bcd606d7a18d0875babb8a6d963c9c059",
+ "shasum": ""
+ },
+ "require": {
+ "composer-runtime-api": "^2",
+ "doctrine/dbal": "^3.5.1",
+ "doctrine/deprecations": "^0.5.3 || ^1",
+ "doctrine/event-manager": "^1.2 || ^2.0",
+ "php": "^8.1",
+ "psr/log": "^1.1.3 || ^2 || ^3",
+ "symfony/console": "^4.4.16 || ^5.4 || ^6.0",
+ "symfony/stopwatch": "^4.4 || ^5.4 || ^6.0",
+ "symfony/var-exporter": "^6.2"
+ },
+ "conflict": {
+ "doctrine/orm": "<2.12"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^9",
+ "doctrine/orm": "^2.13",
+ "doctrine/persistence": "^2 || ^3",
+ "doctrine/sql-formatter": "^1.0",
+ "ext-pdo_sqlite": "*",
+ "phpstan/phpstan": "^1.5",
+ "phpstan/phpstan-deprecation-rules": "^1",
+ "phpstan/phpstan-phpunit": "^1.1",
+ "phpstan/phpstan-strict-rules": "^1.1",
+ "phpstan/phpstan-symfony": "^1.1",
+ "phpunit/phpunit": "^9.5.24",
+ "symfony/cache": "^4.4 || ^5.4 || ^6.0",
+ "symfony/process": "^4.4 || ^5.4 || ^6.0",
+ "symfony/yaml": "^4.4 || ^5.4 || ^6.0"
+ },
+ "suggest": {
+ "doctrine/sql-formatter": "Allows to generate formatted SQL with the diff command.",
+ "symfony/yaml": "Allows the use of yaml for migration configuration files."
+ },
+ "bin": [
+ "bin/doctrine-migrations"
+ ],
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Migrations\\": "lib/Doctrine/Migrations"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ },
+ {
+ "name": "Michael Simonson",
+ "email": "contact@mikesimonson.com"
+ }
+ ],
+ "description": "PHP Doctrine Migrations project offer additional functionality on top of the database abstraction layer (DBAL) for versioning your database schema and easily deploying changes to it. It is a very easy to use and a powerful tool.",
+ "homepage": "https://www.doctrine-project.org/projects/migrations.html",
+ "keywords": [
+ "database",
+ "dbal",
+ "migrations"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/migrations/issues",
+ "source": "https://github.com/doctrine/migrations/tree/3.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fmigrations",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-02-15T18:49:46+00:00"
+ },
+ {
+ "name": "doctrine/orm",
+ "version": "2.14.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/orm.git",
+ "reference": "de7eee5ed7b1b35c99b118f26f210a8281e6db8e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/orm/zipball/de7eee5ed7b1b35c99b118f26f210a8281e6db8e",
+ "reference": "de7eee5ed7b1b35c99b118f26f210a8281e6db8e",
+ "shasum": ""
+ },
+ "require": {
+ "composer-runtime-api": "^2",
+ "doctrine/cache": "^1.12.1 || ^2.1.1",
+ "doctrine/collections": "^1.5 || ^2.0",
+ "doctrine/common": "^3.0.3",
+ "doctrine/dbal": "^2.13.1 || ^3.2",
+ "doctrine/deprecations": "^0.5.3 || ^1",
+ "doctrine/event-manager": "^1.2 || ^2",
+ "doctrine/inflector": "^1.4 || ^2.0",
+ "doctrine/instantiator": "^1.3",
+ "doctrine/lexer": "^1.2.3 || ^2",
+ "doctrine/persistence": "^2.4 || ^3",
+ "ext-ctype": "*",
+ "php": "^7.1 || ^8.0",
+ "psr/cache": "^1 || ^2 || ^3",
+ "symfony/console": "^4.2 || ^5.0 || ^6.0",
+ "symfony/polyfill-php72": "^1.23",
+ "symfony/polyfill-php80": "^1.16"
+ },
+ "conflict": {
+ "doctrine/annotations": "<1.13 || >= 3.0"
+ },
+ "require-dev": {
+ "doctrine/annotations": "^1.13 || ^2",
+ "doctrine/coding-standard": "^9.0.2 || ^11.0",
+ "phpbench/phpbench": "^0.16.10 || ^1.0",
+ "phpstan/phpstan": "~1.4.10 || 1.9.8",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+ "psr/log": "^1 || ^2 || ^3",
+ "squizlabs/php_codesniffer": "3.7.1",
+ "symfony/cache": "^4.4 || ^5.4 || ^6.0",
+ "symfony/var-exporter": "^4.4 || ^5.4 || ^6.2",
+ "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0",
+ "vimeo/psalm": "4.30.0 || 5.4.0"
+ },
+ "suggest": {
+ "ext-dom": "Provides support for XSD validation for XML mapping files",
+ "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0",
+ "symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
+ },
+ "bin": [
+ "bin/doctrine"
+ ],
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\ORM\\": "lib/Doctrine/ORM"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ },
+ {
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com"
+ }
+ ],
+ "description": "Object-Relational-Mapper for PHP",
+ "homepage": "https://www.doctrine-project.org/projects/orm.html",
+ "keywords": [
+ "database",
+ "orm"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/orm/issues",
+ "source": "https://github.com/doctrine/orm/tree/2.14.1"
+ },
+ "time": "2023-01-16T18:36:59+00:00"
+ },
+ {
+ "name": "doctrine/persistence",
+ "version": "3.1.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/persistence.git",
+ "reference": "8bf8ab15960787f1a49d405f6eb8c787b4841119"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/persistence/zipball/8bf8ab15960787f1a49d405f6eb8c787b4841119",
+ "reference": "8bf8ab15960787f1a49d405f6eb8c787b4841119",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/event-manager": "^1 || ^2",
+ "php": "^7.2 || ^8.0",
+ "psr/cache": "^1.0 || ^2.0 || ^3.0"
+ },
+ "conflict": {
+ "doctrine/common": "<2.10"
+ },
+ "require-dev": {
+ "composer/package-versions-deprecated": "^1.11",
+ "doctrine/coding-standard": "^11",
+ "doctrine/common": "^3.0",
+ "phpstan/phpstan": "1.9.4",
+ "phpstan/phpstan-phpunit": "^1",
+ "phpstan/phpstan-strict-rules": "^1.1",
+ "phpunit/phpunit": "^8.5 || ^9.5",
+ "symfony/cache": "^4.4 || ^5.4 || ^6.0",
+ "vimeo/psalm": "4.30.0 || 5.3.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Persistence\\": "src/Persistence"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com"
+ },
+ {
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com"
+ }
+ ],
+ "description": "The Doctrine Persistence project is a set of shared interfaces and functionality that the different Doctrine object mappers share.",
+ "homepage": "https://www.doctrine-project.org/projects/persistence.html",
+ "keywords": [
+ "mapper",
+ "object",
+ "odm",
+ "orm",
+ "persistence"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/persistence/issues",
+ "source": "https://github.com/doctrine/persistence/tree/3.1.4"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fpersistence",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-02-03T11:13:07+00:00"
+ },
+ {
+ "name": "doctrine/sql-formatter",
+ "version": "1.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/sql-formatter.git",
+ "reference": "25a06c7bf4c6b8218f47928654252863ffc890a5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/25a06c7bf4c6b8218f47928654252863ffc890a5",
+ "reference": "25a06c7bf4c6b8218f47928654252863ffc890a5",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.4"
+ },
+ "bin": [
+ "bin/sql-formatter"
+ ],
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\SqlFormatter\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jeremy Dorn",
+ "email": "jeremy@jeremydorn.com",
+ "homepage": "https://jeremydorn.com/"
+ }
+ ],
+ "description": "a PHP SQL highlighting library",
+ "homepage": "https://github.com/doctrine/sql-formatter/",
+ "keywords": [
+ "highlight",
+ "sql"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/sql-formatter/issues",
+ "source": "https://github.com/doctrine/sql-formatter/tree/1.1.3"
+ },
+ "time": "2022-05-23T21:33:49+00:00"
+ },
+ {
+ "name": "easycorp/easyadmin-bundle",
+ "version": "v4.6.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/EasyCorp/EasyAdminBundle.git",
+ "reference": "340548d93c2f6a732a71a528668fdf155d4a2f25"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/EasyCorp/EasyAdminBundle/zipball/340548d93c2f6a732a71a528668fdf155d4a2f25",
+ "reference": "340548d93c2f6a732a71a528668fdf155d4a2f25",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/doctrine-bundle": "^2.5",
+ "doctrine/orm": "^2.10",
+ "ext-json": "*",
+ "php": ">=8.0.2",
+ "symfony/asset": "^5.4|^6.0",
+ "symfony/cache": "^5.4|^6.0",
+ "symfony/config": "^5.4|^6.0",
+ "symfony/dependency-injection": "^5.4|^6.0",
+ "symfony/deprecation-contracts": "^3.0",
+ "symfony/doctrine-bridge": "^5.4|^6.0",
+ "symfony/event-dispatcher": "^5.4|^6.0",
+ "symfony/filesystem": "^5.4|^6.0",
+ "symfony/form": "^5.4|^6.0",
+ "symfony/framework-bundle": "^5.4|^6.0",
+ "symfony/http-foundation": "^5.4|^6.0",
+ "symfony/http-kernel": "^5.4|^6.0",
+ "symfony/intl": "^5.4|^6.0",
+ "symfony/property-access": "^5.4|^6.0",
+ "symfony/security-bundle": "^5.4|^6.0",
+ "symfony/string": "^5.4|^6.0",
+ "symfony/translation": "^5.4|^6.0",
+ "symfony/twig-bundle": "^5.4|^6.0",
+ "symfony/uid": "^5.4|^6.0",
+ "symfony/validator": "^5.4|^6.0"
+ },
+ "require-dev": {
+ "doctrine/doctrine-fixtures-bundle": "^3.4",
+ "phpstan/extension-installer": "^1.2",
+ "phpstan/phpstan": "^1.9",
+ "phpstan/phpstan-phpunit": "^1.2",
+ "phpstan/phpstan-strict-rules": "^1.4",
+ "phpstan/phpstan-symfony": "^1.2",
+ "psr/log": "^1.0",
+ "symfony/browser-kit": "^5.4|^6.0",
+ "symfony/css-selector": "^5.4|^6.0",
+ "symfony/dom-crawler": "^5.4|^6.0",
+ "symfony/phpunit-bridge": "^5.4|^6.0"
+ },
+ "type": "symfony-bundle",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "EasyCorp\\Bundle\\EasyAdminBundle\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Project Contributors",
+ "homepage": "https://github.com/EasyCorp/EasyAdminBundle/graphs/contributors"
+ }
+ ],
+ "description": "Admin generator for Symfony applications",
+ "homepage": "https://github.com/EasyCorp/EasyAdminBundle",
+ "keywords": [
+ "admin",
+ "backend",
+ "generator"
+ ],
+ "support": {
+ "issues": "https://github.com/EasyCorp/EasyAdminBundle/issues",
+ "source": "https://github.com/EasyCorp/EasyAdminBundle/tree/v4.6.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/javiereguiluz",
+ "type": "github"
+ }
+ ],
+ "time": "2023-03-12T10:16:10+00:00"
+ },
+ {
+ "name": "friendsofphp/proxy-manager-lts",
+ "version": "v1.0.14",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/FriendsOfPHP/proxy-manager-lts.git",
+ "reference": "a527c9d9d5348e012bd24482d83a5cd643bcbc9e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/FriendsOfPHP/proxy-manager-lts/zipball/a527c9d9d5348e012bd24482d83a5cd643bcbc9e",
+ "reference": "a527c9d9d5348e012bd24482d83a5cd643bcbc9e",
+ "shasum": ""
+ },
+ "require": {
+ "laminas/laminas-code": "~3.4.1|^4.0",
+ "php": ">=7.1",
+ "symfony/filesystem": "^4.4.17|^5.0|^6.0"
+ },
+ "conflict": {
+ "laminas/laminas-stdlib": "<3.2.1",
+ "zendframework/zend-stdlib": "<3.2.1"
+ },
+ "replace": {
+ "ocramius/proxy-manager": "^2.1"
+ },
+ "require-dev": {
+ "ext-phar": "*",
+ "symfony/phpunit-bridge": "^5.4|^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "name": "ocramius/proxy-manager",
+ "url": "https://github.com/Ocramius/ProxyManager"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "ProxyManager\\": "src/ProxyManager"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com",
+ "homepage": "https://ocramius.github.io/"
+ },
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ }
+ ],
+ "description": "Adding support for a wider range of PHP versions to ocramius/proxy-manager",
+ "homepage": "https://github.com/FriendsOfPHP/proxy-manager-lts",
+ "keywords": [
+ "aop",
+ "lazy loading",
+ "proxy",
+ "proxy pattern",
+ "service proxies"
+ ],
+ "support": {
+ "issues": "https://github.com/FriendsOfPHP/proxy-manager-lts/issues",
+ "source": "https://github.com/FriendsOfPHP/proxy-manager-lts/tree/v1.0.14"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/Ocramius",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/ocramius/proxy-manager",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-30T10:40:19+00:00"
+ },
+ {
+ "name": "laminas/laminas-code",
+ "version": "4.10.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laminas/laminas-code.git",
+ "reference": "ad8b36073f9ac792716478befadca0798cc15635"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laminas/laminas-code/zipball/ad8b36073f9ac792716478befadca0798cc15635",
+ "reference": "ad8b36073f9ac792716478befadca0798cc15635",
+ "shasum": ""
+ },
+ "require": {
+ "php": "~8.1.0 || ~8.2.0"
+ },
+ "require-dev": {
+ "doctrine/annotations": "^2.0.0",
+ "ext-phar": "*",
+ "laminas/laminas-coding-standard": "^2.3.0",
+ "laminas/laminas-stdlib": "^3.6.1",
+ "phpunit/phpunit": "^10.0.9",
+ "psalm/plugin-phpunit": "^0.18.4",
+ "vimeo/psalm": "^5.7.1"
+ },
+ "suggest": {
+ "doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features",
+ "laminas/laminas-stdlib": "Laminas\\Stdlib component"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Laminas\\Code\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Extensions to the PHP Reflection API, static code scanning, and code generation",
+ "homepage": "https://laminas.dev",
+ "keywords": [
+ "code",
+ "laminas",
+ "laminasframework"
+ ],
+ "support": {
+ "chat": "https://laminas.dev/chat",
+ "docs": "https://docs.laminas.dev/laminas-code/",
+ "forum": "https://discourse.laminas.dev",
+ "issues": "https://github.com/laminas/laminas-code/issues",
+ "rss": "https://github.com/laminas/laminas-code/releases.atom",
+ "source": "https://github.com/laminas/laminas-code"
+ },
+ "funding": [
+ {
+ "url": "https://funding.communitybridge.org/projects/laminas-project",
+ "type": "community_bridge"
+ }
+ ],
+ "time": "2023-03-08T11:55:01+00:00"
+ },
+ {
+ "name": "monolog/monolog",
+ "version": "2.9.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Seldaek/monolog.git",
+ "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1",
+ "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2",
+ "psr/log": "^1.0.1 || ^2.0 || ^3.0"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0"
+ },
+ "require-dev": {
+ "aws/aws-sdk-php": "^2.4.9 || ^3.0",
+ "doctrine/couchdb": "~1.0@dev",
+ "elasticsearch/elasticsearch": "^7 || ^8",
+ "ext-json": "*",
+ "graylog2/gelf-php": "^1.4.2 || ^2@dev",
+ "guzzlehttp/guzzle": "^7.4",
+ "guzzlehttp/psr7": "^2.2",
+ "mongodb/mongodb": "^1.8",
+ "php-amqplib/php-amqplib": "~2.4 || ^3",
+ "phpspec/prophecy": "^1.15",
+ "phpstan/phpstan": "^0.12.91",
+ "phpunit/phpunit": "^8.5.14",
+ "predis/predis": "^1.1 || ^2.0",
+ "rollbar/rollbar": "^1.3 || ^2 || ^3",
+ "ruflin/elastica": "^7",
+ "swiftmailer/swiftmailer": "^5.3|^6.0",
+ "symfony/mailer": "^5.4 || ^6",
+ "symfony/mime": "^5.4 || ^6"
+ },
+ "suggest": {
+ "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
+ "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
+ "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client",
+ "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
+ "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler",
+ "ext-mbstring": "Allow to work properly with unicode symbols",
+ "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)",
+ "ext-openssl": "Required to send log messages using SSL",
+ "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)",
+ "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
+ "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)",
+ "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
+ "rollbar/rollbar": "Allow sending log messages to Rollbar",
+ "ruflin/elastica": "Allow sending log messages to an Elastic Search server"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Monolog\\": "src/Monolog"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "https://seld.be"
+ }
+ ],
+ "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
+ "homepage": "https://github.com/Seldaek/monolog",
+ "keywords": [
+ "log",
+ "logging",
+ "psr-3"
+ ],
+ "support": {
+ "issues": "https://github.com/Seldaek/monolog/issues",
+ "source": "https://github.com/Seldaek/monolog/tree/2.9.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/Seldaek",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-02-06T13:44:46+00:00"
+ },
+ {
+ "name": "opis/json-schema",
+ "version": "2.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/opis/json-schema.git",
+ "reference": "c48df6d7089a45f01e1c82432348f2d5976f9bfb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/opis/json-schema/zipball/c48df6d7089a45f01e1c82432348f2d5976f9bfb",
+ "reference": "c48df6d7089a45f01e1c82432348f2d5976f9bfb",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "opis/string": "^2.0",
+ "opis/uri": "^1.0",
+ "php": "^7.4 || ^8.0"
+ },
+ "require-dev": {
+ "ext-bcmath": "*",
+ "ext-intl": "*",
+ "phpunit/phpunit": "^9.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Opis\\JsonSchema\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Sorin Sarca",
+ "email": "sarca_sorin@hotmail.com"
+ },
+ {
+ "name": "Marius Sarca",
+ "email": "marius.sarca@gmail.com"
+ }
+ ],
+ "description": "Json Schema Validator for PHP",
+ "homepage": "https://opis.io/json-schema",
+ "keywords": [
+ "json",
+ "json-schema",
+ "schema",
+ "validation",
+ "validator"
+ ],
+ "support": {
+ "issues": "https://github.com/opis/json-schema/issues",
+ "source": "https://github.com/opis/json-schema/tree/2.3.0"
+ },
+ "time": "2022-01-08T20:38:03+00:00"
+ },
+ {
+ "name": "opis/string",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/opis/string.git",
+ "reference": "9ebf1a1f873f502f6859d11210b25a4bf5d141e7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/opis/string/zipball/9ebf1a1f873f502f6859d11210b25a4bf5d141e7",
+ "reference": "9ebf1a1f873f502f6859d11210b25a4bf5d141e7",
+ "shasum": ""
+ },
+ "require": {
+ "ext-iconv": "*",
+ "ext-json": "*",
+ "php": "^7.4 || ^8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Opis\\String\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Marius Sarca",
+ "email": "marius.sarca@gmail.com"
+ },
+ {
+ "name": "Sorin Sarca",
+ "email": "sarca_sorin@hotmail.com"
+ }
+ ],
+ "description": "Multibyte strings as objects",
+ "homepage": "https://opis.io/string",
+ "keywords": [
+ "multi-byte",
+ "opis",
+ "string",
+ "string manipulation",
+ "utf-8"
+ ],
+ "support": {
+ "issues": "https://github.com/opis/string/issues",
+ "source": "https://github.com/opis/string/tree/2.0.1"
+ },
+ "time": "2022-01-14T15:42:23+00:00"
+ },
+ {
+ "name": "opis/uri",
+ "version": "1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/opis/uri.git",
+ "reference": "0f3ca49ab1a5e4a6681c286e0b2cc081b93a7d5a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/opis/uri/zipball/0f3ca49ab1a5e4a6681c286e0b2cc081b93a7d5a",
+ "reference": "0f3ca49ab1a5e4a6681c286e0b2cc081b93a7d5a",
+ "shasum": ""
+ },
+ "require": {
+ "opis/string": "^2.0",
+ "php": "^7.4 || ^8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Opis\\Uri\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Marius Sarca",
+ "email": "marius.sarca@gmail.com"
+ },
+ {
+ "name": "Sorin Sarca",
+ "email": "sarca_sorin@hotmail.com"
+ }
+ ],
+ "description": "Build, parse and validate URIs and URI-templates",
+ "homepage": "https://opis.io",
+ "keywords": [
+ "URI Template",
+ "parse url",
+ "punycode",
+ "uri",
+ "uri components",
+ "url",
+ "validate uri"
+ ],
+ "support": {
+ "issues": "https://github.com/opis/uri/issues",
+ "source": "https://github.com/opis/uri/tree/1.1.0"
+ },
+ "time": "2021-05-22T15:57:08+00:00"
+ },
+ {
+ "name": "psr/cache",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/cache.git",
+ "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
+ "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Cache\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for caching libraries",
+ "keywords": [
+ "cache",
+ "psr",
+ "psr-6"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/cache/tree/3.0.0"
+ },
+ "time": "2021-02-03T23:26:27+00:00"
+ },
+ {
+ "name": "psr/container",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/container/issues",
+ "source": "https://github.com/php-fig/container/tree/2.0.2"
+ },
+ "time": "2021-11-05T16:47:00+00:00"
+ },
+ {
+ "name": "psr/event-dispatcher",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/event-dispatcher.git",
+ "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
+ "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\EventDispatcher\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Standard interfaces for event handling.",
+ "keywords": [
+ "events",
+ "psr",
+ "psr-14"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/event-dispatcher/issues",
+ "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
+ },
+ "time": "2019-01-08T18:20:26+00:00"
+ },
+ {
+ "name": "psr/log",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
+ "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Log\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/log/tree/3.0.0"
+ },
+ "time": "2021-07-14T16:46:02+00:00"
+ },
+ {
+ "name": "symfony/asset",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/asset.git",
+ "reference": "d42c434e1a73d81cae7c75cd122f20fc80ac1a2b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/asset/zipball/d42c434e1a73d81cae7c75cd122f20fc80ac1a2b",
+ "reference": "d42c434e1a73d81cae7c75cd122f20fc80ac1a2b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2"
+ },
+ "conflict": {
+ "symfony/http-foundation": "<5.4"
+ },
+ "require-dev": {
+ "symfony/http-client": "^5.4|^6.0",
+ "symfony/http-foundation": "^5.4|^6.0",
+ "symfony/http-kernel": "^5.4|^6.0"
+ },
+ "suggest": {
+ "symfony/http-foundation": ""
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Asset\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/asset/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-01T08:36:10+00:00"
+ },
+ {
+ "name": "symfony/cache",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/cache.git",
+ "reference": "81ca309f056e836480928b20280ec52ce8369bb3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/cache/zipball/81ca309f056e836480928b20280ec52ce8369bb3",
+ "reference": "81ca309f056e836480928b20280ec52ce8369bb3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "psr/cache": "^2.0|^3.0",
+ "psr/log": "^1.1|^2|^3",
+ "symfony/cache-contracts": "^1.1.7|^2|^3",
+ "symfony/service-contracts": "^1.1|^2|^3",
+ "symfony/var-exporter": "^5.4|^6.0"
+ },
+ "conflict": {
+ "doctrine/dbal": "<2.13.1",
+ "symfony/dependency-injection": "<5.4",
+ "symfony/http-kernel": "<5.4",
+ "symfony/var-dumper": "<5.4"
+ },
+ "provide": {
+ "psr/cache-implementation": "2.0|3.0",
+ "psr/simple-cache-implementation": "1.0|2.0|3.0",
+ "symfony/cache-implementation": "1.1|2.0|3.0"
+ },
+ "require-dev": {
+ "cache/integration-tests": "dev-master",
+ "doctrine/dbal": "^2.13.1|^3.0",
+ "predis/predis": "^1.1",
+ "psr/simple-cache": "^1.0|^2.0|^3.0",
+ "symfony/config": "^5.4|^6.0",
+ "symfony/dependency-injection": "^5.4|^6.0",
+ "symfony/filesystem": "^5.4|^6.0",
+ "symfony/http-kernel": "^5.4|^6.0",
+ "symfony/messenger": "^5.4|^6.0",
+ "symfony/var-dumper": "^5.4|^6.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Cache\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides extended PSR-6, PSR-16 (and tags) implementations",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "caching",
+ "psr6"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/cache/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-20T17:44:14+00:00"
+ },
+ {
+ "name": "symfony/cache-contracts",
+ "version": "v3.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/cache-contracts.git",
+ "reference": "eeb71f04b6f7f34ca6d15633df82e014528b1632"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/eeb71f04b6f7f34ca6d15633df82e014528b1632",
+ "reference": "eeb71f04b6f7f34ca6d15633df82e014528b1632",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "psr/cache": "^3.0"
+ },
+ "suggest": {
+ "symfony/cache-implementation": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.3-dev"
+ },
+ "thanks": {
+ "name": "symfony/contracts",
+ "url": "https://github.com/symfony/contracts"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\Cache\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to caching",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/cache-contracts/tree/v3.2.1"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-03-01T10:32:47+00:00"
+ },
+ {
+ "name": "symfony/config",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/config.git",
+ "reference": "db4fc45c24e0c3e2198e68ada9d7f90daa1f97e3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/config/zipball/db4fc45c24e0c3e2198e68ada9d7f90daa1f97e3",
+ "reference": "db4fc45c24e0c3e2198e68ada9d7f90daa1f97e3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "symfony/deprecation-contracts": "^2.1|^3",
+ "symfony/filesystem": "^5.4|^6.0",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-php81": "^1.22"
+ },
+ "conflict": {
+ "symfony/finder": "<4.4"
+ },
+ "require-dev": {
+ "symfony/event-dispatcher": "^5.4|^6.0",
+ "symfony/finder": "^5.4|^6.0",
+ "symfony/messenger": "^5.4|^6.0",
+ "symfony/service-contracts": "^1.1|^2|^3",
+ "symfony/yaml": "^5.4|^6.0"
+ },
+ "suggest": {
+ "symfony/yaml": "To use the yaml reference dumper"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Config\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/config/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-09T04:36:00+00:00"
+ },
+ {
+ "name": "symfony/console",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/console.git",
+ "reference": "c3ebc83d031b71c39da318ca8b7a07ecc67507ed"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/console/zipball/c3ebc83d031b71c39da318ca8b7a07ecc67507ed",
+ "reference": "c3ebc83d031b71c39da318ca8b7a07ecc67507ed",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/service-contracts": "^1.1|^2|^3",
+ "symfony/string": "^5.4|^6.0"
+ },
+ "conflict": {
+ "symfony/dependency-injection": "<5.4",
+ "symfony/dotenv": "<5.4",
+ "symfony/event-dispatcher": "<5.4",
+ "symfony/lock": "<5.4",
+ "symfony/process": "<5.4"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0|2.0|3.0"
+ },
+ "require-dev": {
+ "psr/log": "^1|^2|^3",
+ "symfony/config": "^5.4|^6.0",
+ "symfony/dependency-injection": "^5.4|^6.0",
+ "symfony/event-dispatcher": "^5.4|^6.0",
+ "symfony/lock": "^5.4|^6.0",
+ "symfony/process": "^5.4|^6.0",
+ "symfony/var-dumper": "^5.4|^6.0"
+ },
+ "suggest": {
+ "psr/log": "For using the console logger",
+ "symfony/event-dispatcher": "",
+ "symfony/lock": "",
+ "symfony/process": ""
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Console\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Eases the creation of beautiful and testable command line interfaces",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "cli",
+ "command line",
+ "console",
+ "terminal"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/console/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-01T08:36:10+00:00"
+ },
+ {
+ "name": "symfony/css-selector",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/css-selector.git",
+ "reference": "f1d00bddb83a4cb2138564b2150001cb6ce272b1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/css-selector/zipball/f1d00bddb83a4cb2138564b2150001cb6ce272b1",
+ "reference": "f1d00bddb83a4cb2138564b2150001cb6ce272b1",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\CssSelector\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Jean-François Simon",
+ "email": "jeanfrancois.simon@sensiolabs.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Converts CSS selectors to XPath expressions",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/css-selector/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-01T08:36:10+00:00"
+ },
+ {
+ "name": "symfony/dependency-injection",
+ "version": "v6.0.20",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/dependency-injection.git",
+ "reference": "359806e1adebd1c43e18e5ea22acd14bef7fcf8c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/359806e1adebd1c43e18e5ea22acd14bef7fcf8c",
+ "reference": "359806e1adebd1c43e18e5ea22acd14bef7fcf8c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "psr/container": "^1.1|^2.0",
+ "symfony/deprecation-contracts": "^2.1|^3",
+ "symfony/polyfill-php81": "^1.22",
+ "symfony/service-contracts": "^1.1.6|^2.0|^3.0"
+ },
+ "conflict": {
+ "ext-psr": "<1.1|>=2",
+ "symfony/config": "<5.4",
+ "symfony/finder": "<5.4",
+ "symfony/proxy-manager-bridge": "<5.4",
+ "symfony/yaml": "<5.4"
+ },
+ "provide": {
+ "psr/container-implementation": "1.1|2.0",
+ "symfony/service-implementation": "1.1|2.0|3.0"
+ },
+ "require-dev": {
+ "symfony/config": "^5.4|^6.0",
+ "symfony/expression-language": "^5.4|^6.0",
+ "symfony/yaml": "^5.4|^6.0"
+ },
+ "suggest": {
+ "symfony/config": "",
+ "symfony/expression-language": "For using expressions in service container configuration",
+ "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required",
+ "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
+ "symfony/yaml": ""
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\DependencyInjection\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Allows you to standardize and centralize the way objects are constructed in your application",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/dependency-injection/tree/v6.0.20"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-30T15:41:07+00:00"
+ },
+ {
+ "name": "symfony/deprecation-contracts",
+ "version": "v3.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/deprecation-contracts.git",
+ "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e",
+ "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.3-dev"
+ },
+ "thanks": {
+ "name": "symfony/contracts",
+ "url": "https://github.com/symfony/contracts"
+ }
+ },
+ "autoload": {
+ "files": [
+ "function.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "A generic function and convention to trigger deprecation notices",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.1"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-03-01T10:25:55+00:00"
+ },
+ {
+ "name": "symfony/doctrine-bridge",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/doctrine-bridge.git",
+ "reference": "47f56e2ddf6a08fc2f0341940c7b1774cf1a8f89"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/47f56e2ddf6a08fc2f0341940c7b1774cf1a8f89",
+ "reference": "47f56e2ddf6a08fc2f0341940c7b1774cf1a8f89",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/event-manager": "^1|^2",
+ "doctrine/persistence": "^2|^3",
+ "php": ">=8.0.2",
+ "symfony/deprecation-contracts": "^2.1|^3",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/service-contracts": "^1.1|^2|^3"
+ },
+ "conflict": {
+ "doctrine/dbal": "<2.13.1",
+ "doctrine/lexer": "<1.1",
+ "doctrine/orm": "<2.7.4",
+ "phpunit/phpunit": "<5.4.3",
+ "symfony/cache": "<5.4",
+ "symfony/dependency-injection": "<5.4",
+ "symfony/form": "<5.4",
+ "symfony/http-kernel": "<5.4",
+ "symfony/messenger": "<5.4",
+ "symfony/property-info": "<5.4",
+ "symfony/security-bundle": "<5.4",
+ "symfony/security-core": "<6.0",
+ "symfony/validator": "<5.4"
+ },
+ "require-dev": {
+ "doctrine/annotations": "^1.10.4|^2",
+ "doctrine/collections": "^1.0|^2.0",
+ "doctrine/data-fixtures": "^1.1",
+ "doctrine/dbal": "^2.13.1|^3.0",
+ "doctrine/orm": "^2.7.4",
+ "psr/log": "^1|^2|^3",
+ "symfony/cache": "^5.4|^6.0",
+ "symfony/config": "^5.4|^6.0",
+ "symfony/dependency-injection": "^5.4|^6.0",
+ "symfony/doctrine-messenger": "^5.4|^6.0",
+ "symfony/expression-language": "^5.4|^6.0",
+ "symfony/form": "^5.4.9|^6.0.9",
+ "symfony/http-kernel": "^5.4|^6.0",
+ "symfony/messenger": "^5.4|^6.0",
+ "symfony/property-access": "^5.4|^6.0",
+ "symfony/property-info": "^5.4|^6.0",
+ "symfony/proxy-manager-bridge": "^5.4|^6.0",
+ "symfony/security-core": "^6.0",
+ "symfony/stopwatch": "^5.4|^6.0",
+ "symfony/translation": "^5.4|^6.0",
+ "symfony/uid": "^5.4|^6.0",
+ "symfony/validator": "^5.4|^6.0",
+ "symfony/var-dumper": "^5.4|^6.0"
+ },
+ "suggest": {
+ "doctrine/data-fixtures": "",
+ "doctrine/dbal": "",
+ "doctrine/orm": "",
+ "symfony/form": "",
+ "symfony/property-info": "",
+ "symfony/validator": ""
+ },
+ "type": "symfony-bridge",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Bridge\\Doctrine\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides integration for Doctrine with various Symfony components",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/doctrine-bridge/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-11T11:50:03+00:00"
+ },
+ {
+ "name": "symfony/dom-crawler",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/dom-crawler.git",
+ "reference": "622578ff158318b1b49d95068bd6b66c713601e9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/622578ff158318b1b49d95068bd6b66c713601e9",
+ "reference": "622578ff158318b1b49d95068bd6b66c713601e9",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-mbstring": "~1.0"
+ },
+ "conflict": {
+ "masterminds/html5": "<2.6"
+ },
+ "require-dev": {
+ "masterminds/html5": "^2.6",
+ "symfony/css-selector": "^5.4|^6.0"
+ },
+ "suggest": {
+ "symfony/css-selector": ""
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\DomCrawler\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Eases DOM navigation for HTML and XML documents",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/dom-crawler/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-20T17:44:14+00:00"
+ },
+ {
+ "name": "symfony/dotenv",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/dotenv.git",
+ "reference": "9cee123707e689f7e06c09624c145d206468bcf2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/dotenv/zipball/9cee123707e689f7e06c09624c145d206468bcf2",
+ "reference": "9cee123707e689f7e06c09624c145d206468bcf2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2"
+ },
+ "require-dev": {
+ "symfony/console": "^5.4|^6.0",
+ "symfony/process": "^5.4|^6.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Dotenv\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Registers environment variables from a .env file",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "dotenv",
+ "env",
+ "environment"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/dotenv/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-01T08:36:10+00:00"
+ },
+ {
+ "name": "symfony/error-handler",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/error-handler.git",
+ "reference": "c7df52182f43a68522756ac31a532dd5b1e6db67"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/error-handler/zipball/c7df52182f43a68522756ac31a532dd5b1e6db67",
+ "reference": "c7df52182f43a68522756ac31a532dd5b1e6db67",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "psr/log": "^1|^2|^3",
+ "symfony/var-dumper": "^5.4|^6.0"
+ },
+ "require-dev": {
+ "symfony/deprecation-contracts": "^2.1|^3",
+ "symfony/http-kernel": "^5.4|^6.0",
+ "symfony/serializer": "^5.4|^6.0"
+ },
+ "bin": [
+ "Resources/bin/patch-type-declarations"
+ ],
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\ErrorHandler\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides tools to manage errors and ease debugging PHP code",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/error-handler/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-01T08:36:10+00:00"
+ },
+ {
+ "name": "symfony/event-dispatcher",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/event-dispatcher.git",
+ "reference": "2eaf8e63bc5b8cefabd4a800157f0d0c094f677a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2eaf8e63bc5b8cefabd4a800157f0d0c094f677a",
+ "reference": "2eaf8e63bc5b8cefabd4a800157f0d0c094f677a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "symfony/event-dispatcher-contracts": "^2|^3"
+ },
+ "conflict": {
+ "symfony/dependency-injection": "<5.4"
+ },
+ "provide": {
+ "psr/event-dispatcher-implementation": "1.0",
+ "symfony/event-dispatcher-implementation": "2.0|3.0"
+ },
+ "require-dev": {
+ "psr/log": "^1|^2|^3",
+ "symfony/config": "^5.4|^6.0",
+ "symfony/dependency-injection": "^5.4|^6.0",
+ "symfony/error-handler": "^5.4|^6.0",
+ "symfony/expression-language": "^5.4|^6.0",
+ "symfony/http-foundation": "^5.4|^6.0",
+ "symfony/service-contracts": "^1.1|^2|^3",
+ "symfony/stopwatch": "^5.4|^6.0"
+ },
+ "suggest": {
+ "symfony/dependency-injection": "",
+ "symfony/http-kernel": ""
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\EventDispatcher\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/event-dispatcher/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-01T08:36:10+00:00"
+ },
+ {
+ "name": "symfony/event-dispatcher-contracts",
+ "version": "v3.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/event-dispatcher-contracts.git",
+ "reference": "0ad3b6f1e4e2da5690fefe075cd53a238646d8dd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/0ad3b6f1e4e2da5690fefe075cd53a238646d8dd",
+ "reference": "0ad3b6f1e4e2da5690fefe075cd53a238646d8dd",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "psr/event-dispatcher": "^1"
+ },
+ "suggest": {
+ "symfony/event-dispatcher-implementation": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.3-dev"
+ },
+ "thanks": {
+ "name": "symfony/contracts",
+ "url": "https://github.com/symfony/contracts"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\EventDispatcher\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to dispatching event",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.2.1"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-03-01T10:32:47+00:00"
+ },
+ {
+ "name": "symfony/filesystem",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/filesystem.git",
+ "reference": "3d49eec03fda1f0fc19b7349fbbe55ebc1004214"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/3d49eec03fda1f0fc19b7349fbbe55ebc1004214",
+ "reference": "3d49eec03fda1f0fc19b7349fbbe55ebc1004214",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-mbstring": "~1.8"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Filesystem\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides basic utilities for the filesystem",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/filesystem/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-20T17:44:14+00:00"
+ },
+ {
+ "name": "symfony/finder",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/finder.git",
+ "reference": "5cc9cac6586fc0c28cd173780ca696e419fefa11"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/5cc9cac6586fc0c28cd173780ca696e419fefa11",
+ "reference": "5cc9cac6586fc0c28cd173780ca696e419fefa11",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Finder\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Finds files and directories via an intuitive fluent interface",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/finder/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-20T17:44:14+00:00"
+ },
+ {
+ "name": "symfony/flex",
+ "version": "v1.19.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/flex.git",
+ "reference": "51077ed0f6dc2c94cd0b670167eee3747c31b2c1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/flex/zipball/51077ed0f6dc2c94cd0b670167eee3747c31b2c1",
+ "reference": "51077ed0f6dc2c94cd0b670167eee3747c31b2c1",
+ "shasum": ""
+ },
+ "require": {
+ "composer-plugin-api": "^1.0|^2.0",
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "composer/composer": "^1.0.2|^2.0",
+ "symfony/dotenv": "^4.4|^5.0|^6.0",
+ "symfony/filesystem": "^4.4|^5.0|^6.0",
+ "symfony/phpunit-bridge": "^4.4.12|^5.0|^6.0",
+ "symfony/process": "^4.4|^5.0|^6.0"
+ },
+ "type": "composer-plugin",
+ "extra": {
+ "class": "Symfony\\Flex\\Flex"
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Flex\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien.potencier@gmail.com"
+ }
+ ],
+ "description": "Composer plugin for Symfony",
+ "support": {
+ "issues": "https://github.com/symfony/flex/issues",
+ "source": "https://github.com/symfony/flex/tree/v1.19.5"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-30T17:02:31+00:00"
+ },
+ {
+ "name": "symfony/form",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/form.git",
+ "reference": "bec07ecf4aac245183b8e0fa93eb68630415346e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/form/zipball/bec07ecf4aac245183b8e0fa93eb68630415346e",
+ "reference": "bec07ecf4aac245183b8e0fa93eb68630415346e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "symfony/deprecation-contracts": "^2.1|^3",
+ "symfony/event-dispatcher": "^5.4|^6.0",
+ "symfony/options-resolver": "^5.4|^6.0",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-intl-icu": "^1.21",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/polyfill-php81": "^1.23",
+ "symfony/property-access": "^5.4|^6.0",
+ "symfony/service-contracts": "^1.1|^2|^3"
+ },
+ "conflict": {
+ "phpunit/phpunit": "<5.4.3",
+ "symfony/console": "<5.4",
+ "symfony/dependency-injection": "<5.4",
+ "symfony/doctrine-bridge": "<5.4",
+ "symfony/error-handler": "<5.4",
+ "symfony/framework-bundle": "<5.4",
+ "symfony/http-kernel": "<5.4",
+ "symfony/translation": "<5.4",
+ "symfony/translation-contracts": "<1.1.7",
+ "symfony/twig-bridge": "<5.4"
+ },
+ "require-dev": {
+ "doctrine/collections": "^1.0|^2.0",
+ "symfony/config": "^5.4|^6.0",
+ "symfony/console": "^5.4|^6.0",
+ "symfony/dependency-injection": "^5.4|^6.0",
+ "symfony/expression-language": "^5.4|^6.0",
+ "symfony/http-foundation": "^5.4|^6.0",
+ "symfony/http-kernel": "^5.4|^6.0",
+ "symfony/intl": "^5.4|^6.0",
+ "symfony/security-csrf": "^5.4|^6.0",
+ "symfony/translation": "^5.4|^6.0",
+ "symfony/uid": "^5.4|^6.0",
+ "symfony/validator": "^5.4|^6.0",
+ "symfony/var-dumper": "^5.4|^6.0"
+ },
+ "suggest": {
+ "symfony/security-csrf": "For protecting forms against CSRF attacks.",
+ "symfony/twig-bridge": "For templating with Twig.",
+ "symfony/validator": "For form validation."
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Form\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Allows to easily create, process and reuse HTML forms",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/form/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-01T08:36:10+00:00"
+ },
+ {
+ "name": "symfony/framework-bundle",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/framework-bundle.git",
+ "reference": "ee403597484be1073222373fc2962b44c36f5dd4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/ee403597484be1073222373fc2962b44c36f5dd4",
+ "reference": "ee403597484be1073222373fc2962b44c36f5dd4",
+ "shasum": ""
+ },
+ "require": {
+ "composer-runtime-api": ">=2.1",
+ "ext-xml": "*",
+ "php": ">=8.0.2",
+ "symfony/cache": "^5.4|^6.0",
+ "symfony/config": "^5.4|^6.0",
+ "symfony/dependency-injection": "^5.4.5|^6.0.5",
+ "symfony/error-handler": "^5.4|^6.0",
+ "symfony/event-dispatcher": "^5.4|^6.0",
+ "symfony/filesystem": "^5.4|^6.0",
+ "symfony/finder": "^5.4|^6.0",
+ "symfony/http-foundation": "^5.4|^6.0",
+ "symfony/http-kernel": "^5.4|^6.0",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/polyfill-php81": "^1.22",
+ "symfony/routing": "^5.4|^6.0"
+ },
+ "conflict": {
+ "doctrine/annotations": "<1.13.1",
+ "doctrine/persistence": "<1.3",
+ "phpdocumentor/reflection-docblock": "<3.2.2",
+ "phpdocumentor/type-resolver": "<1.4.0",
+ "phpunit/phpunit": "<5.4.3",
+ "symfony/asset": "<5.4",
+ "symfony/console": "<5.4",
+ "symfony/dom-crawler": "<5.4",
+ "symfony/dotenv": "<5.4",
+ "symfony/form": "<5.4",
+ "symfony/http-client": "<5.4",
+ "symfony/lock": "<5.4",
+ "symfony/mailer": "<5.4",
+ "symfony/messenger": "<5.4",
+ "symfony/mime": "<5.4",
+ "symfony/property-access": "<5.4",
+ "symfony/property-info": "<5.4",
+ "symfony/security-core": "<5.4",
+ "symfony/security-csrf": "<5.4",
+ "symfony/serializer": "<5.4",
+ "symfony/stopwatch": "<5.4",
+ "symfony/translation": "<5.4",
+ "symfony/twig-bridge": "<5.4",
+ "symfony/twig-bundle": "<5.4",
+ "symfony/validator": "<5.4",
+ "symfony/web-profiler-bundle": "<5.4",
+ "symfony/workflow": "<5.4"
+ },
+ "require-dev": {
+ "doctrine/annotations": "^1.13.1|^2",
+ "doctrine/persistence": "^1.3|^2|^3",
+ "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
+ "symfony/asset": "^5.4|^6.0",
+ "symfony/browser-kit": "^5.4|^6.0",
+ "symfony/console": "^5.4.9|^6.0.9",
+ "symfony/css-selector": "^5.4|^6.0",
+ "symfony/dom-crawler": "^5.4|^6.0",
+ "symfony/dotenv": "^5.4|^6.0",
+ "symfony/expression-language": "^5.4|^6.0",
+ "symfony/form": "^5.4|^6.0",
+ "symfony/http-client": "^5.4|^6.0",
+ "symfony/lock": "^5.4|^6.0",
+ "symfony/mailer": "^5.4|^6.0",
+ "symfony/messenger": "^5.4|^6.0",
+ "symfony/mime": "^5.4|^6.0",
+ "symfony/notifier": "^5.4|^6.0",
+ "symfony/polyfill-intl-icu": "~1.0",
+ "symfony/process": "^5.4|^6.0",
+ "symfony/property-info": "^5.4|^6.0",
+ "symfony/rate-limiter": "^5.4|^6.0",
+ "symfony/security-bundle": "^5.4|^6.0",
+ "symfony/serializer": "^5.4|^6.0",
+ "symfony/stopwatch": "^5.4|^6.0",
+ "symfony/string": "^5.4|^6.0",
+ "symfony/translation": "^5.4|^6.0",
+ "symfony/twig-bundle": "^5.4|^6.0",
+ "symfony/validator": "^5.4|^6.0",
+ "symfony/web-link": "^5.4|^6.0",
+ "symfony/workflow": "^5.4|^6.0",
+ "symfony/yaml": "^5.4|^6.0",
+ "twig/twig": "^2.10|^3.0"
+ },
+ "suggest": {
+ "ext-apcu": "For best performance of the system caches",
+ "symfony/console": "For using the console commands",
+ "symfony/form": "For using forms",
+ "symfony/property-info": "For using the property_info service",
+ "symfony/serializer": "For using the serializer service",
+ "symfony/validator": "For using validation",
+ "symfony/web-link": "For using web links, features such as preloading, prefetching or prerendering",
+ "symfony/yaml": "For using the debug:config and lint:yaml commands"
+ },
+ "type": "symfony-bundle",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Bundle\\FrameworkBundle\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/framework-bundle/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-11T11:50:03+00:00"
+ },
+ {
+ "name": "symfony/http-foundation",
+ "version": "v6.0.20",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/http-foundation.git",
+ "reference": "e16b2676a4b3b1fa12378a20b29c364feda2a8d6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e16b2676a4b3b1fa12378a20b29c364feda2a8d6",
+ "reference": "e16b2676a4b3b1fa12378a20b29c364feda2a8d6",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "symfony/deprecation-contracts": "^2.1|^3",
+ "symfony/polyfill-mbstring": "~1.1"
+ },
+ "require-dev": {
+ "predis/predis": "~1.0",
+ "symfony/cache": "^5.4|^6.0",
+ "symfony/dependency-injection": "^5.4|^6.0",
+ "symfony/expression-language": "^5.4|^6.0",
+ "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4",
+ "symfony/mime": "^5.4|^6.0",
+ "symfony/rate-limiter": "^5.2|^6.0"
+ },
+ "suggest": {
+ "symfony/mime": "To use the file extension guesser"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\HttpFoundation\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Defines an object-oriented layer for the HTTP specification",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/http-foundation/tree/v6.0.20"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-30T15:41:07+00:00"
+ },
+ {
+ "name": "symfony/http-kernel",
+ "version": "v6.0.20",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/http-kernel.git",
+ "reference": "6dc70833fd0ef5e861e17c7854c12d7d86679349"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6dc70833fd0ef5e861e17c7854c12d7d86679349",
+ "reference": "6dc70833fd0ef5e861e17c7854c12d7d86679349",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "psr/log": "^1|^2|^3",
+ "symfony/error-handler": "^5.4|^6.0",
+ "symfony/event-dispatcher": "^5.4|^6.0",
+ "symfony/http-foundation": "^5.4|^6.0",
+ "symfony/polyfill-ctype": "^1.8"
+ },
+ "conflict": {
+ "symfony/browser-kit": "<5.4",
+ "symfony/cache": "<5.4",
+ "symfony/config": "<5.4",
+ "symfony/console": "<5.4",
+ "symfony/dependency-injection": "<5.4",
+ "symfony/doctrine-bridge": "<5.4",
+ "symfony/form": "<5.4",
+ "symfony/http-client": "<5.4",
+ "symfony/mailer": "<5.4",
+ "symfony/messenger": "<5.4",
+ "symfony/translation": "<5.4",
+ "symfony/twig-bridge": "<5.4",
+ "symfony/validator": "<5.4",
+ "twig/twig": "<2.13"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0|2.0|3.0"
+ },
+ "require-dev": {
+ "psr/cache": "^1.0|^2.0|^3.0",
+ "symfony/browser-kit": "^5.4|^6.0",
+ "symfony/config": "^5.4|^6.0",
+ "symfony/console": "^5.4|^6.0",
+ "symfony/css-selector": "^5.4|^6.0",
+ "symfony/dependency-injection": "^5.4|^6.0",
+ "symfony/dom-crawler": "^5.4|^6.0",
+ "symfony/expression-language": "^5.4|^6.0",
+ "symfony/finder": "^5.4|^6.0",
+ "symfony/http-client-contracts": "^1.1|^2|^3",
+ "symfony/process": "^5.4|^6.0",
+ "symfony/routing": "^5.4|^6.0",
+ "symfony/stopwatch": "^5.4|^6.0",
+ "symfony/translation": "^5.4|^6.0",
+ "symfony/translation-contracts": "^1.1|^2|^3",
+ "twig/twig": "^2.13|^3.0.4"
+ },
+ "suggest": {
+ "symfony/browser-kit": "",
+ "symfony/config": "",
+ "symfony/console": "",
+ "symfony/dependency-injection": ""
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\HttpKernel\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides a structured process for converting a Request into a Response",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/http-kernel/tree/v6.0.20"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-02-01T08:22:55+00:00"
+ },
+ {
+ "name": "symfony/intl",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/intl.git",
+ "reference": "a2e1ce9048ea549ee1e8d9ce521cbe9a9ec7d92c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/intl/zipball/a2e1ce9048ea549ee1e8d9ce521cbe9a9ec7d92c",
+ "reference": "a2e1ce9048ea549ee1e8d9ce521cbe9a9ec7d92c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2"
+ },
+ "require-dev": {
+ "symfony/filesystem": "^5.4|^6.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Intl\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ },
+ {
+ "name": "Eriksen Costa",
+ "email": "eriksen.costa@infranology.com.br"
+ },
+ {
+ "name": "Igor Wiedler",
+ "email": "igor@wiedler.ch"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides a PHP replacement layer for the C intl extension that includes additional data from the ICU library",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "i18n",
+ "icu",
+ "internationalization",
+ "intl",
+ "l10n",
+ "localization"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/intl/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-01T08:36:10+00:00"
+ },
+ {
+ "name": "symfony/lock",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/lock.git",
+ "reference": "c326af52d5db5c427d5f7269b00f6b2212ec1ad3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/lock/zipball/c326af52d5db5c427d5f7269b00f6b2212ec1ad3",
+ "reference": "c326af52d5db5c427d5f7269b00f6b2212ec1ad3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "psr/log": "^1|^2|^3"
+ },
+ "conflict": {
+ "doctrine/dbal": "<2.13"
+ },
+ "require-dev": {
+ "doctrine/dbal": "^2.13|^3.0",
+ "predis/predis": "~1.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Lock\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jérémy Derussé",
+ "email": "jeremy@derusse.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Creates and manages locks, a mechanism to provide exclusive access to a shared resource",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "cas",
+ "flock",
+ "locking",
+ "mutex",
+ "redlock",
+ "semaphore"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/lock/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-01T08:36:10+00:00"
+ },
+ {
+ "name": "symfony/monolog-bridge",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/monolog-bridge.git",
+ "reference": "8932b9108765203156fa07e819d45f58e927d3c5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/8932b9108765203156fa07e819d45f58e927d3c5",
+ "reference": "8932b9108765203156fa07e819d45f58e927d3c5",
+ "shasum": ""
+ },
+ "require": {
+ "monolog/monolog": "^1.25.1|^2",
+ "php": ">=8.0.2",
+ "symfony/http-kernel": "^5.4|^6.0",
+ "symfony/service-contracts": "^1.1|^2|^3"
+ },
+ "conflict": {
+ "symfony/console": "<5.4",
+ "symfony/http-foundation": "<5.4",
+ "symfony/security-core": "<6.0"
+ },
+ "require-dev": {
+ "symfony/console": "^5.4|^6.0",
+ "symfony/http-client": "^5.4|^6.0",
+ "symfony/mailer": "^5.4|^6.0",
+ "symfony/messenger": "^5.4|^6.0",
+ "symfony/mime": "^5.4|^6.0",
+ "symfony/security-core": "^6.0",
+ "symfony/var-dumper": "^5.4|^6.0"
+ },
+ "suggest": {
+ "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.",
+ "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.",
+ "symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler."
+ },
+ "type": "symfony-bridge",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Bridge\\Monolog\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides integration for Monolog with various Symfony components",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/monolog-bridge/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-01T08:36:10+00:00"
+ },
+ {
+ "name": "symfony/monolog-bundle",
+ "version": "v3.8.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/monolog-bundle.git",
+ "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d",
+ "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d",
+ "shasum": ""
+ },
+ "require": {
+ "monolog/monolog": "^1.22 || ^2.0 || ^3.0",
+ "php": ">=7.1.3",
+ "symfony/config": "~4.4 || ^5.0 || ^6.0",
+ "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0",
+ "symfony/http-kernel": "~4.4 || ^5.0 || ^6.0",
+ "symfony/monolog-bridge": "~4.4 || ^5.0 || ^6.0"
+ },
+ "require-dev": {
+ "symfony/console": "~4.4 || ^5.0 || ^6.0",
+ "symfony/phpunit-bridge": "^5.2 || ^6.0",
+ "symfony/yaml": "~4.4 || ^5.0 || ^6.0"
+ },
+ "type": "symfony-bundle",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Bundle\\MonologBundle\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony MonologBundle",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "log",
+ "logging"
+ ],
+ "support": {
+ "issues": "https://github.com/symfony/monolog-bundle/issues",
+ "source": "https://github.com/symfony/monolog-bundle/tree/v3.8.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-05-10T14:24:36+00:00"
+ },
+ {
+ "name": "symfony/options-resolver",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/options-resolver.git",
+ "reference": "6a180d1c45e0d9797470ca9eb46215692de00fa3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/options-resolver/zipball/6a180d1c45e0d9797470ca9eb46215692de00fa3",
+ "reference": "6a180d1c45e0d9797470ca9eb46215692de00fa3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "symfony/deprecation-contracts": "^2.1|^3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\OptionsResolver\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides an improved replacement for the array_replace PHP function",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "config",
+ "configuration",
+ "options"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/options-resolver/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-01T08:36:10+00:00"
+ },
+ {
+ "name": "symfony/password-hasher",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/password-hasher.git",
+ "reference": "2ae49765c5328307e82c0ee2898a39c071ef5bc8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/password-hasher/zipball/2ae49765c5328307e82c0ee2898a39c071ef5bc8",
+ "reference": "2ae49765c5328307e82c0ee2898a39c071ef5bc8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2"
+ },
+ "conflict": {
+ "symfony/security-core": "<5.4"
+ },
+ "require-dev": {
+ "symfony/console": "^5.4|^6.0",
+ "symfony/security-core": "^5.4|^6.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\PasswordHasher\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Robin Chalas",
+ "email": "robin.chalas@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides password hashing utilities",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "hashing",
+ "password"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/password-hasher/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-01T08:36:10+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-grapheme",
+ "version": "v1.27.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
+ "reference": "511a08c03c1960e08a883f4cffcacd219b758354"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354",
+ "reference": "511a08c03c1960e08a883f4cffcacd219b758354",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.27-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for intl's grapheme_* functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "grapheme",
+ "intl",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-11-03T14:55:06+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-icu",
+ "version": "v1.27.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-icu.git",
+ "reference": "a3d9148e2c363588e05abbdd4ee4f971f0a5330c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/a3d9148e2c363588e05abbdd4ee4f971f0a5330c",
+ "reference": "a3d9148e2c363588e05abbdd4ee4f971f0a5330c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "suggest": {
+ "ext-intl": "For best performance and support of other locales than \"en\""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.27-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Icu\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ],
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for intl's ICU-related data and classes",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "icu",
+ "intl",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.27.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-11-03T14:55:06+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-normalizer",
+ "version": "v1.27.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
+ "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
+ "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.27-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for intl's Normalizer class and related functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "intl",
+ "normalizer",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-11-03T14:55:06+00:00"
+ },
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.27.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
+ "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "provide": {
+ "ext-mbstring": "*"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.27-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-11-03T14:55:06+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php80",
+ "version": "v1.27.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php80.git",
+ "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
+ "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.27-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php80\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ion Bazan",
+ "email": "ion.bazan@gmail.com"
+ },
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-11-03T14:55:06+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php81",
+ "version": "v1.27.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php81.git",
+ "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a",
+ "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.27-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php81\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-11-03T14:55:06+00:00"
+ },
+ {
+ "name": "symfony/polyfill-uuid",
+ "version