This commit is contained in:
Miodec 2022-08-26 12:01:20 +02:00
commit 8afaa79f3c
9 changed files with 285 additions and 72 deletions

View file

@ -7,16 +7,18 @@ const router = Router();
router.get("/", asyncHandler(ConfigurationController.getConfiguration));
router.patch(
"/",
validateRequest({
body: {
configuration: joi.object(),
},
}),
asyncHandler(ConfigurationController.updateConfiguration)
);
if (process.env.MODE === "dev") {
router.patch(
"/",
validateRequest({
body: {
configuration: joi.object(),
},
}),
asyncHandler(ConfigurationController.updateConfiguration)
);
router.get("/schema", asyncHandler(ConfigurationController.getSchema));
router.get("/schema", asyncHandler(ConfigurationController.getSchema));
}
export default router;

View file

@ -37,9 +37,11 @@ function addApiRoutes(app: Application): void {
res.sendStatus(404);
});
// Cannot be added to the route map because it needs to be added before the maintenance handler
app.use("/configuration", configuration);
if (process.env.MODE === "dev") {
app.use("/configure", express.static(join(__dirname, "../../../private")));
app.use("/configuration", configuration);
}
addSwaggerMiddlewares(app);

View file

@ -47,7 +47,7 @@ function setWordsInput(value: string): void {
}
function updateUI(): void {
const acc = Misc.roundTo2(TestStats.calculateAccuracy());
const acc: number = Misc.roundTo2(TestStats.calculateAccuracy());
if (!isNaN(acc)) LiveAcc.update(acc);
if (Config.keymapMode === "next" && Config.mode !== "zen") {
@ -64,8 +64,8 @@ function backspaceToPrevious(): void {
if (!TestActive.get()) return;
if (
TestInput.input.history.length == 0 ||
TestUI.currentWordElementIndex == 0
TestInput.input.history.length === 0 ||
TestUI.currentWordElementIndex === 0
) {
return;
}
@ -108,16 +108,17 @@ function handleSpace(): void {
$("#words").append("<div class='word active'></div>");
}
const currentWord = TestWords.words.getCurrent();
const currentWord: string = TestWords.words.getCurrent();
if (Config.funbox === "layoutfluid" && Config.mode !== "time") {
// here I need to check if Config.customLayoutFluid exists because of my scuffed solution of returning whenever value is undefined in the setCustomLayoutfluid function
const layouts = Config.customLayoutfluid
// here I need to check if Config.customLayoutFluid exists because of my
// scuffed solution of returning whenever value is undefined in the setCustomLayoutfluid function
const layouts: string[] = Config.customLayoutfluid
? Config.customLayoutfluid.split("#")
: ["qwerty", "dvorak", "colemak"];
let index = 0;
const outof = TestWords.words.length;
const outOf: number = TestWords.words.length;
index = Math.floor(
(TestInput.input.history.length + 1) / (outof / layouts.length)
(TestInput.input.history.length + 1) / (outOf / layouts.length)
);
if (Config.layout !== layouts[index] && layouts[index] !== undefined) {
Notifications.add(`--- !!! ${layouts[index]} !!! ---`, 0);
@ -134,13 +135,13 @@ function handleSpace(): void {
}
dontInsertSpace = true;
const burst = TestStats.calculateBurst();
const burst: number = TestStats.calculateBurst();
LiveBurst.update(Math.round(burst));
TestInput.pushBurstToHistory(burst);
//correct word or in zen mode
const isWordCorrect =
currentWord == TestInput.input.current || Config.mode == "zen";
const isWordCorrect: boolean =
currentWord === TestInput.input.current || Config.mode == "zen";
MonkeyPower.addPower(isWordCorrect, true);
TestInput.incrementAccuracy(isWordCorrect);
if (isWordCorrect) {
@ -167,7 +168,7 @@ function handleSpace(): void {
}
TestInput.pushMissedWord(TestWords.words.getCurrent());
TestInput.incrementKeypressErrors();
const cil = TestInput.input.current.length;
const cil: number = TestInput.input.current.length;
if (cil <= TestWords.words.getCurrent().length) {
if (cil >= TestInput.corrected.current.length) {
TestInput.corrected.current += "_";
@ -209,7 +210,7 @@ function handleSpace(): void {
if (Config.difficulty == "expert" || Config.difficulty == "master") {
TestLogic.fail("difficulty");
return;
} else if (TestWords.words.currentIndex == TestWords.words.length) {
} else if (TestWords.words.currentIndex === TestWords.words.length) {
//submitted last word that is incorrect
TestLogic.finish();
return;
@ -217,14 +218,14 @@ function handleSpace(): void {
Replay.addReplayEvent("submitErrorWord");
}
let wordLength;
let wordLength: number;
if (Config.mode === "zen") {
wordLength = TestInput.input.current.length;
} else {
wordLength = TestWords.words.getCurrent().length;
}
const flex = Misc.whorf(Config.minBurstCustomSpeed, wordLength);
const flex: number = Misc.whorf(Config.minBurstCustomSpeed, wordLength);
if (
(Config.minBurst === "fixed" && burst < Config.minBurstCustomSpeed) ||
(Config.minBurst === "flex" && burst < flex)
@ -238,15 +239,15 @@ function handleSpace(): void {
if (
!Config.showAllLines ||
Config.mode == "time" ||
(CustomText.isWordRandom && CustomText.word == 0) ||
(CustomText.isWordRandom && CustomText.word === 0) ||
CustomText.isTimeRandom
) {
const currentTop = Math.floor(
const currentTop: number = Math.floor(
document.querySelectorAll<HTMLElement>("#words .word")[
TestUI.currentWordElementIndex - 1
].offsetTop
);
let nextTop;
let nextTop: number;
try {
nextTop = Math.floor(
document.querySelectorAll<HTMLElement>("#words .word")[
@ -302,44 +303,44 @@ function isCharCorrect(char: string, charIndex: number): boolean {
const originalChar: string = TestWords.words.getCurrent()[charIndex];
if (originalChar == char) {
if (originalChar === char) {
return true;
}
if (Config.language.split("_")[0] == "russian") {
if ((char === "е" || char === "e") && originalChar == "ё") {
if (Config.language.startsWith("russian")) {
if ((char === "е" || char === "e") && originalChar === "ё") {
return true;
}
if (char === "ё" && (originalChar == "е" || originalChar === "e")) {
if (char === "ё" && (originalChar === "е" || originalChar === "e")) {
return true;
}
}
if (Config.funbox === "arrows") {
if ((char === "w" || char === "ArrowUp") && originalChar == "↑") {
if ((char === "w" || char === "ArrowUp") && originalChar === "↑") {
return true;
}
if ((char === "s" || char === "ArrowDown") && originalChar == "↓") {
if ((char === "s" || char === "ArrowDown") && originalChar === "↓") {
return true;
}
if ((char === "a" || char === "ArrowLeft") && originalChar == "←") {
if ((char === "a" || char === "ArrowLeft") && originalChar === "←") {
return true;
}
if ((char === "d" || char === "ArrowRight") && originalChar == "→") {
if ((char === "d" || char === "ArrowRight") && originalChar === "→") {
return true;
}
}
if (
(char === `` || char === "" || char === "'") &&
(originalChar == `` || originalChar === "" || originalChar === "'")
(char === "" || char === "" || char === "'") &&
(originalChar === "" || originalChar === "" || originalChar === "'")
) {
return true;
}
if (
(char === `"` || char === "”" || char == "“" || char === "„") &&
(originalChar == `"` ||
(originalChar === `"` ||
originalChar === "”" ||
originalChar === "“" ||
originalChar === "„")
@ -348,8 +349,8 @@ function isCharCorrect(char: string, charIndex: number): boolean {
}
if (
(char === "" || char === "—" || char == "-") &&
(originalChar == "-" || originalChar === "" || originalChar === "—")
(char === "" || char === "—" || char === "-") &&
(originalChar === "-" || originalChar === "" || originalChar === "—")
) {
return true;
}
@ -360,7 +361,7 @@ function isCharCorrect(char: string, charIndex: number): boolean {
function handleChar(
char: string,
charIndex: number,
realInputVaue?: string
realInputValue?: string
): void {
if (TestUI.resultCalculating || TestUI.resultVisible) {
return;
@ -415,7 +416,7 @@ function handleChar(
Focus.set(true);
Caret.stopAnimation();
const thisCharCorrect = isCharCorrect(char, charIndex);
const thisCharCorrect: boolean = isCharCorrect(char, charIndex);
let resultingWord: string;
if (thisCharCorrect && Config.mode !== "zen") {
@ -442,7 +443,7 @@ function handleChar(
// With chars alone this happens when a previous symbol is completed
// Example:
// input history: ['프'], input:ㄹ, expected :프ㄹ, result: 플
const realInput: string = (realInputVaue ?? "").slice(1);
const realInput: string = (realInputValue ?? "").slice(1);
resultingWord = realInput;
koInputVisual.innerText = resultingWord.slice(-1);
}
@ -549,14 +550,14 @@ function handleChar(
if (Config.mode != "zen") {
//not applicable to zen mode
//auto stop the test if the last word is correct
const currentWord = TestWords.words.getCurrent();
const lastindex = TestWords.words.currentIndex;
const currentWord: string = TestWords.words.getCurrent();
const lastIndex: number = TestWords.words.currentIndex;
if (
(currentWord == TestInput.input.current ||
(currentWord === TestInput.input.current ||
(Config.quickEnd &&
currentWord.length == TestInput.input.current.length &&
currentWord.length === TestInput.input.current.length &&
Config.stopOnError == "off")) &&
lastindex == TestWords.words.length - 1
lastIndex === TestWords.words.length - 1
) {
TestInput.input.pushHistory();
TestInput.corrected.pushHistory();
@ -620,8 +621,8 @@ function handleTab(event: JQuery.KeyDownEvent, popupVisible: boolean): void {
const area = $("#customTextPopup .textarea")[0] as HTMLTextAreaElement;
const start = area.selectionStart;
const end = area.selectionEnd;
const start: number = area.selectionStart;
const end: number = area.selectionEnd;
// set textarea value to: text before caret + tab + text after caret
area.value =
@ -642,7 +643,7 @@ function handleTab(event: JQuery.KeyDownEvent, popupVisible: boolean): void {
shouldInsertTabCharacter = true;
}
const modalVisible =
const modalVisible: boolean =
!$("#commandLineWrapper").hasClass("hidden") || popupVisible;
if (Config.quickRestart === "esc") {
@ -714,14 +715,14 @@ $(document).keydown(async (event) => {
if (ActivePage.get() == "loading") return event.preventDefault();
//autofocus
const wordsFocused = $("#wordsInput").is(":focus");
const pageTestActive = ActivePage.get() === "test";
const wordsFocused: boolean = $("#wordsInput").is(":focus");
const pageTestActive: boolean = ActivePage.get() === "test";
const commandLineVisible = !$("#commandLineWrapper").hasClass("hidden");
const leaderboardsVisible = !$("#leaderboardsWrapper").hasClass("hidden");
const popupVisible = Misc.isAnyPopupVisible();
const popupVisible: boolean = Misc.isAnyPopupVisible();
const allowTyping =
const allowTyping: boolean =
pageTestActive &&
!commandLineVisible &&
!leaderboardsVisible &&
@ -743,7 +744,7 @@ $(document).keydown(async (event) => {
//esc
if (event.key === "Escape" && Config.quickRestart === "esc") {
const modalVisible =
const modalVisible: boolean =
!$("#commandLineWrapper").hasClass("hidden") || popupVisible;
if (modalVisible) return;
@ -839,11 +840,14 @@ $(document).keydown(async (event) => {
//show dead keys
if (event.key === "Dead" && !CompositionState.getComposing()) {
Sound.playClick();
const word = document.querySelector<HTMLElement>("#words .word.active");
const len = TestInput.input.current.length; // have to do this because prettier wraps the line and causes an error
const word: HTMLElement | null = document.querySelector<HTMLElement>(
"#words .word.active"
);
const len: number = TestInput.input.current.length; // have to do this because prettier wraps the line and causes an error
// Check to see if the letter actually exists to toggle it as dead
const deadLetter = word?.querySelectorAll("letter")[len];
const deadLetter: Element | undefined =
word?.querySelectorAll("letter")[len];
if (deadLetter) {
deadLetter.classList.toggle("dead");
}
@ -855,7 +859,7 @@ $(document).keydown(async (event) => {
}
if (Config.funbox === "arrows") {
let char = event.key;
let char: string = event.key;
if (["ArrowLeft", "ArrowUp", "ArrowRight", "ArrowDown"].includes(char)) {
if (char === "ArrowLeft") char = "a";
if (char === "ArrowRight") char = "d";
@ -876,7 +880,7 @@ $(document).keydown(async (event) => {
(event.altKey && window.navigator.platform.search("Linux") > -1)
)
) {
const char = await LayoutEmulator.getCharFromEvent(event);
const char: string | null = await LayoutEmulator.getCharFromEvent(event);
if (char !== null) {
event.preventDefault();
handleChar(char, TestInput.input.current.length);
@ -896,9 +900,11 @@ $("#wordsInput").keyup((event) => {
}
if (TestUI.resultVisible) return;
const now = performance.now();
const now: number = performance.now();
if (TestInput.keypressTimings.duration.current !== -1) {
const diff = Math.abs(TestInput.keypressTimings.duration.current - now);
const diff: number = Math.abs(
TestInput.keypressTimings.duration.current - now
);
TestInput.pushKeypressDuration(diff);
}
TestInput.setKeypressDuration(now);

View file

@ -77,11 +77,28 @@
"deixar",
"apenas",
"primeiro",
"vigilante",
"impetuoso",
"imprudente",
"perspicaz",
"paralelepípedo",
"fervente",
"circuito",
"estimulante",
"intragável",
"ambiguidade",
"pragmático",
"majestoso",
"aterrorizante",
"espiritual",
"estetoscópio",
"uma",
"aqui",
"mundo",
"qualquer",
"organizar",
"trabalho",
"detalhe",
"país",
"conseguir",
"tu",

View file

@ -426,6 +426,72 @@
"source": "المقنع الكندي",
"length": 113,
"id": 70
},
{
"text": "من بخل بالعلم ابتلى بثلاث: إما موت فيذهب علمه, إما ينسى, وإما يصحب فيذهب عمله",
"source": "عبد الله بن المبارك",
"length": 77,
"id": 71
},
{
"text": "من صبر فما أقل ما يصبر , ومن جزع فما أقل ما يتمتع",
"source": "عبد الله بن المبارك",
"length": 49,
"id": 72
},
{
"text": "وقال محمد بن علي لابنه: يا بنى إياك والكسل والضجر , فأنهما مفتاح كل شر إنك إن كسلت لم تؤد حقا, وإن ضجرت لم تصبر على حق.",
"source": "محمد بن علي بن الحسين بن علي أبي طالب",
"length": 119,
"id": 73
},
{
"text": "إذا رأيت الرجل يعمل الحسنة, فاعلم أن لها عنده أخوات, وإذا رأيته يعمل السيئة, فاعلم أن لها عنده أخوات, فإن الحسنة تدل على أختها, وإن السيئة تدل على أختها",
"source": "عروة بن الزبير",
"length": 152,
"id": 74
},
{
"text": "وقال: مكتوب في الحكمة: لتكن كلمتك طيبة, وليكن وجهك بسطا, تكن أحب إلى الناس ممن يعطيهم العطاء.",
"source": "عروة بن الزبير",
"length": 93,
"id": 75
},
{
"text": "الكلام الحسن حسن وأحسن من الحسن معناه استعماله, وأحسن من استعماله ثوابه, وأحسن من ثوابه رضا من يعمل له.",
"source": "يحيى بن معاذ الرازي",
"length": 103,
"id": 76
},
{
"text": "وقال يحيى بن معاذ: الناس ثلاثة : رجل شغله معاده عن معاشه ورجل شغله معاشه عن معاده, ورجل مشتغل بهما جميعاَ فالأولى درجة الفائزين, والثانية درجة الهالكين, والثالثة درجة المخاطرين.",
"source": "يحيى بن معاذ الرازي",
"length": 177,
"id": 77
},
{
"text": "عجبت ممن يحزن على نقصان ماله كيف لا يحزن على نقصان عمره.",
"source": "يحيى بن معاذ الرازي",
"length": 56,
"id": 78
},
{
"text": "الزهد ثلاثة أشياء: القلة, والخلوة, والجوع, وكان يقول: جوع التوابين تجربة, وجوع الزاهدين سياسة, وجوع الصديقين تكرمة.",
"source": "يحيى بن معاذ الرازي",
"length": 115,
"id": 79
},
{
"text": "يا بني احذر الصرعة على الغفلة, حين لا تستجاب الدعوة, ولا سبيل إلى رجعة, ولا تغترن بطول العافية, فإنما هو أجل, ليس دونه فناء, ولا بعد أن تستكمله بقاء.",
"source": "عمر بن عبد العزيز",
"length": 149,
"id": 80
},
{
"text": "ان استطعت فكن عالماً, فإن لم تستطع فكن متعلماً, فإن لم تستطع فأحبهم, فإن لم تستطع فلا تبغضهم.",
"source": "عمر بن عبد العزيز",
"length": 93,
"id": 81
}
]
}

View file

@ -194,9 +194,9 @@
"id": 31
},
{
"text": "void Person::set_p(int id, char n[]) {\\n\\tthis->id = id;\\n\\tstrcpy(this->name, n);\\t \\n}",
"text": "void Person::set_p(int id, char n[]) {\\n\\tthis->id = id;\\n\\tstrcpy(this->name, n);\\n}",
"source": "geeksforgeeks - Inheritance in C++",
"length": 90,
"length": 85,
"id": 32
}
]

View file

@ -5613,7 +5613,7 @@
},
{
"text": "Those who do not exist cannot suffer and are of no account to any viable ethics. If the true path to goodness is the elimination of suffering, then only those who must exist can be allowed to exist. It is the nature of life to favor existence over nonexistence, and to prefer the fertile soil to the poisoned wind. Because those who open their mouths to that wind pass from the world and leave no descendant, whether of flesh or of thought.",
"source": "Destiny 2 Shadowkeep - Book of Unveiling - Pleased to Meet You",
"source": "Destiny 2: Shadowkeep - Book of Unveiling - Pleased to Meet You",
"id": 949,
"length": 440
},
@ -21657,7 +21657,7 @@
},
{
"text": "The Light lives in all places. In all things. You can block it. Even try to trap it. But the Light will always find its way.",
"source": "Destiny 2",
"source": "Destiny 2 - The Speaker",
"id": 3705,
"length": 124
},
@ -31101,7 +31101,7 @@
},
{
"text": "Artificial intelligence activated. Enjoying yourselves, intruders? It's worth knowing the cataclysmic damage you will be responsible for today. Do not fool yourselves. This facility is not simply the fruitless work of some pathetic scientist. This house was built by the genius Clovis Bray I himself. Within lies humanity's salvation. La fontaine de jouvence. Made possible by Clarity Control. Magnificent, wasn't it? An entity from beyond our own dimension. And the answer to humanity's eternal struggle: mortality. Were it to fall into the wrong hands, humanity, and the universe, would be utterly doomed. I have no reason to believe you are anything other than 'the wrong hands.' You now face godlike judgement. May it extend eternally.",
"source": "Destiny 2",
"source": "Destiny 2: Beyond Light - Deep Stone Crypt - Crypt AI",
"length": 739,
"id": 5336
},
@ -35370,6 +35370,126 @@
"source": "Portal 2",
"length": 252,
"id": 6201
},
{
"text": "Wake up to reality! Nothing ever goes as planned in this accursed world. The longer you live, the more you realize that the only things that truly exist in this reality are merely pain, suffering and futility. Listen, everywhere you look in this world, wherever there is light, there will always be shadows to be found as well. As long as there is a concept of victors, the vanquished will also exist. The selfish intent of wanting to preserve peace, initiates war and hatred is born in order to protect love. There are nexuses causal relationships that cannot be separated.",
"source": "Uchiha Madara - Naruto",
"length": 574,
"id": 6202
},
{
"text": "The world isn't perfect. But it's there for us, doing the best it can… that's what makes it so damn beautiful.",
"source": "Roy Mustang - Full Metal Alchemist",
"length": 110,
"id": 6203
},
{
"text": "To know sorrow is not terrifying. What is terrifying is to know you can't go back to happiness you could have.",
"source": "Matsumoto Rangiku - Bleach",
"length": 110,
"id": 6204
},
{
"text": "We are all like fireworks: We climb, we shine and always go our separate ways and become further apart. But even when that time comes, lets not disappear like a firework and continue to shine… forever.",
"source": "Hitsugaya Toshiro - Bleach",
"length": 202,
"id": 6205
},
{
"text": "Whatever you lose, you'll find it again. But what you throw away you'll never get back.",
"source": "Kenshin Himura - Rurouni Kenshin: Meiji Kenkaku Romantan",
"length": 87,
"id": 6206
},
{
"text": "People, who can't throw something important away, can never hope to change anything.",
"source": "Armin Arlert - Attack on Titan",
"length": 84,
"id": 6207
},
{
"text": "You will never be able to love anybody else until you love yourself.",
"source": "Lelouch Lamperouge - Code Geass",
"length": 68,
"id": 6208
},
{
"text": "People's lives don't end when they die, it ends when they lose faith.",
"source": "Uchiha Itachi - Naruto",
"length": 69,
"id": 6209
},
{
"text": "If you don't like your destiny, don't accept it.",
"source": "Uzumaki Naruto - Naruto",
"length": 48,
"id": 6210
},
{
"text": "If you don't share someone's pain, you can never understand them.",
"source": "Nagato - Naruto",
"length": 65,
"id": 6211
},
{
"text": "Why should I apologize for being a monster? Has anyone ever apologized for turning me into one?",
"source": "Juuzo Suzuya - Tokyo Ghoul",
"length": 95,
"id": 6212
},
{
"text": "There's no shame in falling down! True shame is to not stand up again!",
"source": "Shintarō Midorima - Kuroko's Basketball",
"length": 70,
"id": 6213
},
{
"text": "You can die anytime, but living takes true courage.",
"source": "Kenshin Himura - Rurouni Kenshin: Meiji Kenkaku Romantan",
"length": 51,
"id": 6214
},
{
"text": "Don't be so quick to throw away your life. No matter how disgraceful or embarrassing it may be, you need to keep struggling to find your way out until the very end.",
"source": "Clare - Claymore",
"length": 164,
"id": 6215
},
{
"text": "Whether we wanted it or not, we've stepped into a war with the Cabal on Mars. So let's get to taking out their command, one by one. Valus Ta'aurc. From what I can gather he commands the Siege Dancers from an Imperial Land Tank outside of Rubicon. He's well protected, but with the right team, we can punch through those defenses, take this beast out, and break their grip on Freehold.",
"source": "Destiny - Cerberus Vae III - Commander Zavala",
"length": 384,
"id": 6216
},
{
"text": "I don't even have time to explain why I don't have time to explain.",
"source": "Destiny - Exo Stranger",
"length": 67,
"id": 6217
},
{
"text": "You're not brave. You've merely forgotten the fear of death. Allow me to reacquaint you.",
"source": "Destiny 2 - Dominus Ghaul",
"length": 88,
"id": 6218
},
{
"text": "I CAN'T BELIEVE THAT- I don't have a medal for this! Hang on! I'm so proud of you, Guardian, and I want... you to have this.",
"source": "Destiny 2 - Lord Shaxx",
"length": 124,
"id": 6219
},
{
"text": "We have seen enough. The children of Sol cry out for salvation. You promised them life... but deliver only death. As you have for so many before. Enough. Enough death. Enough life. You have no pieces left to place. The game is over. Do not be afraid. Your pale heart holds the key. This time... there is no escape.",
"source": "Destiny 2: The Witch Queen - The Witness",
"length": 314,
"id": 6220
},
{
"text": "Funny. The line between Light and Dark is so very thin. Do you know which side you're on?",
"source": "Destiny 2: Forsaken - Uldren Sov",
"length": 89,
"id": 6221
}
]
}

View file

@ -1154,7 +1154,7 @@
"id": 192
},
{
"text": "Dari Sabang sampai Merauke, berjajar pulau-pulau. Sambung-menyambung menjadi satu, itulah Indonesia. Indonesia tanah airku, aku berjanji padamu. Menjunjung tanah airku, tanah airku indonesia.",
"text": "Dari Sabang sampai Merauke, berjajar pulau-pulau. Sambung-menyambung menjadi satu, itulah Indonesia. Indonesia tanah airku, aku berjanji padamu. Menjunjung tanah airku, tanah airku Indonesia.",
"source": "Dari Sabang Sampai Merauke",
"length": 191,
"id": 193

View file

@ -7,6 +7,6 @@
--text-color: #82eaff;
--error-color: #ffbde6;
--error-extra-color: #ff8188;
--colorful-error-color: #ffbde6;
--colorful-error-color: #d1a5fd;
--colorful-error-extra-color: #ff8188;
}