mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
DB/Structure
* fix data types and data length and add default values where necessary * data should no longer get truncated * misc fixes
This commit is contained in:
@@ -25,7 +25,7 @@ Also, this project is not meant to be used for commercial puposes of any kind!
|
||||
+ [Multibyte String](https://www.php.net/manual/en/book.mbstring.php)
|
||||
+ [File Information](https://www.php.net/manual/en/book.fileinfo.php)
|
||||
+ [GNU Multiple Precision](https://www.php.net/manual/en/book.gmp.php) (When using TrinityCore as auth source)
|
||||
+ MySQL ≥ 5.5.30
|
||||
+ MySQL ≥ 5.7.0 OR MariaDB ≥ 10.6.4 OR similar
|
||||
+ [TDB 335.21101](https://github.com/TrinityCore/TrinityCore/releases/tag/TDB335.21101)
|
||||
+ WIN: php.exe needs to be added to the `PATH` system variable, if it isn't already.
|
||||
+ Tools require cmake: Please refer to the individual repositories for detailed information
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
mb_internal_encoding('UTF-8');
|
||||
mysqli_report(MYSQLI_REPORT_ERROR);
|
||||
|
||||
define('AOWOW_REVISION', 35);
|
||||
define('AOWOW_REVISION', 36);
|
||||
define('OS_WIN', substr(PHP_OS, 0, 3) == 'WIN'); // OS_WIN as per compile info of php
|
||||
define('CLI', PHP_SAPI === 'cli');
|
||||
define('CLI_HAS_E', CLI && // WIN10 and later usually support ANSI escape sequences
|
||||
|
||||
@@ -266,7 +266,7 @@ class RemoteArenaTeamList extends ArenaTeamList
|
||||
|
||||
// basic arena team data
|
||||
foreach (Util::createSqlBatchInsert($data) as $ins)
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_arena_team (?#) VALUES '.$ins, array_keys(reset($data)));
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_arena_team (?#) VALUES '.$ins.' ON DUPLICATE KEY UPDATE `id` = `id`', array_keys(reset($data)));
|
||||
|
||||
// merge back local ids
|
||||
$localIds = DB::Aowow()->selectCol(
|
||||
|
||||
@@ -251,7 +251,7 @@ class RemoteGuildList extends GuildList
|
||||
|
||||
// basic guild data
|
||||
foreach (Util::createSqlBatchInsert($data) as $ins)
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_guild (?#) VALUES '.$ins, array_keys(reset($data)));
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_guild (?#) VALUES '.$ins.' ON DUPLICATE KEY UPDATE `id` = `id`', array_keys(reset($data)));
|
||||
|
||||
// merge back local ids
|
||||
$localIds = DB::Aowow()->selectCol(
|
||||
|
||||
@@ -687,7 +687,7 @@ class RemoteProfileList extends ProfileList
|
||||
if ($guildData)
|
||||
{
|
||||
foreach (Util::createSqlBatchInsert($guildData) as $ins)
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_guild (?#) VALUES '.$ins, array_keys(reset($guildData)));
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_guild (?#) VALUES '.$ins.' ON DUPLICATE KEY UPDATE `id` = `id`', array_keys(reset($guildData)));
|
||||
|
||||
// merge back local ids
|
||||
$localGuilds = DB::Aowow()->selectCol('SELECT realm AS ARRAY_KEY, realmGUID AS ARRAY_KEY2, id FROM ?_profiler_guild WHERE realm IN (?a) AND realmGUID IN (?a)',
|
||||
|
||||
@@ -43,7 +43,7 @@ class SoundList extends BaseType
|
||||
|
||||
if ($this->fileBuffer)
|
||||
{
|
||||
$files = DB::Aowow()->select('SELECT id AS ARRAY_KEY, `id`, `file` AS title, `type`, `path` FROM ?_sounds_files sf WHERE id IN (?a)', array_keys($this->fileBuffer));
|
||||
$files = DB::Aowow()->select('SELECT id AS ARRAY_KEY, `id`, `file` AS title, CAST(`type` AS UNSIGNED) AS type, `path` FROM ?_sounds_files sf WHERE id IN (?a)', array_keys($this->fileBuffer));
|
||||
foreach ($files as $id => $data)
|
||||
{
|
||||
// 3.3.5 bandaid - need fullpath to play via wow API, remove for cata and later
|
||||
|
||||
@@ -1605,7 +1605,7 @@ class SpellList extends BaseType
|
||||
// step 0: get text
|
||||
$data = $this->getField($type, true);
|
||||
if (empty($data) || $data == "[]") // empty tooltip shouldn't be displayed anyway
|
||||
return ['', []];
|
||||
return ['', [], false];
|
||||
|
||||
// step 1: if the text is supplemented with text-variables, get and replace them
|
||||
if ($this->curTpl['spellDescriptionVariableId'] > 0)
|
||||
@@ -1706,7 +1706,7 @@ class SpellList extends BaseType
|
||||
$data = strtr($data, ["\r" => '', "\n" => '<br />']);
|
||||
|
||||
// cache result
|
||||
$this->parsedText[$this->id][$type][User::$localeId][$this->charLevel][(int)$this->interactive] = [$data, $relSpells];
|
||||
$this->parsedText[$this->id][$type][User::$localeId][$this->charLevel][(int)$this->interactive] = [$data, $relSpells, $this->scaling[$this->id]];
|
||||
|
||||
return [$data, $relSpells, $this->scaling[$this->id]];
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -155,7 +155,7 @@ function setup() : void
|
||||
|
||||
if ($rCode == 301 || $rCode == 302)
|
||||
{
|
||||
if (!empty($res['Location']) && preg_match("/(https?:\/\/)(.*)".strtr($testFile, ['/' => '\/', '.' => '\.'])."/i", $res['Location'], $n))
|
||||
if (!empty($res['Location']) && preg_match("/(https?:\/\/)(.*)".strtr($testFile, ['/' => '\/', '.' => '\.'])."/i", is_array($res['Location']) ? array_pop($res['Location']) : $res['Location'], $n))
|
||||
{
|
||||
$protocol = $n[1];
|
||||
$host = $n[2];
|
||||
|
||||
@@ -173,6 +173,8 @@ function siteconfig() : void
|
||||
$inp = ['idx' => ['', false, '/\d/']];
|
||||
if (CLI::read($inp) && $inp && $inp['idx'] !== '')
|
||||
{
|
||||
$inp['idx'] = intVal($inp['idx']);
|
||||
|
||||
// add new php setting
|
||||
if ($inp['idx'] == $sumNum)
|
||||
{
|
||||
|
||||
@@ -52,7 +52,7 @@ function sync(array $s = [], array $b = []) : void
|
||||
DB::Aowow()->query('UPDATE ?_dbversion SET `build` = ?', $_ ? implode(' ', $_) : '');
|
||||
}
|
||||
|
||||
if (!$s && !$_s && !$b && !$_b)
|
||||
if (!$s && !$_s && !$b && !$_b && !CLISetup::getOpt('setup'))
|
||||
CLI::write('no valid table names supplied', CLI::LOG_ERROR);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ SqlGen::register(new class extends SetupScript
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
if (!$ids)
|
||||
DB::Aowow()->query('REPLACE INTO ?_currencies (id, category, itemId) SELECT id, category, itemId FROM dbc_currencytypes');
|
||||
DB::Aowow()->query('REPLACE INTO ?_currencies (`id`, `category`, `itemId`) SELECT `id`, LEAST(`category`, 41), `itemId` FROM dbc_currencytypes');
|
||||
|
||||
$moneyItems = DB::Aowow()->selectCol('SELECT id AS ARRAY_KEY, itemId FROM dbc_currencytypes{ WHERE id IN (?a)}', $ids ?: DBSIMPLE_SKIP);
|
||||
$moneyItems = DB::Aowow()->selectCol('SELECT `id` AS ARRAY_KEY, `itemId` FROM dbc_currencytypes{ WHERE `id` IN (?a)}', $ids ?: DBSIMPLE_SKIP);
|
||||
|
||||
// apply names & cap
|
||||
$moneyNames = DB::World()->select('
|
||||
@@ -52,7 +52,7 @@ SqlGen::register(new class extends SetupScript
|
||||
$strings = $moneyNames[$itemId];
|
||||
else
|
||||
{
|
||||
CLI::write('item #'.$itemId.' required by currency #'.$cId.' not in item_template', CLI::LOG_WARN);
|
||||
CLI::write('item #'.$itemId.' referenced by currency #'.$cId.' not in item_template', CLI::LOG_WARN);
|
||||
$strings = ['name_loc0' => 'Item #'.$itemId.' not in DB', 'iconId' => 0, 'cuFlags' => CUSTOM_EXCLUDE_FOR_LISTVIEW, 'category' => 3];
|
||||
}
|
||||
|
||||
|
||||
@@ -165,9 +165,9 @@ SqlGen::register(new class extends SetupScript
|
||||
|
||||
CLI::write(' - linking to race');
|
||||
|
||||
DB::Aowow()->query('TRUNCATE ?_races_sounds');
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_races_sounds SELECT raceId, soundIdMale, 1 FROM dbc_vocaluisounds WHERE soundIdMale <> soundIdFemale AND soundIdMale > 0');
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_races_sounds SELECT raceId, soundIdFemale, 2 FROM dbc_vocaluisounds WHERE soundIdMale <> soundIdFemale AND soundIdFemale > 0');
|
||||
DB::Aowow()->query('TRUNCATE ?_races_sounds'); // just to silence expected duplicate key errors
|
||||
DB::Aowow()->query('INSERT INTO ?_races_sounds SELECT `raceId`, `soundIdMale`, 1 FROM dbc_vocaluisounds WHERE `soundIdMale` <> `soundIdFemale` AND `soundIdMale` > 0 ON DUPLICATE KEY UPDATE `soundId` = `soundId`');
|
||||
DB::Aowow()->query('INSERT INTO ?_races_sounds SELECT `raceId`, `soundIdFemale`, 2 FROM dbc_vocaluisounds WHERE `soundIdMale` <> `soundIdFemale` AND `soundIdFemale` > 0 ON DUPLICATE KEY UPDATE `soundId` = `soundId`');
|
||||
|
||||
// ps: im too dumb to union this
|
||||
|
||||
@@ -178,8 +178,8 @@ SqlGen::register(new class extends SetupScript
|
||||
|
||||
CLI::write(' - linking to emotes');
|
||||
|
||||
DB::Aowow()->query('TRUNCATE ?_emotes_sounds');
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_emotes_sounds SELECT emotesTextId, raceId, gender + 1, soundId FROM dbc_emotestextsound');
|
||||
DB::Aowow()->query('TRUNCATE ?_emotes_sounds'); // just to silence expected duplicate key errors
|
||||
DB::Aowow()->query('INSERT INTO ?_emotes_sounds SELECT `emotesTextId`, `raceId`, `gender` + 1, `soundId` FROM dbc_emotestextsound ON DUPLICATE KEY UPDATE `emoteId` = `emoteId`');
|
||||
|
||||
|
||||
/*******************/
|
||||
@@ -200,32 +200,32 @@ SqlGen::register(new class extends SetupScript
|
||||
?_creature_sounds (`id`, `greeting`, `farewell`, `angry`, `exertion`, `exertioncritical`, `injury`, `injurycritical`, `death`, `stun`, `stand`, `aggro`, `wingflap`, `wingglide`, `alert`, `fidget`, `customattack`, `loop`, `jumpstart`, `jumpend`, `petattack`, `petorder`, `petdismiss`, `birth`, `spellcast`, `submerge`, `submerged`)
|
||||
SELECT
|
||||
cdi.id,
|
||||
IFNULL(ns.greetSoundId, 0),
|
||||
IFNULL(ns.byeSoundId, 0),
|
||||
IFNULL(ns.angrySoundId, 0),
|
||||
IF(csdA.exertion, csdA.exertion, IFNULL(csdB.exertion, 0)),
|
||||
IF(csdA.exertionCritical, csdA.exertionCritical, IFNULL(csdB.exertionCritical, 0)),
|
||||
IF(csdA.injury, csdA.injury, IFNULL(csdB.injury, 0)),
|
||||
IF(csdA.injuryCritical, csdA.injuryCritical, IFNULL(csdB.injuryCritical, 0)),
|
||||
IF(csdA.death, csdA.death, IFNULL(csdB.death, 0)),
|
||||
IF(csdA.stun, csdA.stun, IFNULL(csdB.stun, 0)),
|
||||
IF(csdA.stand, csdA.stand, IFNULL(csdB.stand, 0)),
|
||||
IF(csdA.aggro, csdA.aggro, IFNULL(csdB.aggro, 0)),
|
||||
IF(csdA.wingFlap, csdA.wingFlap, IFNULL(csdB.wingFlap, 0)),
|
||||
IF(csdA.wingGlide, csdA.wingGlide, IFNULL(csdB.wingGlide, 0)),
|
||||
IF(csdA.alert, csdA.alert, IFNULL(csdB.alert, 0)),
|
||||
IF(csdA.fidget, csdA.fidget, IFNULL(csdB.fidget, 0)),
|
||||
IF(csdA.customAttack, csdA.customAttack, IFNULL(csdB.customAttack, 0)),
|
||||
IF(csdA.loop, csdA.loop, IFNULL(csdB.loop, 0)),
|
||||
IF(csdA.jumpStart, csdA.jumpStart, IFNULL(csdB.jumpStart, 0)),
|
||||
IF(csdA.jumpEnd, csdA.jumpEnd, IFNULL(csdB.jumpEnd, 0)),
|
||||
IF(csdA.petAttack, csdA.petAttack, IFNULL(csdB.petAttack, 0)),
|
||||
IF(csdA.petOrder, csdA.petOrder, IFNULL(csdB.petOrder, 0)),
|
||||
IF(csdA.petDismiss, csdA.petDismiss, IFNULL(csdB.petDismiss, 0)),
|
||||
IF(csdA.birth, csdA.birth, IFNULL(csdB.birth, 0)),
|
||||
IF(csdA.spellcast, csdA.spellcast, IFNULL(csdB.spellcast, 0)),
|
||||
IF(csdA.submerge, csdA.submerge, IFNULL(csdB.submerge, 0)),
|
||||
IF(csdA.submerged, csdA.submerged, IFNULL(csdB.submerged, 0))
|
||||
GREATEST(IFNULL(ns.greetSoundId, 0), 0),
|
||||
GREATEST(IFNULL(ns.byeSoundId, 0), 0),
|
||||
GREATEST(IFNULL(ns.angrySoundId, 0), 0),
|
||||
GREATEST(IF(csdA.exertion, csdA.exertion, IFNULL(csdB.exertion, 0)), 0),
|
||||
GREATEST(IF(csdA.exertionCritical, csdA.exertionCritical, IFNULL(csdB.exertionCritical, 0)), 0),
|
||||
GREATEST(IF(csdA.injury, csdA.injury, IFNULL(csdB.injury, 0)), 0),
|
||||
GREATEST(IF(csdA.injuryCritical, csdA.injuryCritical, IFNULL(csdB.injuryCritical, 0)), 0),
|
||||
GREATEST(IF(csdA.death, csdA.death, IFNULL(csdB.death, 0)), 0),
|
||||
GREATEST(IF(csdA.stun, csdA.stun, IFNULL(csdB.stun, 0)), 0),
|
||||
GREATEST(IF(csdA.stand, csdA.stand, IFNULL(csdB.stand, 0)), 0),
|
||||
GREATEST(IF(csdA.aggro, csdA.aggro, IFNULL(csdB.aggro, 0)), 0),
|
||||
GREATEST(IF(csdA.wingFlap, csdA.wingFlap, IFNULL(csdB.wingFlap, 0)), 0),
|
||||
GREATEST(IF(csdA.wingGlide, csdA.wingGlide, IFNULL(csdB.wingGlide, 0)), 0),
|
||||
GREATEST(IF(csdA.alert, csdA.alert, IFNULL(csdB.alert, 0)), 0),
|
||||
GREATEST(IF(csdA.fidget, csdA.fidget, IFNULL(csdB.fidget, 0)), 0),
|
||||
GREATEST(IF(csdA.customAttack, csdA.customAttack, IFNULL(csdB.customAttack, 0)), 0),
|
||||
GREATEST(IF(csdA.loop, csdA.loop, IFNULL(csdB.loop, 0)), 0),
|
||||
GREATEST(IF(csdA.jumpStart, csdA.jumpStart, IFNULL(csdB.jumpStart, 0)), 0),
|
||||
GREATEST(IF(csdA.jumpEnd, csdA.jumpEnd, IFNULL(csdB.jumpEnd, 0)), 0),
|
||||
GREATEST(IF(csdA.petAttack, csdA.petAttack, IFNULL(csdB.petAttack, 0)), 0),
|
||||
GREATEST(IF(csdA.petOrder, csdA.petOrder, IFNULL(csdB.petOrder, 0)), 0),
|
||||
GREATEST(IF(csdA.petDismiss, csdA.petDismiss, IFNULL(csdB.petDismiss, 0)), 0),
|
||||
GREATEST(IF(csdA.birth, csdA.birth, IFNULL(csdB.birth, 0)), 0),
|
||||
GREATEST(IF(csdA.spellcast, csdA.spellcast, IFNULL(csdB.spellcast, 0)), 0),
|
||||
GREATEST(IF(csdA.submerge, csdA.submerge, IFNULL(csdB.submerge, 0)), 0),
|
||||
GREATEST(IF(csdA.submerged, csdA.submerged, IFNULL(csdB.submerged, 0)), 0)
|
||||
FROM
|
||||
dbc_creaturedisplayinfo cdi
|
||||
LEFT JOIN
|
||||
@@ -256,20 +256,20 @@ SqlGen::register(new class extends SetupScript
|
||||
?_spell_sounds (`id`, `precast`, `cast`, `impact`, `state`, `statedone`, `channel`, `missile`, `animation`, `casterimpact`, `targetimpact`, `missiletargeting`, `instantarea`, `impactarea`, `persistentarea`)
|
||||
SELECT
|
||||
sv.id,
|
||||
IFNULL(svk1.soundId, 0),
|
||||
IFNULL(svk2.soundId, 0),
|
||||
IFNULL(svk3.soundId, 0),
|
||||
IFNULL(svk4.soundId, 0),
|
||||
IFNULL(svk5.soundId, 0),
|
||||
IFNULL(svk6.soundId, 0),
|
||||
missileSoundId,
|
||||
animationSoundId,
|
||||
IFNULL(svk7.soundId, 0),
|
||||
IFNULL(svk8.soundId, 0),
|
||||
IFNULL(svk9.soundId, 0),
|
||||
IFNULL(svk10.soundId, 0),
|
||||
IFNULL(svk11.soundId, 0),
|
||||
IFNULL(svk12.soundId, 0)
|
||||
GREATEST(IFNULL(svk1.soundId, 0), 0),
|
||||
GREATEST(IFNULL(svk2.soundId, 0), 0),
|
||||
GREATEST(IFNULL(svk3.soundId, 0), 0),
|
||||
GREATEST(IFNULL(svk4.soundId, 0), 0),
|
||||
GREATEST(IFNULL(svk5.soundId, 0), 0),
|
||||
GREATEST(IFNULL(svk6.soundId, 0), 0),
|
||||
GREATEST(missileSoundId, 0),
|
||||
GREATEST(animationSoundId, 0),
|
||||
GREATEST(IFNULL(svk7.soundId, 0), 0),
|
||||
GREATEST(IFNULL(svk8.soundId, 0), 0),
|
||||
GREATEST(IFNULL(svk9.soundId, 0), 0),
|
||||
GREATEST(IFNULL(svk10.soundId, 0), 0),
|
||||
GREATEST(IFNULL(svk11.soundId, 0), 0),
|
||||
GREATEST(IFNULL(svk12.soundId, 0), 0)
|
||||
FROM
|
||||
dbc_spellvisual sv
|
||||
LEFT JOIN
|
||||
|
||||
@@ -111,7 +111,7 @@ SqlGen::register(new class extends SetupScript
|
||||
stanceMask, stanceMaskNot,
|
||||
targets,
|
||||
spellFocus,
|
||||
IFNULL(sct.baseTime, 0) / 1000 AS castTime,
|
||||
GREATEST(IFNULL(sct.baseTime, 0), 0) / 1000 AS castTime,
|
||||
recoveryTime, recoveryTimeCategory,
|
||||
startRecoveryTime, startRecoveryCategory,
|
||||
procChance, procCharges,
|
||||
@@ -269,7 +269,7 @@ SqlGen::register(new class extends SetupScript
|
||||
ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL = 2 not used for now
|
||||
*/
|
||||
|
||||
CLI::write(' - linking with skillineability');
|
||||
CLI::write(' - linking with skilllineability');
|
||||
|
||||
$results = DB::Aowow()->select('SELECT spellId AS ARRAY_KEY, id AS ARRAY_KEY2, skillLineId, reqRaceMask, reqClassMask, reqSkillLevel, acquireMethod, skillLevelGrey, skillLevelYellow FROM dbc_skilllineability sla');
|
||||
foreach ($results as $spellId => $sets)
|
||||
@@ -501,7 +501,7 @@ SqlGen::register(new class extends SetupScript
|
||||
$itemInfo = DB::World()->select('SELECT entry AS ARRAY_KEY, displayId AS d, Quality AS q FROM item_template WHERE entry IN (?a)', $itemSpells);
|
||||
foreach ($itemSpells as $sId => $itemId)
|
||||
if (isset($itemInfo[$itemId]))
|
||||
DB::Aowow()->query('UPDATE ?_spell s, ?_icons ic, dbc_spellicon si SET s.iconIdAlt = ?d, s.cuFlags = s.cuFlags | ?d WHERE s.iconIdBak = si.id AND ic.name = LOWER(SUBSTRING_INDEX(si.iconPath, "\\\\", -1)) AND s.id = ?d', -$itemInfo[$itemId]['d'], ((7 - $itemInfo[$itemId]['q']) << 8), $sId);
|
||||
DB::Aowow()->query('UPDATE ?_spell s, ?_icons ic, dbc_spellicon si SET s.iconIdAlt = ?d, s.cuFlags = s.cuFlags | ?d WHERE s.iconIdBak = si.id AND ic.name = LOWER(SUBSTRING_INDEX(si.iconPath, "\\\\", -1)) AND s.id = ?d', $itemInfo[$itemId]['d'], ((7 - $itemInfo[$itemId]['q']) << 8), $sId);
|
||||
|
||||
$itemReqs = DB::World()->selectCol('SELECT entry AS ARRAY_KEY, requiredSpell FROM item_template WHERE requiredSpell NOT IN (?a)', [0, 34090, 34091]); // not riding
|
||||
foreach ($itemReqs AS $itemId => $req)
|
||||
|
||||
@@ -19,9 +19,9 @@ SqlGen::register(new class extends SetupScript
|
||||
// has no unique keys..
|
||||
DB::Aowow()->query('TRUNCATE TABLE ?_spelldifficulty');
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_spelldifficulty SELECT * FROM dbc_spelldifficulty');
|
||||
DB::Aowow()->query('INSERT INTO ?_spelldifficulty SELECT GREATEST(`normal10`, 0), GREATEST(`normal25`, 0), GREATEST(`heroic10`, 0), GREATEST(`heroic25`, 0) FROM dbc_spelldifficulty');
|
||||
|
||||
$rows = DB::World()->select('SELECT spellid0, spellid1, spellid2, spellid3 FROM spelldifficulty_dbc');
|
||||
$rows = DB::World()->select('SELECT `spellid0`, `spellid1`, `spellid2`, `spellid3` FROM spelldifficulty_dbc');
|
||||
foreach ($rows as $r)
|
||||
DB::Aowow()->query('INSERT INTO ?_spelldifficulty VALUES (?a)', array_values($r));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user