- added initial folder(s) and code to handle loading common data to save duplicated files space
This commit is contained in:
parent
6db2b394bf
commit
102363f151
|
@ -398,22 +398,22 @@ void UnitType::load(int id,const string &dir, const TechTree *techTree,
|
||||||
//image
|
//image
|
||||||
const XmlNode *imageNode= parametersNode->getChild("image");
|
const XmlNode *imageNode= parametersNode->getChild("image");
|
||||||
image= Renderer::getInstance().newTexture2D(rsGame);
|
image= Renderer::getInstance().newTexture2D(rsGame);
|
||||||
image->load(currentPath + imageNode->getAttribute("path")->getRestrictedValue());
|
image->load(imageNode->getAttribute("path")->getRestrictedValue(currentPath));
|
||||||
loadedFileList[currentPath + imageNode->getAttribute("path")->getRestrictedValue()]++;
|
loadedFileList[imageNode->getAttribute("path")->getRestrictedValue(currentPath)]++;
|
||||||
|
|
||||||
//image cancel
|
//image cancel
|
||||||
const XmlNode *imageCancelNode= parametersNode->getChild("image-cancel");
|
const XmlNode *imageCancelNode= parametersNode->getChild("image-cancel");
|
||||||
cancelImage= Renderer::getInstance().newTexture2D(rsGame);
|
cancelImage= Renderer::getInstance().newTexture2D(rsGame);
|
||||||
cancelImage->load(currentPath + imageCancelNode->getAttribute("path")->getRestrictedValue());
|
cancelImage->load(imageCancelNode->getAttribute("path")->getRestrictedValue(currentPath));
|
||||||
loadedFileList[currentPath + imageCancelNode->getAttribute("path")->getRestrictedValue()]++;
|
loadedFileList[imageCancelNode->getAttribute("path")->getRestrictedValue(currentPath)]++;
|
||||||
|
|
||||||
//meeting point
|
//meeting point
|
||||||
const XmlNode *meetingPointNode= parametersNode->getChild("meeting-point");
|
const XmlNode *meetingPointNode= parametersNode->getChild("meeting-point");
|
||||||
meetingPoint= meetingPointNode->getAttribute("value")->getBoolValue();
|
meetingPoint= meetingPointNode->getAttribute("value")->getBoolValue();
|
||||||
if(meetingPoint){
|
if(meetingPoint){
|
||||||
meetingPointImage= Renderer::getInstance().newTexture2D(rsGame);
|
meetingPointImage= Renderer::getInstance().newTexture2D(rsGame);
|
||||||
meetingPointImage->load(currentPath + meetingPointNode->getAttribute("image-path")->getRestrictedValue());
|
meetingPointImage->load(meetingPointNode->getAttribute("image-path")->getRestrictedValue(currentPath));
|
||||||
loadedFileList[currentPath + meetingPointNode->getAttribute("image-path")->getRestrictedValue()]++;
|
loadedFileList[meetingPointNode->getAttribute("image-path")->getRestrictedValue(currentPath)]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
//selection sounds
|
//selection sounds
|
||||||
|
@ -422,10 +422,10 @@ void UnitType::load(int id,const string &dir, const TechTree *techTree,
|
||||||
selectionSounds.resize(selectionSoundNode->getChildCount());
|
selectionSounds.resize(selectionSoundNode->getChildCount());
|
||||||
for(int i=0; i<selectionSounds.getSounds().size(); ++i){
|
for(int i=0; i<selectionSounds.getSounds().size(); ++i){
|
||||||
const XmlNode *soundNode= selectionSoundNode->getChild("sound", i);
|
const XmlNode *soundNode= selectionSoundNode->getChild("sound", i);
|
||||||
string path= soundNode->getAttribute("path")->getRestrictedValue();
|
string path= soundNode->getAttribute("path")->getRestrictedValue(currentPath);
|
||||||
StaticSound *sound= new StaticSound();
|
StaticSound *sound= new StaticSound();
|
||||||
sound->load(currentPath + path);
|
sound->load(path);
|
||||||
loadedFileList[currentPath + path]++;
|
loadedFileList[path]++;
|
||||||
selectionSounds[i]= sound;
|
selectionSounds[i]= sound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -436,10 +436,10 @@ void UnitType::load(int id,const string &dir, const TechTree *techTree,
|
||||||
commandSounds.resize(commandSoundNode->getChildCount());
|
commandSounds.resize(commandSoundNode->getChildCount());
|
||||||
for(int i=0; i<commandSoundNode->getChildCount(); ++i){
|
for(int i=0; i<commandSoundNode->getChildCount(); ++i){
|
||||||
const XmlNode *soundNode= commandSoundNode->getChild("sound", i);
|
const XmlNode *soundNode= commandSoundNode->getChild("sound", i);
|
||||||
string path= soundNode->getAttribute("path")->getRestrictedValue();
|
string path= soundNode->getAttribute("path")->getRestrictedValue(currentPath);
|
||||||
StaticSound *sound= new StaticSound();
|
StaticSound *sound= new StaticSound();
|
||||||
sound->load(currentPath + path);
|
sound->load(path);
|
||||||
loadedFileList[currentPath + path]++;
|
loadedFileList[path]++;
|
||||||
commandSounds[i]= sound;
|
commandSounds[i]= sound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,10 +127,12 @@ private:
|
||||||
// class XmlAttribute
|
// class XmlAttribute
|
||||||
// =====================================================
|
// =====================================================
|
||||||
|
|
||||||
class XmlAttribute{
|
class XmlAttribute {
|
||||||
private:
|
private:
|
||||||
string value;
|
string value;
|
||||||
string name;
|
string name;
|
||||||
|
bool skipRestrictionCheck;
|
||||||
|
bool usesCommondata;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
XmlAttribute(XmlAttribute&);
|
XmlAttribute(XmlAttribute&);
|
||||||
|
@ -141,15 +143,15 @@ public:
|
||||||
XmlAttribute(const string &name, const string &value);
|
XmlAttribute(const string &name, const string &value);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const string &getName() const {return name;}
|
const string getName() const {return name;}
|
||||||
const string &getValue() const {return value;}
|
const string getValue(string prefixValue="") const;
|
||||||
|
|
||||||
bool getBoolValue() const;
|
bool getBoolValue() const;
|
||||||
int getIntValue() const;
|
int getIntValue() const;
|
||||||
int getIntValue(int min, int max) const;
|
int getIntValue(int min, int max) const;
|
||||||
float getFloatValue() const;
|
float getFloatValue() const;
|
||||||
float getFloatValue(float min, float max) const;
|
float getFloatValue(float min, float max) const;
|
||||||
const string &getRestrictedValue() const;
|
const string getRestrictedValue(string prefixValue="") const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,6 @@ void Properties::load(const string &path, bool clearCurrentProperties) {
|
||||||
|
|
||||||
bool Properties::applyTagsToValue(string &value) {
|
bool Properties::applyTagsToValue(string &value) {
|
||||||
string originalValue = value;
|
string originalValue = value;
|
||||||
|
|
||||||
char *homeDir = NULL;
|
char *homeDir = NULL;
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
homeDir = getenv("USERPROFILE");
|
homeDir = getenv("USERPROFILE");
|
||||||
|
@ -144,11 +143,19 @@ bool Properties::applyTagsToValue(string &value) {
|
||||||
#if defined(CUSTOM_DATA_INSTALL_PATH)
|
#if defined(CUSTOM_DATA_INSTALL_PATH)
|
||||||
replaceAll(value, "$APPLICATIONDATAPATH", CUSTOM_DATA_INSTALL_PATH);
|
replaceAll(value, "$APPLICATIONDATAPATH", CUSTOM_DATA_INSTALL_PATH);
|
||||||
replaceAll(value, "%%APPLICATIONDATAPATH%%", CUSTOM_DATA_INSTALL_PATH);
|
replaceAll(value, "%%APPLICATIONDATAPATH%%", CUSTOM_DATA_INSTALL_PATH);
|
||||||
|
|
||||||
|
replaceAll(value, "$COMMONDATAPATH", string(CUSTOM_DATA_INSTALL_PATH) + "/commondata/");
|
||||||
|
replaceAll(value, "%%COMMONDATAPATH%%", string(CUSTOM_DATA_INSTALL_PATH) + "/commondata/");
|
||||||
|
|
||||||
#else
|
#else
|
||||||
replaceAll(value, "$APPLICATIONDATAPATH", Properties::applicationPath);
|
replaceAll(value, "$APPLICATIONDATAPATH", Properties::applicationPath);
|
||||||
replaceAll(value, "%%APPLICATIONDATAPATH%%", Properties::applicationPath);
|
replaceAll(value, "%%APPLICATIONDATAPATH%%", Properties::applicationPath);
|
||||||
|
|
||||||
|
replaceAll(value, "$COMMONDATAPATH", Properties::applicationPath + "/commondata/");
|
||||||
|
replaceAll(value, "%%COMMONDATAPATH%%", Properties::applicationPath + "/commondata/");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//printf("\nBEFORE SUBSTITUTE [%s] AFTER [%s]\n",originalValue.c_str(),value.c_str());
|
||||||
return (originalValue != value);
|
return (originalValue != value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <xercesc/framework/LocalFileFormatTarget.hpp>
|
#include <xercesc/framework/LocalFileFormatTarget.hpp>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "properties.h"
|
||||||
#include "leak_dumper.h"
|
#include "leak_dumper.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -180,8 +181,7 @@ XmlTree::~XmlTree(){
|
||||||
// class XmlNode
|
// class XmlNode
|
||||||
// =====================================================
|
// =====================================================
|
||||||
|
|
||||||
XmlNode::XmlNode(DOMNode *node){
|
XmlNode::XmlNode(DOMNode *node) {
|
||||||
|
|
||||||
if(node == NULL || node->getNodeName() == NULL) {
|
if(node == NULL || node->getNodeName() == NULL) {
|
||||||
throw runtime_error("XML structure seems to be corrupt!");
|
throw runtime_error("XML structure seems to be corrupt!");
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ XmlNode::XmlNode(DOMNode *node){
|
||||||
if(domAttributes != NULL) {
|
if(domAttributes != NULL) {
|
||||||
for(unsigned int i = 0; i < domAttributes->getLength(); ++i) {
|
for(unsigned int i = 0; i < domAttributes->getLength(); ++i) {
|
||||||
DOMNode *currentNode= domAttributes->item(i);
|
DOMNode *currentNode= domAttributes->item(i);
|
||||||
if(currentNode->getNodeType()==DOMNode::ATTRIBUTE_NODE){
|
if(currentNode->getNodeType() == DOMNode::ATTRIBUTE_NODE) {
|
||||||
XmlAttribute *xmlAttribute= new XmlAttribute(domAttributes->item(i));
|
XmlAttribute *xmlAttribute= new XmlAttribute(domAttributes->item(i));
|
||||||
attributes.push_back(xmlAttribute);
|
attributes.push_back(xmlAttribute);
|
||||||
}
|
}
|
||||||
|
@ -223,33 +223,34 @@ XmlNode::XmlNode(DOMNode *node){
|
||||||
if(node->getNodeType() == DOMNode::ELEMENT_NODE && children.size() == 0) {
|
if(node->getNodeType() == DOMNode::ELEMENT_NODE && children.size() == 0) {
|
||||||
char *textStr= XMLString::transcode(node->getTextContent());
|
char *textStr= XMLString::transcode(node->getTextContent());
|
||||||
text= textStr;
|
text= textStr;
|
||||||
|
//Properties::applyTagsToValue(this->text);
|
||||||
XMLString::release(&textStr);
|
XMLString::release(&textStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlNode::XmlNode(const string &name){
|
XmlNode::XmlNode(const string &name) {
|
||||||
this->name= name;
|
this->name= name;
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlNode::~XmlNode(){
|
XmlNode::~XmlNode() {
|
||||||
for(unsigned int i=0; i<children.size(); ++i){
|
for(unsigned int i=0; i<children.size(); ++i) {
|
||||||
delete children[i];
|
delete children[i];
|
||||||
}
|
}
|
||||||
for(unsigned int i=0; i<attributes.size(); ++i){
|
for(unsigned int i=0; i<attributes.size(); ++i) {
|
||||||
delete attributes[i];
|
delete attributes[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlAttribute *XmlNode::getAttribute(unsigned int i) const{
|
XmlAttribute *XmlNode::getAttribute(unsigned int i) const {
|
||||||
if(i>=attributes.size()){
|
if(i >= attributes.size()) {
|
||||||
throw runtime_error(getName()+" node doesn't have "+intToStr(i)+" attributes");
|
throw runtime_error(getName()+" node doesn't have "+intToStr(i)+" attributes");
|
||||||
}
|
}
|
||||||
return attributes[i];
|
return attributes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlAttribute *XmlNode::getAttribute(const string &name,bool mustExist) const {
|
XmlAttribute *XmlNode::getAttribute(const string &name,bool mustExist) const {
|
||||||
for(unsigned int i=0; i<attributes.size(); ++i){
|
for(unsigned int i = 0; i < attributes.size(); ++i) {
|
||||||
if(attributes[i]->getName()==name){
|
if(attributes[i]->getName() == name) {
|
||||||
return attributes[i];
|
return attributes[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,8 +262,9 @@ XmlAttribute *XmlNode::getAttribute(const string &name,bool mustExist) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlNode *XmlNode::getChild(unsigned int i) const {
|
XmlNode *XmlNode::getChild(unsigned int i) const {
|
||||||
if(i>=children.size())
|
if(i >= children.size()) {
|
||||||
throw runtime_error("\"" + getName()+"\" node doesn't have "+intToStr(i+1)+" children");
|
throw runtime_error("\"" + getName()+"\" node doesn't have "+intToStr(i+1)+" children");
|
||||||
|
}
|
||||||
return children[i];
|
return children[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,9 +275,9 @@ XmlNode *XmlNode::getChild(const string &childName, unsigned int i) const{
|
||||||
}
|
}
|
||||||
|
|
||||||
int count= 0;
|
int count= 0;
|
||||||
for(unsigned int j=0; j<children.size(); ++j){
|
for(unsigned int j = 0; j < children.size(); ++j) {
|
||||||
if(children[j]->getName()==childName){
|
if(children[j]->getName() == childName) {
|
||||||
if(count==i){
|
if(count == i) {
|
||||||
return children[j];
|
return children[j];
|
||||||
}
|
}
|
||||||
count++;
|
count++;
|
||||||
|
@ -285,14 +287,11 @@ XmlNode *XmlNode::getChild(const string &childName, unsigned int i) const{
|
||||||
throw runtime_error("Node \""+getName()+"\" doesn't have "+intToStr(i+1)+" children named \""+childName+"\"\n\nTree: "+getTreeString());
|
throw runtime_error("Node \""+getName()+"\" doesn't have "+intToStr(i+1)+" children named \""+childName+"\"\n\nTree: "+getTreeString());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XmlNode::hasChildAtIndex(const string &childName, int i) const
|
bool XmlNode::hasChildAtIndex(const string &childName, int i) const {
|
||||||
{
|
|
||||||
int count= 0;
|
int count= 0;
|
||||||
for(unsigned int j = 0; j < children.size(); ++j)
|
for(unsigned int j = 0; j < children.size(); ++j) {
|
||||||
{
|
if(children[j]->getName()==childName) {
|
||||||
if(children[j]->getName()==childName)
|
if(count == i) {
|
||||||
{
|
|
||||||
if(count==i){
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
count++;
|
count++;
|
||||||
|
@ -303,13 +302,10 @@ bool XmlNode::hasChildAtIndex(const string &childName, int i) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool XmlNode::hasChild(const string &childName) const
|
bool XmlNode::hasChild(const string &childName) const {
|
||||||
{
|
|
||||||
int count= 0;
|
int count= 0;
|
||||||
for(unsigned int j = 0; j < children.size(); ++j)
|
for(unsigned int j = 0; j < children.size(); ++j) {
|
||||||
{
|
if(children[j]->getName() == childName) {
|
||||||
if(children[j]->getName()==childName)
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -323,7 +319,7 @@ XmlNode *XmlNode::addChild(const string &name){
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlAttribute *XmlNode::addAttribute(const string &name, const string &value){
|
XmlAttribute *XmlNode::addAttribute(const string &name, const string &value) {
|
||||||
XmlAttribute *attr= new XmlAttribute(name, value);
|
XmlAttribute *attr= new XmlAttribute(name, value);
|
||||||
attributes.push_back(attr);
|
attributes.push_back(attr);
|
||||||
return attr;
|
return attr;
|
||||||
|
@ -352,14 +348,14 @@ DOMElement *XmlNode::buildElement(XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *do
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
string XmlNode::getTreeString() const{
|
string XmlNode::getTreeString() const {
|
||||||
string str;
|
string str;
|
||||||
|
|
||||||
str+= getName();
|
str+= getName();
|
||||||
|
|
||||||
if(!children.empty()){
|
if(!children.empty()) {
|
||||||
str+= " (";
|
str+= " (";
|
||||||
for(unsigned int i=0; i<children.size(); ++i){
|
for(unsigned int i=0; i<children.size(); ++i) {
|
||||||
str+= children[i]->getTreeString();
|
str+= children[i]->getTreeString();
|
||||||
str+= " ";
|
str+= " ";
|
||||||
}
|
}
|
||||||
|
@ -373,38 +369,46 @@ string XmlNode::getTreeString() const{
|
||||||
// class XmlAttribute
|
// class XmlAttribute
|
||||||
// =====================================================
|
// =====================================================
|
||||||
|
|
||||||
XmlAttribute::XmlAttribute(DOMNode *attribute){
|
XmlAttribute::XmlAttribute(DOMNode *attribute) {
|
||||||
char str[strSize];
|
skipRestrictionCheck = false;
|
||||||
|
usesCommondata = false;
|
||||||
|
char str[strSize]="";
|
||||||
|
|
||||||
XMLString::transcode(attribute->getNodeValue(), str, strSize-1);
|
XMLString::transcode(attribute->getNodeValue(), str, strSize-1);
|
||||||
value= str;
|
value= str;
|
||||||
|
usesCommondata = ((value.find("$COMMONDATAPATH") != string::npos) || (value.find("%%COMMONDATAPATH%%") != string::npos));
|
||||||
|
skipRestrictionCheck = Properties::applyTagsToValue(this->value);
|
||||||
|
|
||||||
XMLString::transcode(attribute->getNodeName(), str, strSize-1);
|
XMLString::transcode(attribute->getNodeName(), str, strSize-1);
|
||||||
name= str;
|
name= str;
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlAttribute::XmlAttribute(const string &name, const string &value){
|
XmlAttribute::XmlAttribute(const string &name, const string &value) {
|
||||||
|
skipRestrictionCheck = false;
|
||||||
|
usesCommondata = false;
|
||||||
this->name= name;
|
this->name= name;
|
||||||
this->value= value;
|
this->value= value;
|
||||||
|
usesCommondata = ((value.find("$COMMONDATAPATH") != string::npos) || (value.find("%%COMMONDATAPATH%%") != string::npos));
|
||||||
|
skipRestrictionCheck = Properties::applyTagsToValue(this->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XmlAttribute::getBoolValue() const{
|
bool XmlAttribute::getBoolValue() const {
|
||||||
if(value=="true"){
|
if(value == "true") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(value=="false"){
|
else if(value == "false") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
throw runtime_error("Not a valid bool value (true or false): " +getName()+": "+ value);
|
throw runtime_error("Not a valid bool value (true or false): " +getName()+": "+ value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int XmlAttribute::getIntValue() const{
|
int XmlAttribute::getIntValue() const {
|
||||||
return strToInt(value);
|
return strToInt(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
int XmlAttribute::getIntValue(int min, int max) const{
|
int XmlAttribute::getIntValue(int min, int max) const {
|
||||||
int i= strToInt(value);
|
int i= strToInt(value);
|
||||||
if(i<min || i>max){
|
if(i<min || i>max){
|
||||||
throw runtime_error("Xml Attribute int out of range: " + getName() + ": " + value);
|
throw runtime_error("Xml Attribute int out of range: " + getName() + ": " + value);
|
||||||
|
@ -424,19 +428,32 @@ float XmlAttribute::getFloatValue(float min, float max) const{
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
const string &XmlAttribute::getRestrictedValue() const
|
const string XmlAttribute::getValue(string prefixValue) const {
|
||||||
{
|
string result = value;
|
||||||
const string allowedCharacters = "abcdefghijklmnopqrstuvwxyz1234567890._-/";
|
if(skipRestrictionCheck == false && usesCommondata == false) {
|
||||||
|
result = prefixValue + value;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
for(unsigned int i= 0; i<value.size(); ++i){
|
const string XmlAttribute::getRestrictedValue(string prefixValue) const {
|
||||||
if(allowedCharacters.find(value[i])==string::npos){
|
if(skipRestrictionCheck == false && usesCommondata == false) {
|
||||||
throw runtime_error(
|
const string allowedCharacters = "abcdefghijklmnopqrstuvwxyz1234567890._-/";
|
||||||
string("The string \"" + value + "\" contains a character that is not allowed: \"") + value[i] +
|
|
||||||
"\"\nFor portability reasons the only allowed characters in this field are: " + allowedCharacters);
|
for(unsigned int i= 0; i<value.size(); ++i){
|
||||||
|
if(allowedCharacters.find(value[i])==string::npos){
|
||||||
|
throw runtime_error(
|
||||||
|
string("The string \"" + value + "\" contains a character that is not allowed: \"") + value[i] +
|
||||||
|
"\"\nFor portability reasons the only allowed characters in this field are: " + allowedCharacters);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
string result = value;
|
||||||
|
if(skipRestrictionCheck == false && usesCommondata == false) {
|
||||||
|
result = prefixValue + value;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}}//end namespace
|
}}//end namespace
|
||||||
|
|
Loading…
Reference in New Issue
Block a user