mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2024-11-10 07:12:07 +00:00
Remove support for qhost
qhost was a proprietery management application for Quake II dedicated servers. Since we don't know if the code is still working and most likely no one uses it anymore, remove it. This war requested by Daniel.
This commit is contained in:
parent
0353f6fc42
commit
c80954a65e
4 changed files with 0 additions and 506 deletions
2
Makefile
2
Makefile
|
@ -520,7 +520,6 @@ CLIENT_OBJS_ := \
|
||||||
|
|
||||||
ifeq ($(OSTYPE), Windows)
|
ifeq ($(OSTYPE), Windows)
|
||||||
CLIENT_OBJS_ += \
|
CLIENT_OBJS_ += \
|
||||||
src/windows/conproc.o \
|
|
||||||
src/windows/mem.o \
|
src/windows/mem.o \
|
||||||
src/windows/network.o \
|
src/windows/network.o \
|
||||||
src/windows/qal.o \
|
src/windows/qal.o \
|
||||||
|
@ -580,7 +579,6 @@ SERVER_OBJS_ := \
|
||||||
|
|
||||||
ifeq ($(OSTYPE), Windows)
|
ifeq ($(OSTYPE), Windows)
|
||||||
SERVER_OBJS_ += \
|
SERVER_OBJS_ += \
|
||||||
src/windows/conproc.o \
|
|
||||||
src/windows/mem.o \
|
src/windows/mem.o \
|
||||||
src/windows/network.o \
|
src/windows/network.o \
|
||||||
src/windows/system.o
|
src/windows/system.o
|
||||||
|
|
|
@ -1,460 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or (at
|
|
||||||
* your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
||||||
* 02111-1307, USA.
|
|
||||||
*
|
|
||||||
* =======================================================================
|
|
||||||
*
|
|
||||||
* The "qhost" subsystem, hosting the console window.
|
|
||||||
*
|
|
||||||
* =======================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <process.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#include "header/conproc.h"
|
|
||||||
|
|
||||||
#define CCOM_WRITE_TEXT 0x2
|
|
||||||
#define CCOM_GET_TEXT 0x3
|
|
||||||
#define CCOM_GET_SCR_LINES 0x4
|
|
||||||
#define CCOM_SET_SCR_LINES 0x5
|
|
||||||
|
|
||||||
HANDLE heventDone;
|
|
||||||
HANDLE hfileBuffer;
|
|
||||||
HANDLE heventChildSend;
|
|
||||||
HANDLE heventParentSend;
|
|
||||||
HANDLE hStdout;
|
|
||||||
HANDLE hStdin;
|
|
||||||
|
|
||||||
LPVOID GetMappedBuffer(HANDLE hfileBuffer);
|
|
||||||
BOOL GetScreenBufferLines(int *piLines);
|
|
||||||
BOOL SetScreenBufferLines(int iLines);
|
|
||||||
BOOL ReadText(LPTSTR pszText, int iBeginLine, int iEndLine);
|
|
||||||
BOOL WriteText(LPCTSTR szText);
|
|
||||||
BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy);
|
|
||||||
int CharToCode(char c);
|
|
||||||
unsigned int _stdcall RequestProc(void *arg);
|
|
||||||
void ReleaseMappedBuffer(LPVOID pBuffer);
|
|
||||||
|
|
||||||
int ccom_argc;
|
|
||||||
char **ccom_argv;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the position (1 to argc-1) in the
|
|
||||||
* program's argument list where the given
|
|
||||||
* parameter apears, or 0 if not present
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
CCheckParm(char *parm)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 1; i < ccom_argc; i++)
|
|
||||||
{
|
|
||||||
if (!ccom_argv[i])
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(parm, ccom_argv[i]))
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
InitConProc(int argc, char **argv)
|
|
||||||
{
|
|
||||||
HANDLE hFile = NULL;
|
|
||||||
HANDLE heventParent = NULL;
|
|
||||||
HANDLE heventChild = NULL;
|
|
||||||
int t;
|
|
||||||
unsigned int threadAddr;
|
|
||||||
|
|
||||||
ccom_argc = argc;
|
|
||||||
ccom_argv = argv;
|
|
||||||
|
|
||||||
/* give QHOST a chance to hook into the console */
|
|
||||||
if ((t = CCheckParm("-HFILE")) > 0)
|
|
||||||
{
|
|
||||||
if (t < argc)
|
|
||||||
{
|
|
||||||
hFile = (HANDLE)(int)strtol(ccom_argv[t + 1], (char **)NULL, 10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((t = CCheckParm("-HPARENT")) > 0)
|
|
||||||
{
|
|
||||||
if (t < argc)
|
|
||||||
{
|
|
||||||
heventParent = (HANDLE)(int)strtol(ccom_argv[t + 1], (char **)NULL, 10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((t = CCheckParm("-HCHILD")) > 0)
|
|
||||||
{
|
|
||||||
if (t < argc)
|
|
||||||
{
|
|
||||||
heventChild = (HANDLE)(int)strtol(ccom_argv[t + 1], (char **)NULL, 10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ignore if we don't have all the events. */
|
|
||||||
if (!hFile || !heventParent || !heventChild)
|
|
||||||
{
|
|
||||||
printf("Qhost not present.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Initializing for qhost.\n");
|
|
||||||
|
|
||||||
hfileBuffer = hFile;
|
|
||||||
heventParentSend = heventParent;
|
|
||||||
heventChildSend = heventChild;
|
|
||||||
|
|
||||||
/* so we'll know when to go away. */
|
|
||||||
heventDone = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
||||||
|
|
||||||
if (!heventDone)
|
|
||||||
{
|
|
||||||
printf("Couldn't create heventDone\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_beginthreadex(NULL, 0, RequestProc, NULL, 0, &threadAddr))
|
|
||||||
{
|
|
||||||
CloseHandle(heventDone);
|
|
||||||
printf("Couldn't create QHOST thread\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* save off the input/output handles. */
|
|
||||||
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
|
||||||
|
|
||||||
/* force 80 character width,
|
|
||||||
at least 25 character height */
|
|
||||||
SetConsoleCXCY(hStdout, 80, 25);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
DeinitConProc(void)
|
|
||||||
{
|
|
||||||
if (heventDone)
|
|
||||||
{
|
|
||||||
SetEvent(heventDone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned _stdcall
|
|
||||||
RequestProc(void *arg)
|
|
||||||
{
|
|
||||||
int *pBuffer;
|
|
||||||
DWORD dwRet;
|
|
||||||
HANDLE heventWait[2];
|
|
||||||
int iBeginLine, iEndLine;
|
|
||||||
|
|
||||||
heventWait[0] = heventParentSend;
|
|
||||||
heventWait[1] = heventDone;
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
dwRet = WaitForMultipleObjects(2, heventWait, FALSE, INFINITE);
|
|
||||||
|
|
||||||
/* heventDone fired, so we're exiting. */
|
|
||||||
if (dwRet == WAIT_OBJECT_0 + 1)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pBuffer = (int *)GetMappedBuffer(hfileBuffer);
|
|
||||||
|
|
||||||
/* hfileBuffer is invalid. Just leave. */
|
|
||||||
if (!pBuffer)
|
|
||||||
{
|
|
||||||
printf("Invalid hfileBuffer\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (pBuffer[0])
|
|
||||||
{
|
|
||||||
case CCOM_WRITE_TEXT:
|
|
||||||
pBuffer[0] = WriteText((LPCTSTR)(pBuffer + 1));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CCOM_GET_TEXT:
|
|
||||||
iBeginLine = pBuffer[1];
|
|
||||||
iEndLine = pBuffer[2];
|
|
||||||
pBuffer[0] = ReadText((LPTSTR)(pBuffer + 1), iBeginLine,
|
|
||||||
iEndLine);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CCOM_GET_SCR_LINES:
|
|
||||||
pBuffer[0] = GetScreenBufferLines(&pBuffer[1]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CCOM_SET_SCR_LINES:
|
|
||||||
pBuffer[0] = SetScreenBufferLines(pBuffer[1]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseMappedBuffer(pBuffer);
|
|
||||||
SetEvent(heventChildSend);
|
|
||||||
}
|
|
||||||
|
|
||||||
_endthreadex(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPVOID
|
|
||||||
GetMappedBuffer(HANDLE hfileBuffer)
|
|
||||||
{
|
|
||||||
LPVOID pBuffer;
|
|
||||||
|
|
||||||
pBuffer = MapViewOfFile(hfileBuffer,
|
|
||||||
FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
|
|
||||||
|
|
||||||
return pBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ReleaseMappedBuffer(LPVOID pBuffer)
|
|
||||||
{
|
|
||||||
UnmapViewOfFile(pBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL
|
|
||||||
GetScreenBufferLines(int *piLines)
|
|
||||||
{
|
|
||||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
|
||||||
BOOL bRet;
|
|
||||||
|
|
||||||
bRet = GetConsoleScreenBufferInfo(hStdout, &info);
|
|
||||||
|
|
||||||
if (bRet)
|
|
||||||
{
|
|
||||||
*piLines = info.dwSize.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
return bRet;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL
|
|
||||||
SetScreenBufferLines(int iLines)
|
|
||||||
{
|
|
||||||
return SetConsoleCXCY(hStdout, 80, iLines);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL
|
|
||||||
ReadText(LPTSTR pszText, int iBeginLine, int iEndLine)
|
|
||||||
{
|
|
||||||
COORD coord;
|
|
||||||
DWORD dwRead;
|
|
||||||
BOOL bRet;
|
|
||||||
|
|
||||||
coord.X = 0;
|
|
||||||
coord.Y = iBeginLine;
|
|
||||||
|
|
||||||
bRet = ReadConsoleOutputCharacter(hStdout, pszText,
|
|
||||||
80 * (iEndLine - iBeginLine + 1), coord,
|
|
||||||
&dwRead);
|
|
||||||
|
|
||||||
/* Make sure it's null terminated. */
|
|
||||||
if (bRet)
|
|
||||||
{
|
|
||||||
pszText[dwRead] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return bRet;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL
|
|
||||||
WriteText(LPCTSTR szText)
|
|
||||||
{
|
|
||||||
DWORD dwWritten;
|
|
||||||
INPUT_RECORD rec;
|
|
||||||
char upper, *sz;
|
|
||||||
|
|
||||||
sz = (LPTSTR)szText;
|
|
||||||
|
|
||||||
while (*sz)
|
|
||||||
{
|
|
||||||
/* 13 is the code for a carriage
|
|
||||||
return (\n) instead of 10. */
|
|
||||||
if (*sz == 10)
|
|
||||||
{
|
|
||||||
*sz = 13;
|
|
||||||
}
|
|
||||||
|
|
||||||
upper = toupper(*sz);
|
|
||||||
|
|
||||||
rec.EventType = KEY_EVENT;
|
|
||||||
rec.Event.KeyEvent.bKeyDown = TRUE;
|
|
||||||
rec.Event.KeyEvent.wRepeatCount = 1;
|
|
||||||
rec.Event.KeyEvent.wVirtualKeyCode = upper;
|
|
||||||
rec.Event.KeyEvent.wVirtualScanCode = CharToCode(*sz);
|
|
||||||
rec.Event.KeyEvent.uChar.AsciiChar = *sz;
|
|
||||||
rec.Event.KeyEvent.uChar.UnicodeChar = *sz;
|
|
||||||
rec.Event.KeyEvent.dwControlKeyState = isupper(*sz) ? 0x80 : 0x0;
|
|
||||||
|
|
||||||
WriteConsoleInput(hStdin, &rec, 1, &dwWritten);
|
|
||||||
|
|
||||||
rec.Event.KeyEvent.bKeyDown = FALSE;
|
|
||||||
|
|
||||||
WriteConsoleInput(hStdin, &rec, 1, &dwWritten);
|
|
||||||
|
|
||||||
sz++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
CharToCode(char c)
|
|
||||||
{
|
|
||||||
char upper;
|
|
||||||
|
|
||||||
upper = toupper(c);
|
|
||||||
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case 13:
|
|
||||||
return 28;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isalpha(c))
|
|
||||||
{
|
|
||||||
return 30 + upper - 65;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isdigit(c))
|
|
||||||
{
|
|
||||||
return 1 + upper - 47;
|
|
||||||
}
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL
|
|
||||||
SetConsoleCXCY(HANDLE hStdout, int cx, int cy)
|
|
||||||
{
|
|
||||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
|
||||||
COORD coordMax;
|
|
||||||
|
|
||||||
coordMax = GetLargestConsoleWindowSize(hStdout);
|
|
||||||
|
|
||||||
if (cy > coordMax.Y)
|
|
||||||
{
|
|
||||||
cy = coordMax.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cx > coordMax.X)
|
|
||||||
{
|
|
||||||
cx = coordMax.X;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GetConsoleScreenBufferInfo(hStdout, &info))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* height */
|
|
||||||
info.srWindow.Left = 0;
|
|
||||||
info.srWindow.Right = info.dwSize.X - 1;
|
|
||||||
info.srWindow.Top = 0;
|
|
||||||
info.srWindow.Bottom = cy - 1;
|
|
||||||
|
|
||||||
if (cy < info.dwSize.Y)
|
|
||||||
{
|
|
||||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
info.dwSize.Y = cy;
|
|
||||||
|
|
||||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cy > info.dwSize.Y)
|
|
||||||
{
|
|
||||||
info.dwSize.Y = cy;
|
|
||||||
|
|
||||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GetConsoleScreenBufferInfo(hStdout, &info))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* width */
|
|
||||||
info.srWindow.Left = 0;
|
|
||||||
info.srWindow.Right = cx - 1;
|
|
||||||
info.srWindow.Top = 0;
|
|
||||||
info.srWindow.Bottom = info.dwSize.Y - 1;
|
|
||||||
|
|
||||||
if (cx < info.dwSize.X)
|
|
||||||
{
|
|
||||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
info.dwSize.X = cx;
|
|
||||||
|
|
||||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cx > info.dwSize.X)
|
|
||||||
{
|
|
||||||
info.dwSize.X = cx;
|
|
||||||
|
|
||||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or (at
|
|
||||||
* your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
||||||
* 02111-1307, USA.
|
|
||||||
*
|
|
||||||
* =======================================================================
|
|
||||||
*
|
|
||||||
* Header file to the "qhost" subsystem.
|
|
||||||
*
|
|
||||||
* =======================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WIN_CONPROC_H
|
|
||||||
#define WIN_CONPROC_H
|
|
||||||
|
|
||||||
void InitConProc(int argc, char **argv);
|
|
||||||
void DeinitConProc(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
|
|
||||||
#include "../common/header/common.h"
|
#include "../common/header/common.h"
|
||||||
#include "header/conproc.h"
|
|
||||||
#include "header/resource.h"
|
#include "header/resource.h"
|
||||||
#include "header/winquake.h"
|
#include "header/winquake.h"
|
||||||
|
|
||||||
|
@ -94,9 +93,6 @@ Sys_Error(char *error, ...)
|
||||||
CloseHandle(qwclsemaphore);
|
CloseHandle(qwclsemaphore);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* shut down QHOST hooks if necessary */
|
|
||||||
DeinitConProc();
|
|
||||||
|
|
||||||
/* Close stdout and stderr */
|
/* Close stdout and stderr */
|
||||||
#ifndef DEDICATED_ONLY
|
#ifndef DEDICATED_ONLY
|
||||||
fclose(stdout);
|
fclose(stdout);
|
||||||
|
@ -123,9 +119,6 @@ Sys_Quit(void)
|
||||||
FreeConsole();
|
FreeConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* shut down QHOST hooks if necessary */
|
|
||||||
DeinitConProc();
|
|
||||||
|
|
||||||
/* Close stdout and stderr */
|
/* Close stdout and stderr */
|
||||||
#ifndef DEDICATED_ONLY
|
#ifndef DEDICATED_ONLY
|
||||||
fclose(stdout);
|
fclose(stdout);
|
||||||
|
@ -184,9 +177,6 @@ Sys_Init(void)
|
||||||
|
|
||||||
hinput = GetStdHandle(STD_INPUT_HANDLE);
|
hinput = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
houtput = GetStdHandle(STD_OUTPUT_HANDLE);
|
houtput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
|
||||||
/* let QHOST hook in */
|
|
||||||
InitConProc(argc, argv);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue