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', '$1', $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[] = ''; + $summary[] = ''; + $summary[] = ''; + $summary[] = ''; + $summary[] = ''; + $summary[] = ''; + $summary[] = ''; + $summary[] = ''; + $summary[] = ''; + $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('', + $attackerTxt, $unit->name, $unit->faction_id, $healthPercent); + $summary[] = sprintf('', + $unit->_cntDealt, $unit->_dmgDealt, $avgDealt); + $summary[] = sprintf('', + $unit->_cntTaken, $unit->_dmgTaken, $avgTaken); + $summary[] = ''; + } + } + $summary[] = '
Podsumowanie bitwy
StronaPostaćWykonane atakiOtrzymane ataki
ImięFrakcjaZdrowieAtakiObrażeniaŚredniaAtakiObrażeniaŚrednia
%s%s%s%.2f%%%d%.3f%.3f%d%.3f%.3f
'; + 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 @@ + + + + + + + +
    +
    +Nowa postać + + + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + +
    PostaćPoziomTuryZdrowieLokacjaAkcja
    ${char/name}${char/level}${char/turns}${char/health} / ${char/health_max}Otchłań Narodzinedytuj + aktywna + +
    +
    + +

    ustawienia konta

    + +
    +

    +Postać: + + + +

    +
    + + + + 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}
    + + + +
    Cechy bojowe
    +
    + +
    +
    + + + + + + + +
    Cechy
    ${item/name}${item/value}
    +
    +
    + + + + + + + + + + +
    Umiejętności
    ${item/name}${item/value}nieznana
    +
    +
    + + + + + + + + + + +
    Zaklęcia
    ${item/name}${item/_cost} MPnieznane
    +
    +
    + + + + 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 @@ + + + + + + + + +
    +

    + +
    + ściągawka +

    +
    + + +
    +

    + ${item/sender_name} + Postać usunięta +

    +

    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 @@ + + + + + + + +
    + +
    +
    + Nowy klan + + + +
    +
    + +
    +
    + Dołącz do klanu + +
    + + ściągawka +
    +
    + + + + + + + + +
    Złożone podania
    KlanPodanie
    ${item/clan_name} (${item/clan_id})niewypełnione
    + +
    + +
    + +
    +
    + Ustawienia + + + + + + + + + + + + + + + + +
    + +
    + +
    + ściągawka +
    + +
    Podgląd +
    +
    +
    + +
    + + +
    + +
    + + + + + + + + + + + + + + + + + + + +
    Postacie
    ImięPoziomEXPFrakcjaData narodzin
    ${item/name}${item/level}${item/xp_used}brak${item/faction_id} (r${item/rank_id})${item/date_created} + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + +
    Podania
    ImięPoziomEXPFrakcjaData narodzinPodanie
    ${item/character_name}${item/level}${item/xp_used}brak${item/faction_id} (r${item/rank_id})${item/date_created}niewypełnione
    +
    + +
    + + + + 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 + + +Do wyświetlania w profilu postaci. +
    + + +Wypełnij tylko jeśli zmieniasz hasło. +
    +Styl strony: + +
    +Email: +Do przypominania hasła, nie wyświetlany w grze. +
    + +
    +
    + + + + 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 +
      +
    • + + +
    • +
    • + + +
    • +
    • + + +
    • +
    • + + +
    • +
    + +
    +
    + +
    +

    + ${character/avatar_url} +

    +

    +

    + +
    + + + + 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 @@ + + + + + +

    Daemon 2

    + +
    + +
    + + + + + +

    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 & .

    + + +

    Najnowsze wieści

    +
      +
    • ${item/published}
    • +
    +
    + + + + 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) + +
    +
    + + + + +
    Zdrowie${characterData/health} / ${characterData/health_max}
    Mana${characterData/mana} / ${characterData/mana_max}
    +
    + +
    + +

    ${group/name}

    + +
    +
    + ${inv/item/name} (przypisany) + + + + + + niezidentyfikowany + + ${inv/item/description}
    ${inv/item/getDescription} +
    +
    +
    +
    +
    + + + + 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 + + + + + + + + + + + + + + + +
    +
    +

    + + + +

    +

    + + Aktywna postać: ${activeCharacter/name} + Tury: ${characterData/turns} + + Brak aktywnej postaci. + +

    + +
    +
    +
    + + + +
      +
    • ${msg}
    • +
    +
    + + + + + +<link rel="icon" type="image/png" href="static/favicon"/> +<link rel="stylesheet" title="${pageSkinName}" href="${pageSkinUrl}/skin.css"/> +<link rel="alternate feed" title="News" href="news" type="application/atom+xml"/> +<!--[if IE]><script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]--> +</tal:block> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<head><tal:block metal:use-macro="macros.xml/pageMetadata"/></head> +<body> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="macros.xml/pageMessages"/> + +<form action="" method="post"> +<p> +<textarea name="msg" cols="100" rows="5">${inputMsg}</textarea> +<br/> +<label>Adresat: <input name="to" value="${inputTo}" size="32"/></label> +<button>wyślij wiadomość</button> <a href="http://pl.daemon.wikia.com/wiki/BBCode">ściągawka</a> +</p> +</form> + +<section tal:repeat="item list"> +<h3> + <a tal:condition="item/sender_id" href="stats-characters?view=${item/sender_id}">${item/sender_name}</a> + <tal:block condition="item/recipient_id"> + do: <a href="stats-characters?view=${item/recipient_id}">${item/recipient_name}</a> + </tal:block> +</h3> +<p>Wysłane: ${item/date_added} <a tal:condition="exists:item/replyUrl" href="${item/replyUrl}">[odpowiedz]</a></p> +<blockquote tal:content="structure item/content"></blockquote> +</section> + +<p tal:condition="nextUrl"><a href="${nextUrl}">pokaż starsze wiadomości...</a></p> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</body> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<head><tal:block metal:use-macro="macros.xml/pageMetadata"/></head> +<body> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="macros.xml/pageMessages"/> + +<p tal:condition="locationDesc"><i tal:content="structure locationDesc"></i></p> + +<section class="multicols"> + <table> + <tr> + <th>Poziom</th> + <td>${characterData/level}</td> + </tr> + <tr> + <th>Doświadczenie</th> + <td>${characterData/xp_free} + ${characterData/xp_used}</td> + </tr> + <tr> + <th>Zdrowie</th> + <td>${characterData/health} / ${characterData/health_max}</td> + </tr> + <tr> + <th>Mana</th> + <td>${characterData/mana} / ${characterData/mana_max}</td> + </tr> + <tr> + <th>Złoto</th> + <td>${characterData/gold_purse} + ${characterData/gold_bank}</td> + </tr> + <tr tal:condition="lastMission"> + <th>Misja</th> + <td> + ${lastMission/_name}<br/> + świątynia: ${lastMission/service_name}<br/> + przeliczenie nr ${lastMission/rollover_id}<br/> + status: <b>${lastMission/_statusName}</b> + </td> + </tr> + </table> + <div class="box" style="background-image:url(${pictureUrl})"> + <p> + <tal:block condition="region">Region: ${region}<br/></tal:block> + Lokacja: <b>${location/name}</b><br/> + <tal:block condition="php:location.type == 'arena'">Arena - PvP ograniczone<br/></tal:block> + <tal:block condition="php:location.type == 'caern'">Caern - PvP ograniczone<br/></tal:block> + <tal:block condition="php:location.type == 'boss'">Boss (${location/boss_status_name}) - PvP ograniczone<br/></tal:block> + <tal:block condition="faction">Frakcja: ${faction}<br/></tal:block> + </p> + <ul> + <li tal:repeat="item maps"><a href="static/${item/url}" target="maps">${item/name}</a></li> + </ul> + </div> + <p tal:condition="activeCharacter/avatar_url" class="avatar"> + <img src="${activeCharacter/avatar_url}" alt="${activeCharacter/avatar_url}"/> + </p> +</section> + +<section class="multicols"> + <form action="" method="post"> + <h2>Akcja</h2> + <p> + <button name="act" value="train">trening</button><br/> + <button name="act" value="rest">odpoczynek</button><br/> + <button name="act" value="hunt">polowanie</button> + </p> + </form> + <form action="" method="post"> + <h2>Wędrówka</h2> + <p> + <tal:block repeat="item paths"> + <button name="travel" value="${item/destination_id}" tal:attributes="disabled not:item/_enabled"> + ${item/path_name} + <tal:block condition="php:item['cost_gold'] || item['cost_mana']">(${item/cost_gold} zł, ${item/cost_mana} MP)</tal:block> + </button> + <br tal:condition="not:repeat/item/end"/> + </tal:block> + </p> + </form> + <div> + <h2>Usługi</h2> + <ul> + <tal:block repeat="item services"> + <li tal:condition="item/_enabled"><a href="service.php?id=${item/service_id}">${item/name}</a></li> + <li tal:condition="not:item/_enabled">${item/name}</li> + </tal:block> + </ul> + </div> +</section> + +<section tal:condition="characters"> +<form action="duel" method="post"> + <h2>Inne postacie w tej lokacji</h2> + <table class="border"> + <tr><th>Postać</th><th>Poziom</th><th>EXP</th><th>Frakcja</th><th>PvP</th></tr> + <tr tal:repeat="item characters"> + <td><a href="stats-characters?view=${item/character_id}">${item/name}</a></td> + <td>${item/level}</td> + <td>${item/xp_used}</td> + <td tal:condition="not:item/faction_id"><i>brak</i></td> + <td tal:condition="item/faction_id">${item/faction_name} (ranga ${item/rank_id})</td> + <td tal:condition="not:item/_canAttack"><i>niedozwolone</i></td> + <td tal:condition="item/_canAttack"> + <button tal:condition="not:item/_sparring" name="attack" value="${item/character_id}">atakuj</button> + <button tal:condition="item/_sparring" name="attack" value="${item/character_id}">sparring</button> + </td> + </tr> + </table> + <p><a tal:condition="showMoreLink" href="?more">pokaż wszystkie postacie</a></p> +</form> +</section> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</body> +</html> 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 @@ +<h2>${activeCharacter/name} vs ${monsterName}</h2> + +<section class="multicols"> + + <section tal:condition="characterData/health"> + <p> + Zdrowie: <b>${characterData/health} / ${characterData/health_max}</b> + <br/> + Mana: <b>${characterData/mana} / ${characterData/mana_max}</b> + </p> + <form tal:condition="not:fromEvent" action="" method="post"> + <p> + <button name="act" value="train">trening</button><br/> + <button name="act" value="rest">odpoczynek</button><br/> + <button name="act" value="hunt">polowanie</button> + </p> + </form> + </section> + + <section tal:condition="php:'a'==winner"> + <p>Walkę wygrywa <i>${activeCharacter/name}</i>.</p> + <p> + Doświadczenie: <b>${characterData/xp_free} (+${winnerXp})</b>, + złoto <b>${characterData/gold_purse} (+${winnerGold})</b>. + </p> + <p tal:condition="winnerLevel">Nowy poziom: <b>${winnerLevel}</b>.</p> + <p tal:condition="winnerDrop">Zdobyty przedmiot: <i>${winnerDrop}</i>.</p> + <p tal:condition="winnerMission">Misja zakończona - zgłoś się do świątyni po nagrodę.</p> + </section> + + <section tal:condition="php:'m'==winner"> + <p>Walkę wygrywa <i>${monsterName}</i>.</p> + <p class="ex">${activeCharacter/name} traci powłokę cielesną.</p> + </section> + + <section tal:condition="not:winner"> + <p class="ex">Potwór ucieka.</p> + </section> + +</section> + +<h2>Przebieg walki</h2> +<section tal:content="structure combatLog"></section> 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<feed xmlns="http://www.w3.org/2005/Atom"> +<id>${feedId}</id> +<title>${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 @@ + + + + + +

    Daemon 2

    + +
    +
    +Rejestracja + + + + +
    +
    + + + +

    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 @@ + + + + + +

    Daemon 2

    + +
    +
    +Reset hasła + + +
    + + + +
    +
    + + + +

    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... +

    + +
    +

    +
    + +
    +

    + Odrodzenie: +

    +
    + +
    + + + + 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 @@ + + + + +

    Daemon 2

    + +

    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: + + + + +
    + + + + +VS + + + + +
    + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Win AWin BRemis2xKOZdrowie AZdrowie B
    AVGMINMAXAVGMINMAX
    ${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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Imię
    Płeć + +
    Ostatna akcja
    Klan (ID)
    Portret postaci (URL)
    Motto
    Opis
    + + + wróć do listy +
    +
    +
    + + +
    +
    +Dane związane z erą + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Lokacja (ID)
    Frakcja + + + +
    Tury
    Złoto + + +
    Doświadczenie + + + +
    Zdrowie + + / +
    Mana + + / +
    Atrybuty + + + + + +
    Umiętności + + + + + +
    + + + + + +
    Koszty zaklęć + + +
    + + + +
    + + + wróć do listy +
    +
    +
    + + + 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 @@ + + + + + + +
    + + + + + + + + + + + + + + + + + + + + +
    IDImięGraczOstatnia 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Zapisz jako ID + + Zmień by utworzyć kopię. +
    Nazwa + +

    Główny atak + + + + +
    + + +
    Drugi atak + + + + +
    + + +

    Obrona + + +
    + + +
    Pancerz + + + +
    Zdrowie + + + + Punkty zdrowia na turę. +

    + + + wróć do listy +
    +
    +
    + + + 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 + + + +
    +
    + +
    +

    + + + +

    +
    + +
    + + + + + + + + + + + + + + + + +
    IDNazwa + +
    ${item/combat_unit_id}${item/name}edytuj
    +
    + + + 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 @@ + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    Wartość bazowa + + wycena = wartość bazowa * (cecha1 * mnożnik1 + cecha2 * mnożnik2 + ...) +
    Typ przedmiotuMnożniki
    ${row/name} + PSTR: + + + PATK: + + +
    + PDEF: + + + PRES: + + +
    + MSTR: + + + MATK: + + +
    + MDEF: + + + MRES: + + +
    + Pancerz: + + Szybkość: + + Regeneracja: + +
    + +
    +
    + + + 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 @@ + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Stronicowanie + ilość pozycji na stronach statystyk
    + ilość pozycji na stronie poczty lub ogłoszeń
    + ilość postaci na liście w otoczeniu +
    Logowanie + + +
    Rejestracja + + +
    Przeliczenia + + +
    Endgame + + +
    Tury + + +
    Lokacja startowa + + Domyślny respawn dla świeżo założonej postaci. +
    Uzdrowiciel + Zdrowie: + - + Mana: + - + Ile ma leczyć za 1 złota. +
    Misje w świątyni + minimalny EXP gracza + minimalny EXP dla regeneracji +
    Frakcje + mnożnik spadku siły frakcji
    +
    Aktywacja endgame + minimalny poziom postaci + minimalna ranga postaci +
    Komunikat globalny + +
    Generator + ustawienia generatora +
    + +
    +
    + + + 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Zapisz jako ID + + Zmień by utworzyć kopię. +
    Nazwa + + Wyświetlana w Badaniu Terenu itp. +
    Skrypt + + Nazwa skryptu do wykonania. +
    Notatki + +
    Ściągawka, nie wyświetlana nigdzie w grze. +
    + + + wróć do listy +
    +
    +
    + + + 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 + + + +
    +
    + +
    + + + + + + + + + + + + + + + + +
    IDNazwa + +
    ${item/event_id}${item/name}edytuj
    +
    + + + 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 + + + + + + + + + + + + + + + + + + + + + + +
    ID + + Zmień by utworzyć kopię. +
    Nazwa + +
    Potęga + +
    + + + wróć do listy +
    +
    +
    + +

    Rangi

    + +
    +
    +Nowa ranga + + +
    + +
    +
    + +
    + + + + + + + + + + + + + + + + + +
    NumerPunktyTytuł + +
    ${item/rank_id}${item/min_points}${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 + + + +
    +
    + +
    + + + + + + + + + + + + + + + + +
    IDNazwa + +
    ${item/faction_id}${item/name}edytuj
    +
    + + + 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ID docelowy Może nadpisać istniejący przedmiot!
    Nazwa
    Typ + Broń: +
    + Pancerz: +
    Wartość Planowana wartość przedmiotu.
    Szablon + +
    + + ustawienia generatora +
    +
    +
    + + +
    +
    +Mieszator + + + + + + + + + + + + + + + + + + + + + + +
    ID docelowy Może nadpisać istniejący przedmiot!
    Nazwa
    Przedmioty bazowe + + + szukaj +
    + + + szukaj +
    +
    +
    + + + + 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)

    + + + + + +
    poziomcena
    ${repeat/row/key}${row} zł
    +
    + +
    +

    Ile bonusu powinien mieć przedmiot za potwora

    + + + + + +
    bonus %bonus stałycena
    ${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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ID + + Zmień by utworzyć kopię. +
    Nazwa + +
    Wartość + + Cena zakupu i koszt przypisania. +
    + Wycena: ${item/suggested_value} + Wyliczana automatycznie z bonusów przy zapisie. +
    Typ + +
    Typ obrażeń + + Ignorowane dla typów innych niż broń. +
    Własność specjalna + + +
    Opis + +
    Opis statów doklejany jest automatycznie. +
    + + + wróć do listy +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Cecha bojowaBonus %Bonus stały
    Siła fizyczna
    Trafienie fizyczne
    Obrona fizyczna
    Odporność fizyczna
    Siła magiczna
    Trafienie magiczne
    Obrona magiczna
    Odporność magiczna
    Pancerznie dotyczy
    Szybkośćnie dotyczy
    Regeneracjanie dotyczy
    +
    +
    + + + 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 + + + + + + + + + + + + + + + + + +
    ID + + Zmień by utworzyć kopię. +
    Nazwa + +
    + + + wróć do listy +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Cecha bojowaBonus %Bonus stały
    Szansa na +Szansa na -Szansa na +Szansa na -
    Siła fizyczna
    Trafienie fizyczne
    Obrona fizyczna
    Odporność fizyczna
    Siła magiczna
    Trafienie magiczne
    Obrona magiczna
    Odporność magiczna
    Pancerznie dotyczy
    Szybkośćnie dotyczy
    Regeneracjanie dotyczy
    +
    +
    + + + 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 + + + +
    +
    + +
    + + + + + + + + + + + + + + + + +
    IDNazwa + +
    ${row/id}${row/name}edytuj
    +
    + + + 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 + + + + +
    +
    + +
    +

    + + + + +

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    IDNazwaTypWartość + + Staty
    WycenaWartości
    ${item/item_id}${item/name}${item/type} (${item/damage_type})${item/value}edytuj${item/suggested_value} + ${item/pstr_p} ${item/pstr_c} ${item/patk_p} ${item/patk_c} / + ${item/pdef_p} ${item/pdef_c} ${item/pres_p} ${item/pres_c} / + ${item/mstr_p} ${item/mstr_c} ${item/matk_p} ${item/matk_c} / + ${item/mdef_p} ${item/mdef_c} ${item/mres_p} ${item/mres_c} / + ${item/armor} ${item/speed} ${item/regen} / ${item/special_type} ${item/special_param} +
    +
    + + + 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Zapisz jako ID + + Zmień by utworzyć kopię. +
    Nazwa + +
    Region + +
    Typ + +
    Szansa zdarzenia + + / + Łączna szansa na zdarzenie (skrypt lub atak potwora) przy odwiedzaniu lokacji. +
    Boss + + szukaj + +
    Opis + +
    Obrazek (URL) + +
    Frakcja + + +
    + + + wróć do listy +
    +
    +
    + +

    Wędrówka

    + +
    +
    +Nowa ścieżka + +szukaj + + +Może nadpisać istniejące ścieżki. +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + +
    ID celuNazwa celuNazwa ścieżkiKoszt + +
    ${item/destination_id}${item/destination_name}użyj nazwy celunie znaleziono${item/cost_gold} zł / ${item/cost_mana} MPedytuj + + +
    +
    + +

    Potwory

    + +
    +
    +Nowy potwór + +szukaj + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    IDNazwaSzansa + +
    ${item/monster_id}${item/monster_name}nie znaleziono${item/chance}edytuj
    +
    + +

    Zdarzenia

    + +
    +
    +Nowe zdarzenie specjalne + + +
    +
    + +
    + + + + + + + + + + + + + + + + + + +
    SkryptSzansaParametry + +
    ${item/event_id}${item/chance}brakedytuj
    +
    + +

    Usługi

    + +
    +
    +Nowa usługa + + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + +
    IDNazwaTyp + +
    ${item/service_id}${item/service_name}${item/service_type}nie znaleziono
    +
    + + + 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 + + + + + + + + + + + + + + + + + + +
    Szansa + + Względna częstość występowania zdarzenia. +
    Parametry + + Parametry skryptu, oddzielone przecinkami. +
    + + + wróć do listy +
    +
    +
    + + + 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 + + + + + + + + + + + + + +
    Szansa + + Względna częstość występowania potwora. +
    + + + wróć do listy +
    +
    +
    + + + 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 + + + + + + + + + + + + + + + + + + + + +
    Nazwa ścieżkiPusta nazwa oznacza użycie nazwy celu.
    Koszt podróży + + +
    + + + wróć do listy +
    +
    +
    + + + 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 + + + +
    +Nazwa Otchłań Narodzin jest zarezerwowana dla strony respawnu. +
    +
    + +
    +

    + + + + +

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    IDNazwaRegionTypSzansaŚcieżkiPotwory
    ${item/location_id}${item/name}brak${item/type}${item/chance1} / ${item/chance2}edytuj${x}
    ${x}
    +
    + + + 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 @@ + + + + + + + +
    + +
    +
    + + + + + +<link rel="stylesheet" href="../static/basic.css"/> +</tal:block> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="../macros.xml/pageMessages"/> + +<form tal:condition="map" action="" method="post"> +<fieldset> +<legend>Dane mapu</legend> +<table> + +<tr> +<th>ID</th> +<td> + <input name="id" size="32" value="${map/map_id}"/> + <i>Zmień by utworzyć kopię.</i> +</td> +</tr> + +<tr> +<th>Nazwa</th> +<td> + <input name="name" size="48" value="${map/name}"/> +</td> +</tr> + +<tr> +<th>URL</th> +<td> + <input name="url" size="48" value="${map/url}"/> + <i>URL do pliku mapy, jeśli względny to względem katalogu <a href="../static/">static/</a> gry.</i> +</td> +</tr> + +<tr> +<th>Kolejność</th> +<td> + <input name="sort" size="6" value="${map/sort}"/> +</td> +</tr> + +<tr> +<th></th> +<td> + <button type="reset">cofnij</button> + <button>zapisz</button> + <a href="maps">wróć do listy</a> +</td> +<td></td> +</tr> + +</table> +</fieldset> +</form> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="../macros.xml/pageMessages"/> + +<form action="" method="post"> +<fieldset> +<legend>Nowa mapa</legend> +<label>ID: <input name="newId"/></label> +<label>Nazwa: <input name="newName"/></label> +<button>dodaj</button> +</fieldset> +</form> + +<form action="" method="post" tal:condition="maps"> +<table class="border"> +<thead> +<tr> + <th>ID</th> + <th>Nazwa</th> + <th>URL</th> + <th>Kolejność</th> + <th colspan="2"> + <button>usuń zaznaczone</button> + </th> +</tr> +</thead> +<tbody> +<tr tal:repeat="item maps"> + <td>${item/map_id}</td> + <td>${item/name}</td> + <td>${item/url}</td> + <td>${item/sort}</td> + <td><a href="map-edit?id=${item/map_id}">edytuj</a></td> + <td><label><input type="checkbox" name="del[]" value="${item/map_id}"/> usuń</label></td> +</tr> +</tbody> +</table> +</form> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="../macros.xml/pageMessages"/> + +<form tal:condition="drop" action="" method="post"> +<fieldset> +<legend>Dane dropu</legend> +<table> + +<tr> +<th>Szansa</th> +<td> + <input name="chance" size="8" value="${drop/chance}"/> + <i>Względna częstość wypadania przedmiotu.</i> +</td> +</tr> + +<tr> +<th></th> +<td> + <button type="reset">cofnij</button> + <button>zapisz</button> + <a href="monster-edit?id=${drop/monster_id}">wróć do listy</a> +</td> +<td></td> +</tr> + +</table> +</fieldset> +</form> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="../macros.xml/pageMessages"/> + +<form tal:condition="monster" action="" method="post"> +<fieldset> +<legend>Dane potwora</legend> +<table> + +<tr> +<th>Zapisz jako ID</th> +<td> + <input name="monster_id" size="32" value="${monster/monster_id}"/> + <i>Zmień by utworzyć kopię.</i> +</td> +</tr> + +<tr> +<th>Nazwa</th> +<td> + <input name="name" size="48" value="${monster/name}"/> +</td> +</tr> + +<tr> +<th>Poziom</th> +<td> + <input name="level" size="8" value="${monster/level}"/> + <i>Także ilość doświadczenia za pokonanie potwora.</i> +</td> +</tr> + +<tr> +<th>Klasa</th> +<td><b>${className} (${monster/class})</b> <i>Wyznaczana automatycznie z poziomu.</i></td> +</tr> + +<tr> +<th>Złoto</th> +<td> + <input name="gold" size="8" value="${monster/gold}"/> +</td> +</tr> + +<tr> +<th>Szansa dropu</th> +<td> + <input name="chance1" size="4" value="${monster/chance1}"/> + / <input name="chance2" size="4" value="${monster/chance2}"/> + <i>Łączna szansa na zdobycie przedmiotu.</i> +</td> +</tr> + +<tr> +<th>Tytuł</th> +<td> + <select name="title_id"> + <option value="" tal:attributes="selected not:monster/title_id"><brak></option> + <option tal:repeat="item titles" tal:attributes="value item/title_id; selected php:monster.title_id == item['title_id']"><${item/title_id}> ${item/name_f} / ${item/name_m} / ${item/name_n}</option> + </select> +</td> +</tr> + +<tr> +<th>Jednostka bojowa</th> +<td> + <select name="combat_unit_id"> + <option value="" tal:attributes="selected not:monster/combat_unit_id"><brak></option> + <option tal:repeat="item combatUnits" tal:attributes="value item/combat_unit_id; selected php:monster.combat_unit_id == item['combat_unit_id']"><${item/combat_unit_id}> ${item/name}</option> + </select> +</td> +</tr> + +<tr> +<th></th> +<td> + <button type="reset">cofnij</button> + <button>zapisz</button> + <a href="monsters">wróć do listy</a> +</td> +<td></td> +</tr> + +</table> +</fieldset> +</form> + +<h2>Upuszczane przedmioty</h2> + +<form action="" method="post"> +<fieldset> +<legend>Nowy przedmiot</legend> + +<label>ID: <input name="id" id="searchItem" value=""/></label> +<img src="../static/search.png" alt="szukaj" data-search-type="i" data-search-target="searchItem"/> +<button name="addDrop" value="1">dodaj</button> +</fieldset> +</form> + +<form action="" method="post" tal:condition="drops"> +<table class="border"> +<thead> +<tr> + <th>ID</th> + <th>Nazwa</th> + <th>Szansa</th> + <th colspan="2"> + <button>usuń zaznaczone</button> + </th> +</tr> +</thead> +<tbody> +<tr tal:repeat="item drops"> + <td>${item/item_id}</td> + <td>${item/name}</td> + <td>${item/chance}</td> + <td><a href="monster-drop-edit?id=${item/monster_id}&id2=${item/item_id}">edytuj</a></td> + <td> + <label><input type="checkbox" name="del[]" value="${item/item_id}"/> usuń</label> + </td> +</tr> +</tbody> +</table> +</form> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="../macros.xml/pageMessages"/> + +<form action="" method="post"> +<fieldset> +<legend>Nowy potwór</legend> +<label>ID: <input name="newId"/></label> +<label>Nazwa: <input name="newName"/></label> +<button>dodaj</button> +</fieldset> +</form> + +<form action="" method="post"> +<p> +<label>ID: <input name="filter[id]" value="${filter/id}"/></label> +<label>Nazwa: <input name="filter[name]" value="${filter/name}"/></label> +<label>Klasa: + <select name="filter[class]"> + <option value="" tal:attributes="selected not:filter/class"><wszystkie></option> + <option tal:repeat="item monsterClasses" tal:attributes=" value repeat/item/key; selected php:filter.class == repeat.item.key">${item}</option> + </select> +</label> +<button>szukaj</button> +</p> +</form> + +<form action="" method="post" tal:condition="monsters"> +<table class="border"> +<thead> +<tr> + <th>ID</th> + <th>Nazwa</th> + <th>Klasa</th> + <th>Poziom</th> + <th colspan="2"><button>usuń zaznaczone</button></th> + <th>Złoto</th> + <th>Szansa</th> + <th>Dropy</th> + <th>Jednostka</th> + <th>Tytuł</th> +</tr> +</thead> +<tbody> +<tr tal:repeat="item monsters"> + <td>${item/monster_id}</td> + <td>${item/name}</td> + <td>${item/class}</td> + <td>${item/level}</td> + <td><a href="monster-edit?id=${item/monster_id}">edytuj</a></td> + <td><label><input type="checkbox" name="del[]" value="${item/monster_id}"/> usuń</label></td> + <td>${item/gold}</td> + <td>${item/chance1} / ${item/chance2}</td> + <td><tal:block repeat="x item/drops">${x}<br tal:condition="not:repeat/x/end"/></tal:block></td> + <td>${item/combat_unit_id}</td> + <td>${item/title_id}</td> +</tr> +</tbody> +</table> +</form> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="../macros.xml/pageMessages"/> + +<form action="" method="post"> +<fieldset> +<table> + +<tr> +<th>ID</th> +<td> + <select name="id"> + <option value="" selected=""><dodaj nowy wpis></option> + <option tal:repeat="item entries" value="${item/id}">[${item/published}] ${item/title}</option> + </select> + <i>Gra wyświetla tylko najnowsze wpisy.</i> +</td> +</tr> + +<tr> +<th>Autor</th> +<td><input name="author" size="40"/></td> +</tr> + +<tr> +<th>Tytuł</th> +<td><input name="title" size="60"/> <i>Unikalny w ramach danego dnia.</i></td> +</tr> + +<tr> +<th>Treść (HTML)</th> +<td><textarea name="content" cols="80" rows="5"></textarea></td> +</tr> + +<tr> + <th></th> + <td> + <button>zapisz</button> + </td> +</tr> + +</table> +</fieldset> +</form> + +<section tal:repeat="item entries"> +<h2>${item/title}</h2> +<form action="" method="post"> +<p> + Dodany: ${item/published}<br/>Ostatnio zmieniany: ${item/updated}<br/>Autor: ${item/author} + <input type="hidden" name="del" value="${item/id}"/> + <button>usuń</button> +</p> +</form> +<blockquote>${item/content}</blockquote> +</section> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="../macros.xml/pageMessages"/> + +<form tal:condition="player" action="" method="post"> +<fieldset> +<legend>Dane gracza</legend> +<table> + +<tr> +<th>Login</th> +<td><b>${player/login}</b></td> +</tr> + +<tr> +<th>Rejestracja</th> +<td><input name="date_created" size="32" value="${player/date_created}"/></td> +</tr> + +<tr> +<th>Ostatni login</th> +<td><input name="last_login" size="32" value="${player/last_login}"/></td> +</tr> + +<tr> +<th>Zmiana hasła</th> +<td> + <input name="pass1" type="password" autocomplete="off" size="32"/> + <input name="pass2" type="password" autocomplete="off" size="32"/> +</td> +</tr> + +<tr> +<th>Uprawnienia</th> +<td> + <label><input type="checkbox" name="roles[chat]" tal:attributes="checked playerRoles/chat"/> pisanie w ogłoszeniach</label> + <label><input type="checkbox" name="roles[login]" tal:attributes="checked playerRoles/login"/> logowanie do gry (nieużywane)</label> +</td> +</tr> + +<tr> +<th>Nazwa</th> +<td><input name="name" size="48" value="${player/name}"/></td> +</tr> + +<tr> +<th>Styl strony</th> +<td> + <label tal:repeat="skin skins"> + <input type="radio" name="skin" value="${skin}" tal:attributes="checked php:skin==player.skin"/>${skin} + </label> +</td> +</tr> + +<tr> +<th>Email</th> +<td><input name="email" size="64" value="${player/email}"/></td> +</tr> + +<tr> +<th></th> +<td> + <button type="reset">cofnij</button> + <button name="save">zapisz</button> + <a href="players">wróć do listy</a> +</td> +<td></td> +</tr> + +</table> +</fieldset> +</form> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="../macros.xml/pageMessages"/> + +<form action="" method="post" tal:condition="rows"> +<table class="border"> +<thead> +<tr> + <th>ID</th> + <th>Login</th> + <th>Rejestracja</th> + <th>Ostatni login</th> + <th>Prawa</th> + <th></th> + <th>Postacie</th> +</tr> +</thead> +<tbody> +<tr tal:repeat="item rows"> + <td>${item/player_id}</td> + <td>${item/login}</td> + <td>${item/date_created}</td> + <td>${item/last_login}</td> + <td>${item/roles}</td> + <td><a href="player-edit?id=${item/player_id}">edytuj</a></td> + <td><tal:block repeat="x item/characters">${x}<br tal:condition="not:repeat/x/end"/></tal:block></td> +</tr> +</tbody> +</table> +</form> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="../macros.xml/pageMessages"/> + +<form tal:condition="region" action="" method="post"> +<fieldset> +<legend>Dane regionu</legend> +<table> + +<tr> +<th>ID</th> +<td> + <input name="id" size="32" value="${region/region_id}"/> + <i>Zmień by utworzyć kopię.</i> +</td> +</tr> + +<tr> +<th>Nazwa</th> +<td> + <input name="name" size="48" value="${region/name}"/> +</td> +</tr> + +<tr> +<th>Respawn</th> +<td> + <select name="respawn_id"> + <option value="" tal:attributes="selected not:region/respawn_id"><brak></option> + <option tal:repeat="item locations" tal:attributes=" value item/location_id; selected php:region.respawn_id == item['location_id']">${item/name}</option> + </select> + <i>Lokacja w której może odrodzić się postać jeśli choć raz odwiedziła dany region.</i> +</td> +</tr> + +<tr> +<th>Obrazek (URL)</th> +<td> + <input name="picture_url" size="48" value="${region/picture_url}"/> +</td> +</tr> + +<tr> +<th></th> +<td> + <button type="reset">cofnij</button> + <button>zapisz</button> + <a href="regions">wróć do listy</a> +</td> +<td></td> +</tr> + +</table> +</fieldset> +</form> + +<h2>Lokacje</h2> + +<form action="locations" method="post"> +<p> + <input type="hidden" name="filter[id]" value=""/> + <input type="hidden" name="filter[name]" value=""/> + <input type="hidden" name="filter[region_id]" value="${region/region_id}"/> + <button>pokaż lokacje</button> +</p> +</form> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="../macros.xml/pageMessages"/> + +<form action="" method="post"> +<fieldset> +<legend>Nowy region</legend> +<label>ID: <input name="newId"/></label> +<label>Nazwa: <input name="newName"/></label> +<button>dodaj</button> +</fieldset> +</form> + +<form action="" method="post" tal:condition="regions"> +<table class="border"> +<thead> +<tr> + <th>ID</th> + <th>Nazwa</th> + <th>Respawn</th> + <th colspan="2"> + <button>usuń zaznaczone</button> + </th> +</tr> +</thead> +<tbody> +<tr tal:repeat="item regions"> + <td>${item/region_id}</td> + <td>${item/name}</td> + <td tal:condition="item/respawn_name"><a href="location-edit?id=${item/respawn_id}">${item/respawn_name}</a></td> + <td tal:condition="not:item/respawn_name"><i>nie znaleziono</i></td> + <td><a href="region-edit?id=${item/region_id}">edytuj</a></td> + <td><label><input type="checkbox" name="del[]" value="${item/region_id}"/> usuń</label></td> +</tr> +</tbody> +</table> +</form> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="../macros.xml/pageMessages"/> + +<form action="" method="post"> +<fieldset> +<legend>Armageddon</legend> + +<button name="reset" value="characters">postacie</button> +<i>Kasuje większość statów postaci, zachowuje jedynie imiona, płeć itp.</i> +<br/> +<button name="reset" value="history">historia</button> +<i>Czyści pocztę, ogłoszenia oraz historię przeliczeń i pojedynków.</i> + +</fieldset> +</form> + + +<form action="" method="post"> +<fieldset> +<legend>Przeliczenia statów</legend> + +<i>Wszystkie operacje są czasochłonne, nie odpalać zbyt często...</i> +<br/> +<button name="reset" value="items">przedmioty</button> +<i>Masowo waliduje przedmioty i uaktualnia wycenę.</i> + +</fieldset> +</form> + + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> + +<form action="" method="post"> +<p> +<label>ID: <input name="id" value="${inputId}"/></label> +<label>Nazwa: <input name="name" value="${inputName}"/></label> +<button>szukaj</button> +</p> +</form> + +<table tal:condition="results"> +<tr> + <th>ID</th><th>Nazwa</th><td></td> +</tr> +<tr tal:repeat="row results"> + <td>${row/id}</td><td>${row/name}</td> + <td><input type="button" value="wybierz" data-search-result="${row/id}"/></td> +</tr> +</table> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="../macros.xml/pageMessages"/> + +<form tal:condition="service" action="" method="post"> +<fieldset> +<legend>Dane usługi</legend> +<table> + +<tr> +<th>ID</th> +<td> + <input name="id" size="32" value="${service/service_id}"/> + <i>Zmień by utworzyć kopię.</i> +</td> +</tr> + +<tr> +<th>Nazwa</th> +<td> + <input name="name" size="48" value="${service/name}"/> +</td> +</tr> + +<tr> +<th>Typ</th> +<td> + <label tal:repeat="item serviceTypes"><input type="radio" name="type" tal:attributes="value repeat/item/key; checked php:service.type == repeat.item.key"/> ${item}</label> +</td> +</tr> + +<tr> +<th>Frakcja</th> +<td> + <select name="faction_id"> + <option value="" tal:attributes="selected not:service/faction_id"><brak></option> + <option tal:repeat="item factions" tal:attributes=" value item/faction_id; selected php:service.faction_id == item['faction_id']">${item/name}</option> + </select> + <label>Ranga: <input name="rank_id" value="${service/rank_id}" size="4"/></label> +</td> +</tr> + +<tr> +<th>Opis</th> +<td> + <textarea name="desc" cols="80" rows="5">${service/description}</textarea> +</td> +</tr> + +<tr> +<th></th> +<td> + <button type="reset">cofnij</button> + <button>zapisz</button> + <a href="services">wróć do listy</a> +</td> +</tr> + +</table> +</fieldset> +</form> + +<h2>Oferta sklepu</h2> + +<form action="" method="post"> +<fieldset> +<legend>Nowy przedmiot</legend> + +<label>ID: <input name="id" id="searchItem" value=""/></label> +<img src="../static/search.png" alt="szukaj" data-search-type="i" data-search-target="searchItem"/> +<button name="addItem" value="1">dodaj</button> +</fieldset> +</form> + +<form action="" method="post" tal:condition="serviceItems"> +<table class="border"> +<thead> +<tr> + <th>ID</th> + <th>Nazwa</th> + <th>Typ</th> + <th>Ilość</th> + <th> + <button>usuń zaznaczone</button> + </th> +</tr> +</thead> +<tbody> +<tr tal:repeat="item serviceItems"> + <td>${item/item_id}</td> + <td>${item/name}</td> + <td>${item/type}</td> + <td tal:condition="not:item/_drop">∞</td> + <td tal:condition="item/_drop">${item/quantity}</td> + <td> + <label><input type="checkbox" name="del[]" value="${item/item_id}"/> usuń</label> + </td> +</tr> +</tbody> +</table> +</form> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="../macros.xml/pageMessages"/> + +<form action="" method="post"> +<fieldset> +<legend>Nowa usługa</legend> +<label>ID: <input name="newId"/></label> +<label>Nazwa: <input name="newName"/></label> +<button>dodaj</button> +</fieldset> +</form> + +<form action="" method="post" tal:condition="services"> +<table class="border"> +<thead> +<tr> + <th>ID</th> + <th>Nazwa</th> + <th>Typ</th> + <th>Frakcja</th> + <th>Ranga</th> + <th colspan="2"> + <button>usuń zaznaczone</button> + </th> +</tr> +</thead> +<tbody> +<tr tal:repeat="item services"> + <td>${item/service_id}</td> + <td>${item/name}</td> + <td>${item/type}</td> + <td tal:content="item/faction_id | default"><i>brak</i></td> + <td>${item/rank_id}</td> + <td><a href="service-edit?id=${item/service_id}">edytuj</a></td> + <td><label><input type="checkbox" name="del[]" value="${item/service_id}"/> usuń</label></td> +</tr> +</tbody> +</table> +</form> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="../macros.xml/pageMessages"/> + +<form tal:condition="title" action="" method="post"> +<fieldset> +<legend>Dane tytułu</legend> +<table> + +<tr> +<th>ID</th> +<td> + <input name="id" size="32" value="${title/title_id}"/> + <i>Zmień by utworzyć kopię.</i> +</td> +</tr> + +<tr> +<th>Forma żeńska</th> +<td> + <input name="name_f" size="48" value="${title/name_f}"/> +</td> +</tr> + +<tr> +<th>Forma męska</th> +<td> + <input name="name_m" size="48" value="${title/name_m}"/> +</td> +</tr> + +<tr> +<th>Forma nijaka</th> +<td> + <input name="name_n" size="48" value="${title/name_n}"/> +</td> +</tr> + +<tr> +<th>Typ</th> +<td> + <label><input type="radio" name="type" value="normal" tal:attributes="checked php:title.type eq 'normal'"/> normalny</label> + <label><input type="radio" name="type" value="special" tal:attributes="checked php:title.type eq 'special'"/> specjalny</label> + <i>Tytuły specjalne nie są kasowane przy resecie postaci.</i> +</td> +</tr> + +<tr> +<th></th> +<td> + <button type="reset">cofnij</button> + <button>zapisz</button> + <a href="titles">wróć do listy</a> +</td> +<td></td> +</tr> + +</table> +</fieldset> +</form> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<tal:block metal:use-macro="macros.xml/pageMetadata"/> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="../macros.xml/pageMessages"/> + +<form action="" method="post"> +<fieldset> +<legend>Nowy tytuł</legend> +<label>ID: <input name="newId"/></label> +<button>dodaj</button> +</fieldset> +</form> + +<form action="" method="post" tal:condition="titles"> +<table class="border"> +<thead> +<tr> + <th>ID</th> + <th>Forma żeńska</th> + <th>Forma męska</th> + <th>Forma nijaka</th> + <th>Typ</th> + <th colspan="2"> + <button>usuń zaznaczone</button> + </th> +</tr> +</thead> +<tbody> +<tr tal:repeat="item titles"> + <td>${item/title_id}</td> + <td>${item/name_f}</td> + <td>${item/name_m}</td> + <td>${item/name_n}</td> + <td>${item/type}</td> + <td><a href="title-edit?id=${item/title_id}">edytuj</a></td> + <td><label><input type="checkbox" name="del[]" value="${item/title_id}"/> usuń</label></td> +</tr> +</tbody> +</table> +</form> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<head><tal:block metal:use-macro="macros.xml/pageMetadata"/></head> +<body> +<tal:block metal:use-macro="macros.xml/pageHeader"/> +<tal:block metal:use-macro="macros.xml/pageMessages"/> + +<tal:block content="structure eventLog"></tal:block> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</body> +</html> 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 @@ +<section> +<form action="" method="post"> + <h1>Konto</h1> + <p> + Na koncie masz <b>${goldBank}</b> sztuk złota, + w sakiewce <b>${goldPurse}</b> sztuk złota. + </p> + <p> + <label>Podejmij: <input name="getGold" value=""/></label> + <label>Wpłać: <input name="putGold" value=""/></label> + <button>wykonaj</button> + </p> +</form> +</section> + +<section> +<h1>Schowek</h1> +<p tal:condition="not:storage">Twój schowek jest pusty.</p> +<form tal:condition="storage" action="" method="post"> + <p> + <select name="getItem" size="${storageLimit}"> + <option tal:repeat="row storage" value="${row/inventory_id}"> + ${row/item/name} <tal:block condition="exists:row/flags/bound">(przypisany)</tal:block> + </option> + </select> + <button>wyjmij</button> + </p> +</form> +</section> + +<section> +<h1>Plecak</h1> +<p tal:condition="storageFull">Twój schowek jest pełny.</p> +<tal:block condition="not:storageFull"> + <p tal:condition="not:inventory">Nie masz co schować.</p> + <form tal:condition="inventory" action="" method="post"> + <p> + <select name="putItem" size="10"> + <option tal:repeat="row inventory" value="${row/inventory_id}"> + ${row/item/name} <tal:block condition="exists:row/flags/bound">(przypisany)</tal:block> + </option> + </select> + <button>schowaj</button> + </p> + </form> +</tal:block> +</section> 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 @@ +<section> +<h1>Leczenie</h1> +<form action="" method="post"> +<p tal:condition="not:bankEnabled"> + W sakiewce masz <b>${characterData/gold_purse}</b> sztuk złota. +</p> +<p tal:condition="bankEnabled"> + Na koncie masz <b>${characterData/gold_bank}</b> sztuk złota, + w sakiewce <b>${characterData/gold_purse}</b> sztuk złota. + Możesz zapłacić przelewem. +</p> +<p> + <input name="heal" value="1" size="6"/> + <button>opłać leczenie</button> + <i>${deltaHealthMin}-${deltaHealthMax} zdrowia i ${deltaManaMin}-${deltaManaMax} many za każdą sztukę złota</i> +</p> +</form> +</section> + +<section> +<h1>Odpoczynek</h1> +<form action="" method="post"> +<p> + Zdrowie: <b>${characterData/health} / ${characterData/health_max}</b> + Mana: <b>${characterData/mana} / ${characterData/mana_max}</b> + <button name="rest" value="1">odpocznij 1 turę</button> + <i>Bezpieczniej niż na zewnątrz...</i> +</p> +</form> +</section> 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 @@ +<section> + <h1>${shopName}</h1> + <p tal:condition="shopDescription"><i tal:content="structure shopDescription"></i></p> + <p tal:condition="not:bankEnabled"> + W sakiewce masz <b>${goldPurse}</b> sztuk złota. + </p> + <p tal:condition="bankEnabled"> + Na koncie masz <b>${goldBank}</b> sztuk złota, + w sakiewce <b>${goldPurse}</b> sztuk złota. + Możesz zapłacić przelewem. + </p> +</section> + +<section tal:condition="hasItems"> + <h1>Sprzedaż</h1> + <form action="" method="post"> + <select name="sell[]" size="10" multiple="multiple"> + <optgroup tal:condition="equipment" label="Założone"> + <option tal:repeat="row equipment" value="${row/inventory_id}"> + [${row/_price} zł] ${row/item/name} + <tal:block condition="exists:row/flags/bound">(przypisany)</tal:block> + <tal:block condition="exists:row/flags/identified">(zident.)</tal:block> + </option> + </optgroup> + <optgroup tal:condition="inventory" label="Plecak"> + <option tal:repeat="row inventory" value="${row/inventory_id}"> + [${row/_price} zł] ${row/item/name} + <tal:block condition="exists:row/flags/bound">(przypisany)</tal:block> + <tal:block condition="exists:row/flags/identified">(zident.)</tal:block> + </option> + </optgroup> + <optgroup tal:condition="storage" label="Schowek"> + <option tal:repeat="row storage" value="${row/inventory_id}"> + [${row/_price} zł] ${row/item/name} + <tal:block condition="exists:row/flags/bound">(przypisany)</tal:block> + <tal:block condition="exists:row/flags/identified">(zident.)</tal:block> + </option> + </optgroup> + </select> + <br/> + <button>sprzedaj</button> + <i>Możesz wybrać kilka przedmiotów na raz (SHIFT,CTRL).</i> + </form> +</section> + +<section tal:repeat="group shopItems" class="item-list"> +<h1>${group/name}</h1> +<img src="static/item-types/${repeat/group/key}.gif" alt=""/> +<table class="border"> + +<thead> +<tr> + <th>Przedmiot</th> + <th>Ilość</th> + <th>Cena</th> + <th>Kup</th> + <th style="width:50%">Opis</th> +</tr> +</thead> + +<tbody> +<tr tal:repeat="row group/items"> + <td>${row/name}</td> + <td tal:condition="not:row/_drop"><b>∞</b></td> + <td tal:condition="row/_drop">${row/_quantity} szt.</td> + <td>${row/_price} zł</td> + <td tal:condition="not:row/_canBuy"><i>za mało złota</i></td> + <td tal:condition="row/_canBuy"> + <i tal:condition="row/_soldOff">brak towaru</i> + <form tal:condition="not:row/_soldOff" action="" method="post"> + <button name="buy" value="${row/item_id}">kup</button> + <input name="amount" value="1" size="6"/> + <tal:block condition="row/_canBind"> + <label><input type="checkbox" name="bind" value="1"/>z przypisaniem</label> + </tal:block> + </form> + </td> + <td> + <tal:block condition="row/description"><i>${row/description}</i><br/></tal:block> + ${row/getDescription} + </td> +</tr> +</tbody> + +</table> +</section> 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 @@ +<p> + Zdrowie: <b>${characterData/health} / ${characterData/health_max}</b>, + mana: <b>${characterData/mana} / ${characterData/mana_max}</b>. + <tal:block condition="not:bankEnabled"> + W sakiewce masz <b>${characterData/gold_purse}</b> sztuk złota. + </tal:block> + <tal:block condition="bankEnabled"> + Na koncie masz <b>${characterData/gold_bank}</b> sztuk złota, + w sakiewce <b>${characterData/gold_purse}</b> sztuk złota. + Możesz zapłacić przelewem. + </tal:block> +</p> + +<section tal:condition="itemsToBind"> +<h1>Przypisanie</h1> +<form action="" method="post"> +<p> + <select name="bind" size="10"> + <optgroup tal:condition="exists:itemsToBind/equipment" label="Założone"> + <option tal:repeat="row itemsToBind/equipment" value="${repeat/row/key}"> + [${row/value} zł] ${row/name} + <tal:block condition="exists:row/flags/identified">(zident.)</tal:block> + </option> + </optgroup> + <optgroup tal:condition="exists:itemsToBind/inventory" label="Plecak"> + <option tal:repeat="row itemsToBind/inventory" value="${repeat/row/key}"> + [${row/value} zł] ${row/name} + <tal:block condition="exists:row/flags/identified">(zident.)</tal:block> + </option> + </optgroup> + <optgroup tal:condition="exists:itemsToBind/storage" label="Schowek"> + <option tal:repeat="row itemsToBind/storage" value="${repeat/row/key}"> + [${row/value} zł] ${row/name} + <tal:block condition="exists:row/flags/identified">(zident.)</tal:block> + </option> + </optgroup> + </select> + <br/> + <button>przypisz</button> + <i>Połącz przedmiot ze swoją duszą aby nie tracić go po śmierci...</i> +</p> +</form> +</section> + +<section> +<h1>Ołtarz ofiarny</h1> +<form action="" method="post"> +<p> + <select tal:condition="itemsToOffer" name="offer"> + <option value="" selected=""></option> + <optgroup tal:condition="exists:itemsToOffer/inventory" label="Plecak"> + <option tal:repeat="row itemsToOffer/inventory" value="${repeat/row/key}"> + [${row/value} zł] ${row/name} + <tal:block condition="exists:row/flags/bound">(przypisany)</tal:block> + <tal:block condition="exists:row/flags/identified">(zident.)</tal:block> + </option> + </optgroup> + <optgroup tal:condition="exists:itemsToOffer/storage" label="Schowek"> + <option tal:repeat="row itemsToOffer/storage" value="${repeat/row/key}"> + [${row/value} zł] ${row/name} + <tal:block condition="exists:row/flags/bound">(przypisany)</tal:block> + <tal:block condition="exists:row/flags/identified">(zident.)</tal:block> + </option> + </optgroup> + </select> + <label>Złoto: <input name="pray" value="" size="16"/></label> + <button>złóż ofiarę</button> + <br/> + <i>Możesz otrzymać misję lub uzdrowienie. Pamiętaj: bogowie lubią hojnych...</i> +</p> +</form> +</section> + +<form tal:condition="lastMission" action="" method="post"> +<p> +Obecna misja to <q>${lastMission/_name}</q>, +otrzymana w świątyni <b tal:content="lastMission/service_name | default">???</b> +w przeliczeniu nr <b>${lastMission/rollover_id}</b>. +<br/> +<button name="giveUp" value="1">porzuć misję</button> +<i>Nie dostaniesz nowej misji w tym samym przeliczeniu.</i> +</p> +</form> 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 @@ +<form action="" method="post"> +<p> + <label>Imię postaci: <input name="target" value="${target}" size="32"/></label> + <button name="cast" value="${spellId}">rzuć zaklęcie (${cost} MP)</button> +</p> +</form> + +<tal:block condition="result"> +<h2>${result/char/name}</h2> +<table> +<tr> + <th>Zdrowie</th> + <td>${result/cdata/health} / ${result/cdata/health_max}</td> +</tr> +<tr> + <th>Mana</th> + <td>${result/cdata/mana} / ${result/cdata/mana_max}</td> +</tr> +<tr> + <th>Sakiewka</th> + <td>${result/cdata/gold_purse} złota</td> +</tr> +<tr> + <th>Lokacja</th> + <td>${result/locationName}</td> +</tr> +<tr> + <th>Ekwipunek</th> + <td tal:condition="not:result/equipment"><i>brak</i></td> + <td tal:condition="result/equipment">${result/equipment}</td> +</tr> +</table> +</tal:block> 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 @@ +<form action="" method="post"> +<p> + <label>Nazwa przedmiotu: <input name="target" value="${target}" size="32"/></label> + <button name="cast" value="${spellId}">rzuć zaklęcie (${cost} MP)</button> +</p> +</form> + +<tal:block condition="result"> +<h2>${result/item/name}</h2> +<table> +<tr> + <th>Typ</th> + <td>${result/typeName}</td> +</tr> +<tr tal:condition="result/item/damage_type"> + <th>Obrażenia</th> + <td>${result/damageType}</td> +</tr> +<tr> + <th>Wartość</th> + <td>${result/item/value} złota</td> +</tr> +<tr tal:condition="result/item/description"> + <th>Opis</th> + <td>${result/item/description}</td> +</tr> +</table> +<h2>Występowanie</h2> +<table> +<tr> + <th>Potwory</th> + <td tal:content="result/monsters | default"><i>brak</i></td> +</tr> +<tr> + <th>Sklepy</th> + <td tal:content="result/shops | default"><i>brak</i></td> +</tr> +</table> +</tal:block> 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 @@ +<form action="" method="post"> +<p> + <label>Nazwa potwora: <input name="target" value="${target}" size="32"/></label> + <button name="cast" value="${spellId}">rzuć zaklęcie (${cost} MP)</button> +</p> +</form> + +<tal:block condition="result"> + +<h2>${result/monster/name}</h2> +<table style="margin-bottom:1em"> +<tr> + <th>Klasa</th> + <td>${result/className}</td> +</tr> +<tr> + <th>Poziom</th> + <td>${result/monster/level}</td> +</tr> +<tr> + <th>Zdrowie</th> + <td>${result/unit/health_max}</td> +</tr> +<tal:block define="combatStats result/unit" metal:use-macro="macros.xml/combatStats"/> +<tr> + <th>Złoto</th> + <td>${result/monster/gold}</td> +</tr> +<tr> + <th>Szansa na przedmiot</th> + <td>${result/monster/chance1} / ${result/monster/chance2}</td> +</tr> +<tr> + <th>Tytuł</th> + <td tal:condition="result/title">${result/title/name_f} / ${result/title/name_m} / ${result/title/name_n}</td> + <td tal:condition="not:result/title"><i>brak</i></td> +</tr> +</table> + +<h2>Przedmioty</h2> +<p tal:condition="not:result/items"><i>brak</i></p> +<p tal:condition="result/items">${result/items}.</p> +<h2>Występowanie</h2> +<p tal:condition="not:result/locations"><i>brak</i></p> +<p tal:condition="result/locations">${result/locations}.</p> +</tal:block> 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 @@ +<table> +<thead> +<tr> + <th>Lokacja</th> + <th>Szansa na zdarzenie</th> + <th>Zdarzenia</th> +</tr> +</thead> +<tbody> +<tr tal:repeat="location locations"> + <td>${location/name}</td> + <td>${location/chance1} / ${location/chance2}</td> +<!-- + <td tal:condition="not:location/_monsters"><i>brak</i></td> + <td tal:condition="location/_monsters">${location/_monsters}</td> + <td tal:condition="not:location/_events"><i>brak</i></td> + <td tal:condition="location/_events">${location/_events}</td> +--> + <td> + <tal:block repeat="x location/_monsters">${x}<br tal:condition="not:repeat/x/end"/></tal:block> + <tal:block repeat="x location/_events">${x}<br tal:condition="not:repeat/x/end"/></tal:block> + </td> +</tr> +</tbody> +</table> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<head><tal:block metal:use-macro="macros.xml/pageMetadata"/></head> +<body> +<tal:block metal:use-macro="macros.xml/pageHeader"/> + +<tal:block metal:use-macro="macros.xml/menuBar" define="options menu"/> +<tal:block metal:use-macro="macros.xml/pageMessages"/> + +<p tal:condition="not:battle">Wybrany log nie istnieje.</p> + +<tal:block condition="battle"> + <h1>Lokacja: ${battle/location_name}</h1> + <section tal:content="structure battle/combat_log"></section> +</tal:block> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</body> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<head><tal:block metal:use-macro="macros.xml/pageMetadata"/></head> +<body> +<tal:block metal:use-macro="macros.xml/pageHeader"/> + +<tal:block metal:use-macro="macros.xml/menuBar" define="options menu"/> +<tal:block metal:use-macro="macros.xml/pageMessages"/> + +<table class="border"> + +<tr> +<th>Nr</th> +<th><abbr title="Przeliczenie">Prz.</abbr></th> +<th>Lokacja</th> +<th>Typ walki</th> +<th>Log walki</th> +</tr> + +<tr tal:repeat="item list"> +<td>${item/battle_id}</td> +<td>${item/rollover_id}</td> +<td>${item/location_name}</td> +<td>${item/type}</td> +<td tal:condition="item/log_exists"><a href="?view=${item/battle_id}">pokaż</a></td> +</tr> + +</table> + +<p tal:condition="nextUrl"><a href="${nextUrl}">następna strona...</a></p> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</body> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<head><tal:block metal:use-macro="macros.xml/pageMetadata"/></head> +<body> +<tal:block metal:use-macro="macros.xml/pageHeader"/> + +<tal:block metal:use-macro="macros.xml/menuBar" define="options menu"/> +<tal:block metal:use-macro="macros.xml/pageMessages"/> + +<p tal:condition="not:character">Wybrana postać nie istnieje.</p> + +<section tal:condition="character" class="multicols"> + + <section> + + <table> + <tr tal:condition="character/show_player"><th>Gracz</th><td>${character/player_name}</td></tr> + <tr><th>Postać</th><td>${character/name}</td></tr> + <tr><th>Data narodzin</th><td>${character/date_created}</td></tr> + <tr><th>Płeć</th><td>${genderName}</td></tr> + <tr><th>Poziom</th><td>${character/level}</td></tr> + <tr><th>Doświadczenie</th><td>${character/xp_used}</td></tr> + <tr> + <th>Frakcja</th> + <td tal:condition="not:character/faction_name"><i>brak</i></td> + <td tal:condition="character/faction_name">${character/faction_name}</td> + </tr> + <tr tal:condition="character/rank_name"> + <th>Ranga</th> + <td>${character/rank_name} (${character/rank_id})</td> + </tr> + <tr> + <th>Klan</th> + <td tal:condition="not:character/clan_name"><i>brak</i></td> + <td tal:condition="character/clan_name"> + <a href="stats-clans?view=${character/clan_id}">${character/clan_name}</a> + </td> + </tr> + <tr><th>Pojedynki</th><td><a href="stats-duels?char=${characterId}">pokaż pojedynki postaci</a></td></tr> + <tr tal:condition="mailUrl"><th>Kontakt</th><td><a tal:attributes="href mailUrl">wyślij wiadomość</a></td></tr> + <tr tal:condition="character/titles"><th>Tytuły</th><td>${character/titles}</td></tr> + <tr tal:condition="character/quote"><th>Motto</th><td><q>${character/quote}</q></td></tr> + </table> + + <table tal:condition="character/statistics" tal:define="s character/statistics"> + <caption>Statystyki</caption> + <tr><th>Wykonane misje</th><td>${s/missions}</td></tr> + <tr><th>Wygrane pojedynki</th><td>${s/duel_wins}</td></tr> + <tr><th>Przegrane pojedynki</th><td>${s/duel_losses}</td></tr> + <tr><th>Pokonane słabe potwory</th><td>${s/kills_mob1}</td></tr> + <tr><th>Pokonane średnie potwory</th><td>${s/kills_mob2}</td></tr> + <tr><th>Pokonane silne potwory</th><td>${s/kills_mob3}</td></tr> + <tr><th>Pokonane potwory epickie</th><td>${s/kills_mob4}</td></tr> + </table> + + </section> + + <section tal:condition="character/avatar_url | character/description"> + <p tal:condition="character/avatar_url" class="avatar"> + <img src="${character/avatar_url}" alt="${character/avatar_url}"/> + </p> + <p tal:content="structure character/description"/> + </section> + +</section> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</body> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<head><tal:block metal:use-macro="macros.xml/pageMetadata"/></head> +<body> +<tal:block metal:use-macro="macros.xml/pageHeader"/> + +<tal:block metal:use-macro="macros.xml/menuBar" define="options menu"/> +<tal:block metal:use-macro="macros.xml/pageMessages"/> + +<table class="border"> + +<tr> +<th>ID</th> +<tal:block repeat="item headers"> +<th><a href="?sort=${repeat/item/key}" tal:omit-tag="exists:item/selected"> +<abbr tal:condition="exists:item/abbr" title="${item/name}">${item/abbr}</abbr> +<tal:block condition="not:exists:item/abbr">${item/name}</tal:block> +</a></th> +</tal:block> +</tr> + +<tr tal:repeat="item list"> +<td>${item/character_id}</td> +<td><a href="?view=${item/character_id}">${item/name}</a></td> +<td>${item/level}</td> +<td>${item/xp_used}</td> +<td tal:condition="not:item/faction_id"><i>brak</i></td> +<td tal:condition="item/faction_id">${item/faction_id} (r${item/rank_id})</td> +<td tal:condition="not:item/clan_id"><i>brak</i></td> +<td tal:condition="item/clan_id"><a href="stats-clans?view=${item/clan_id}">${item/clan_id}</a></td> +<td>${item/date_created}</td> +<td>${item/last_action}</td> +<td>${item/duel_wins}</td> +<td>${item/duel_losses}</td> +</tr> + +</table> + +<p tal:condition="nextUrl"><a href="${nextUrl}">następna strona...</a></p> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</body> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<head><tal:block metal:use-macro="macros.xml/pageMetadata"/></head> +<body> +<tal:block metal:use-macro="macros.xml/pageHeader"/> + +<tal:block metal:use-macro="macros.xml/menuBar" define="options menu"/> +<tal:block metal:use-macro="macros.xml/pageMessages"/> + +<p tal:condition="not:clan">Wybrany klan nie istnieje.</p> +<tal:block> + +<section tal:condition="clan" class="multicols"> + + <table> + <tr><th>ID</th><td>${clan/clan_id}</td></tr> + <tr><th>Nazwa</th><td>${clan/name}</td></tr> + <tr><th>Przywódca</th><td><a href="stats-characters?view=${clan/leader_id}">${clan/leader_name}</a></td></tr> + <tr><th>Data założenia</th><td>${clan/date_created}</td></tr> + <tr><th>Liczebność</th><td>${clan/members}</td></tr> + <tr> + <th>Postacie</th> + <td><a href="stats-characters?clan=${clan/clan_id}">pokaż listę</a></td> + </tr> + </table> + + <section tal:condition="clan/description" tal:content="structure clan/description"/> + +</section> + + +</tal:block> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</body> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<head><tal:block metal:use-macro="macros.xml/pageMetadata"/></head> +<body> +<tal:block metal:use-macro="macros.xml/pageHeader"/> + +<tal:block metal:use-macro="macros.xml/menuBar" define="options menu"/> +<tal:block metal:use-macro="macros.xml/pageMessages"/> + +<table class="border"> + +<tr> +<th>Tag</th> +<th>Nazwa</th> +<th>Przywódca</th> +<th>Wielkość</th> +<th>Data założenia</th> +</tr> + +<tr tal:repeat="item list"> +<td>${item/clan_id}</td> +<td><a href="?view=${item/clan_id}">${item/name}</a></td> +<td tal:condition="not:item/leader_name"><i>brak</i></td> +<td tal:condition="item/leader_name"><a href="stats-characters?view=${item/leader_id}">${item/leader_name}</a></td> +<td>${item/members}</td> +<td>${item/date_created}</td> +</tr> + +</table> + +<p tal:condition="nextUrl"><a href="${nextUrl}">następna strona...</a></p> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</body> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<head><tal:block metal:use-macro="macros.xml/pageMetadata"/></head> +<body> +<tal:block metal:use-macro="macros.xml/pageHeader"/> + +<tal:block metal:use-macro="macros.xml/menuBar" define="options menu"/> +<tal:block metal:use-macro="macros.xml/pageMessages"/> + +<p tal:condition="not:duel">Wybrany log jest niedostępny.</p> + +<tal:block condition="duel"> + <h1>${duel/attacker_name} vs ${duel/defender_name}</h1> + <section tal:content="structure duel/combat_log"></section> +</tal:block> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</body> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<head><tal:block metal:use-macro="macros.xml/pageMetadata"/></head> +<body> +<tal:block metal:use-macro="macros.xml/pageHeader"/> + +<tal:block metal:use-macro="macros.xml/menuBar" define="options menu"/> +<tal:block metal:use-macro="macros.xml/pageMessages"/> + +<table class="border"> + +<tr> +<th>Nr</th> +<th>Data pojedynku</th> +<th><abbr title="Przeliczenie">Prz.</abbr></th> +<th>Ataker</th> +<th>Obrońca</th> +<th>Typ walki</th> +<th>Zwycięzca</th> +<th tal:condition="activeCharacter/character_id">Log walki</th> +</tr> + +<tr tal:repeat="item list"> +<td>${item/duel_id}</td> +<td>${item/date_added}</td> +<td>${item/rollover_id}</td> +<td tal:condition="not:item/attacker_name"><i>postać usunięta</i></td> +<td tal:condition="item/attacker_name"><a href="stats-characters?view=${item/attacker_id}">${item/attacker_name}</a></td> +<td tal:condition="not:item/defender_name"><i>postać usunięta</i></td> +<td tal:condition="item/defender_name"><a href="stats-characters?view=${item/defender_id}">${item/defender_name}</a></td> +<td>${item/type}</td> +<td>${item/winner}</td> +<tal:block condition="activeCharacter/character_id"> + <td tal:condition="not:item/log_exists"><i>niedostępny</i></td> + <td tal:condition="item/log_exists"><a href="?view=${item/duel_id}">pokaż</a></td> +</tal:block> +</tr> + +</table> + +<p tal:condition="nextUrl"><a href="${nextUrl}">następna strona...</a></p> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</body> +</html> 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 @@ +<!DOCTYPE HTML> +<html lang="pl"> +<head><tal:block metal:use-macro="macros.xml/pageMetadata"/></head> +<body> +<tal:block metal:use-macro="macros.xml/pageHeader"/> + +<tal:block metal:use-macro="macros.xml/menuBar" define="options menu"/> +<tal:block metal:use-macro="macros.xml/pageMessages"/> + +<table> +<tr><th>Logowanie</th><td tal:condition="loginEnabled">dostępne</td><td tal:condition="not:loginEnabled">wyłączone</td></tr> +<tr><th>Rejestracja</th><td tal:condition="registerEnabled">dostępna</td><td tal:condition="not:registerEnabled">wyłączona</td></tr> +<tr><th>Przeliczenia</th><td tal:condition="rolloversEnabled">włączone</td><td tal:condition="not:rolloversEnabled">wyłączone</td></tr> +<tr><th>Limit tur</th><td>${turnLimit}</td></tr> +<tr><th>Przyrost tur</th><td>${turnDelta} dziennie</td></tr> +<tr><th>Oblegane caerny</th><td tal:content="caernSieges | default"><i>brak</i></td></tr> +</table> + +<table class="border"> +<caption>Frakcje</caption> +<tr> + <th>ID</th> + <th>Nazwa</th> + <th>Siła</th> + <th>Mnożnik</th> + <th>Członkowie</th> + <th>Posiadane caerny</th> +</tr> +<tr tal:repeat="row factions"> + <td>${repeat/row/key}</td> + <td>${row/name}</td> + <td>${row/power}</td> + <td>${row/powerMult}%</td> + <td>${row/chars}</td> + <td tal:content="row/caerns | default"><i>brak</i></td> +</tr> +</table> + +<table class="border"> +<caption>Ostatnie przeliczenia</caption> +<tr> + <th>Nr</th> + <th>Data</th> + <th>Gracze</th> + <th>Postacie</th> + <th>Klany</th> + <th>Bitwy</th> +</tr> +<tr tal:repeat="row rollovers"> + <td>${row/rollover_id}</td> + <td>${row/date_added}</td> + <td>${row/players_total}</td> + <td>${row/characters_total}</td> + <td>${row/clans_total}</td> + <td tal:condition="row/_battles"> + <tal:block repeat="x row/_battles"> + <a href="stats-battles?view=${repeat/x/key}">${x}</a> + <br tal:condition="not:repeat/x/end"/> + </tal:block> + </td> + <td tal:condition="not:row/_battles"><i>brak</i></td> +</tr> +</table> + +<tal:block metal:use-macro="macros.xml/pageFooter"/> +</body> +</html> 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 <q>Nexus Archive</q> +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 @@ +<!DOCTYPE html> +<html lang="en-GB"> +<head> + <meta charset="UTF-8"> + <title>Options - Nexus Archive Tracker + + + +
    +
    + Tracker options +

    + +

    +

    + +

    +
    +

    + +

    +
    + + + + 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