forked from github/server
xml-beispiel und message->xml converter
This commit is contained in:
parent
e9f1fc2207
commit
75e0f82099
|
@ -0,0 +1,227 @@
|
|||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static struct vartype {
|
||||
const char * name;
|
||||
const char * type;
|
||||
const char * msg;
|
||||
} vartype[] = {
|
||||
{ "from", "unit", "donation"},
|
||||
|
||||
/* strange and to be changed */
|
||||
|
||||
{ "destruction", "int", "siege" },
|
||||
{ "discover", "string", "givedumb" },
|
||||
{ "receipient", "unit", "givecommand" },
|
||||
{ "sink", "string", "entermaelstrom" },
|
||||
{ "sink", "string", "storm" },
|
||||
{ "using", "resource", "errusingpotion" },
|
||||
{ "type", "string", "scunicorn" },
|
||||
{ "mode", "string", "travel" },
|
||||
{ "special", "string", "new_fspecial" },
|
||||
{ "special", "string", "new_fspecial_level" },
|
||||
|
||||
/* broadband */
|
||||
|
||||
{ "regions", "string" },
|
||||
{ "succ", "string" },
|
||||
{ "renamed", "string" },
|
||||
{ "reason", "string" },
|
||||
{ "message", "string" },
|
||||
{ "value", "string" },
|
||||
{ "error", "string" },
|
||||
{ "string", "string" },
|
||||
{ "command", "string" },
|
||||
{ "spell", "string" }, /* ? */
|
||||
|
||||
{ "building", "building" },
|
||||
|
||||
{ "ship", "ship" },
|
||||
|
||||
{ "resource", "resource" },
|
||||
{ "potion", "resource" },
|
||||
{ "item", "resource" },
|
||||
{ "herb", "resource" },
|
||||
|
||||
{ "teacher", "unit" },
|
||||
{ "student", "unit" },
|
||||
{ "unit", "unit" },
|
||||
{ "renamer", "unit" },
|
||||
{ "spy", "unit" },
|
||||
{ "mage", "unit" },
|
||||
{ "opfer", "unit" },
|
||||
{ "target", "unit" },
|
||||
{ "recipient", "unit" },
|
||||
{ "follower", "unit" },
|
||||
|
||||
{ "skill", "skill" },
|
||||
|
||||
{ "faction", "faction" },
|
||||
|
||||
{ "region", "region" },
|
||||
{ "source", "region" },
|
||||
{ "regionn", "region" },
|
||||
{ "regionv", "region" },
|
||||
{ "end", "region" },
|
||||
{ "start", "region" },
|
||||
{ "runto", "region" },
|
||||
{ "to", "region" },
|
||||
{ "from", "region" },
|
||||
|
||||
{ "kills", "int" },
|
||||
{ "fallen", "int" },
|
||||
{ "amount", "int" },
|
||||
{ "aura", "int" },
|
||||
{ "months", "int" },
|
||||
{ "wanted", "int" },
|
||||
{ "money", "int" },
|
||||
{ "dead", "int" },
|
||||
{ "level", "int" },
|
||||
{ "days", "int" },
|
||||
{ "damage", "int" },
|
||||
{ "cost", "int" },
|
||||
{ "want", "int" },
|
||||
{ "size", "int" },
|
||||
{ "alive", "int" },
|
||||
{ "run", "int" },
|
||||
{ "hits", "int" },
|
||||
{ "turns", "int" },
|
||||
|
||||
{ "race", "race" },
|
||||
|
||||
{ "direction", "direction" },
|
||||
{ "dir", "direction" },
|
||||
|
||||
{ "id", "int36" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const char *
|
||||
type(const char * name,const char * msg)
|
||||
{
|
||||
int i = 0;
|
||||
while (vartype[i].name) {
|
||||
if (strcmp(name, vartype[i].name)==0 &&
|
||||
(vartype[i].msg==NULL || strcmp(vartype[i].msg, msg)==0)) {
|
||||
return vartype[i].type;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
fprintf(stderr, "unknown type for \"%s\" in message \"%s\".\n", name, msg);
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static void
|
||||
parse_message(char * b, FILE * ostream)
|
||||
{
|
||||
char *m, *a = NULL, message[8192];
|
||||
char * name;
|
||||
char * language;
|
||||
char * section = NULL;
|
||||
int i, level = 0;
|
||||
char * args[16];
|
||||
boolean f_symbol = false;
|
||||
|
||||
/* skip comments */
|
||||
if (b[0]=='#' || b[0]==0) return;
|
||||
|
||||
/* the name of this type */
|
||||
name = b;
|
||||
while (*b && *b!=';') ++b;
|
||||
if (!*b) return;
|
||||
*b++ = 0;
|
||||
|
||||
/* the section for this type */
|
||||
section = b;
|
||||
while (*b && *b!=';' && *b!=':') ++b;
|
||||
if (!strcmp(section, "none")) section=NULL;
|
||||
|
||||
/* if available, the level for this type */
|
||||
if (*b==':') {
|
||||
char * x;
|
||||
*b++ = 0;
|
||||
x = b;
|
||||
while (*b && *b!=';') ++b;
|
||||
level=atoi(x);
|
||||
}
|
||||
*b++ = 0;
|
||||
|
||||
/* the locale */
|
||||
language = b;
|
||||
while (*b && *b!=';') ++b;
|
||||
*b++ = 0;
|
||||
|
||||
/* parse the message */
|
||||
i = 0;
|
||||
m = message;
|
||||
*m++='\"';
|
||||
while (*b) {
|
||||
switch (*b) {
|
||||
case '{':
|
||||
f_symbol = true;
|
||||
a = ++b;
|
||||
break;
|
||||
case '}':
|
||||
*b++ = '\0';
|
||||
args[i] = strdup(a);
|
||||
sprintf(m, "$%s", args[i]);
|
||||
m+=strlen(m);
|
||||
i++;
|
||||
f_symbol = false;
|
||||
break;
|
||||
case ' ':
|
||||
if (f_symbol) {
|
||||
a = ++b;
|
||||
break;
|
||||
}
|
||||
/* fall-through intended */
|
||||
default:
|
||||
if (!f_symbol) {
|
||||
*m++ = *b++;
|
||||
} else b++;
|
||||
}
|
||||
}
|
||||
strcpy(m, "\"");
|
||||
args[i] = NULL;
|
||||
|
||||
/* add the messagetype */
|
||||
fprintf(ostream, "<message name=\"%s\">\n", name);
|
||||
for (i=0;args[i];++i) {
|
||||
fprintf(ostream, "\t<param name=\"%s\" type=\"%s\"></param>\n", args[i], type(args[i], name));
|
||||
}
|
||||
fprintf(ostream, "\t<locale name=\"%s\">\n", language);
|
||||
fprintf(ostream, "\t\t<nr section=\"%s\">\n",
|
||||
language, section);
|
||||
fprintf(ostream, "\t\t\t<text>%s</text>\n", message);
|
||||
fputs("\t\t</nr>\n", ostream);
|
||||
fputs("\t</locale>\n", ostream);
|
||||
fputs("</message>\n\n", ostream);
|
||||
}
|
||||
|
||||
void
|
||||
read_messages(FILE * istream, FILE * ostream)
|
||||
{
|
||||
char buf[8192];
|
||||
fputs("<messages>\n", ostream);
|
||||
while (fgets(buf, sizeof(buf), istream)) {
|
||||
buf[strlen(buf)-1] = 0; /* \n weg */
|
||||
parse_message(buf, ostream);
|
||||
}
|
||||
fputs("</messages>\n", ostream);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
FILE * istream = stdin;
|
||||
FILE * ostream = stdout;
|
||||
int nretval = -1;
|
||||
if (argc>1) istream = fopen(argv[1], "rt+");
|
||||
if (argc>2) ostream = fopen(argv[2], "wt+");
|
||||
if (istream && ostream) {
|
||||
read_messages(istream, ostream);
|
||||
}
|
||||
return nretval;
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
# Microsoft Developer Studio Project File - Name="msg2xml" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=msg2xml - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "msg2xml.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "msg2xml.mak" CFG="msg2xml - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "msg2xml - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "msg2xml - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "msg2xml - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x407 /d "NDEBUG"
|
||||
# ADD RSC /l 0x407 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "msg2xml - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "msg2xml___Win32_Debug"
|
||||
# PROP BASE Intermediate_Dir "msg2xml___Win32_Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x407 /d "_DEBUG"
|
||||
# ADD RSC /l 0x407 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "msg2xml - Win32 Release"
|
||||
# Name "msg2xml - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\msg2xml.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
|
@ -0,0 +1,55 @@
|
|||
#include <config.h>
|
||||
#include <xml.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static int
|
||||
cbplaintext(const struct xml_stack * stack, const char * c)
|
||||
{
|
||||
puts(c);
|
||||
fflush(stdout);
|
||||
return XML_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
cbtagend(const struct xml_stack * stack)
|
||||
{
|
||||
xml_tag * tag = stack->tag;
|
||||
printf("</%s>\n", tag->name);
|
||||
fflush(stdout);
|
||||
return XML_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
cbtagbegin(const struct xml_stack * stack)
|
||||
{
|
||||
xml_tag * tag = stack->tag;
|
||||
xml_attrib * xa= tag->attribs;
|
||||
printf("<%s", tag->name);
|
||||
while (xa) {
|
||||
printf(" %s=\"%s\"", xa->name, xa->value);
|
||||
xa = xa->next;
|
||||
}
|
||||
printf(">\n");
|
||||
fflush(stdout);
|
||||
return XML_OK;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
FILE * istream = stdin;
|
||||
int nretval = -1;
|
||||
if (argc>1) istream = fopen(argv[1], "rt+");
|
||||
if (istream) {
|
||||
xml_callbacks xml_cb = { NULL };
|
||||
xml_cb.plaintext = cbplaintext;
|
||||
xml_cb.tagbegin = cbtagbegin;
|
||||
|
||||
nretval = xml_parse(istream, &xml_cb);
|
||||
if (istream!=stdin) fclose(istream);
|
||||
if (ostream!=stdout) fclose(ostream);
|
||||
}
|
||||
return nretval;
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
# Microsoft Developer Studio Project File - Name="xmltest" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=xmltest - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "xmltest.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "xmltest.mak" CFG="xmltest - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "xmltest - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "xmltest - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "xmltest - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x407 /d "NDEBUG"
|
||||
# ADD RSC /l 0x407 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "xmltest - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../common/util" /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x407 /d "_DEBUG"
|
||||
# ADD RSC /l 0x407 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "xmltest - Win32 Release"
|
||||
# Name "xmltest - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\xmltest.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
Loading…
Reference in New Issue