updated to the current pikotools api from branch api2021
This commit is contained in:
parent
85f9fda984
commit
f1af7e2eeb
|
@ -272,7 +272,6 @@ return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool App::Init()
|
bool App::Init()
|
||||||
{
|
{
|
||||||
postgresql_connector.set_conn_param(config.db_database, config.db_user, config.db_pass);
|
postgresql_connector.set_conn_param(config.db_database, config.db_user, config.db_pass);
|
||||||
|
@ -283,7 +282,6 @@ bool App::Init()
|
||||||
model_connector.set_flat_connector(json_connector);
|
model_connector.set_flat_connector(json_connector);
|
||||||
model_connector.set_db_connector(postgresql_connector);
|
model_connector.set_db_connector(postgresql_connector);
|
||||||
model_connector.set_logger(log);
|
model_connector.set_logger(log);
|
||||||
//model_connector.set_doc_connector(doc_html_connector);
|
|
||||||
|
|
||||||
// temporary
|
// temporary
|
||||||
if( config.space.to_bool(L"do_migration_to_winix_fullmorm", false) )
|
if( config.space.to_bool(L"do_migration_to_winix_fullmorm", false) )
|
||||||
|
@ -295,30 +293,6 @@ bool App::Init()
|
||||||
log << log1 << "Migrations complete, now remove do_migration_to_winix_fullmorm from the config" << logend;
|
log << log1 << "Migrations complete, now remove do_migration_to_winix_fullmorm from the config" << logend;
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
/////////////
|
|
||||||
|
|
||||||
morm::Finder<User> finder(model_connector);
|
|
||||||
|
|
||||||
User user = finder.
|
|
||||||
select().
|
|
||||||
where().
|
|
||||||
eq(L"id", 1).
|
|
||||||
get();
|
|
||||||
|
|
||||||
|
|
||||||
log << log1 << user << logend;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::exit(0);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
db_conn.SetConnParam(config.db_database, config.db_user, config.db_pass);
|
db_conn.SetConnParam(config.db_database, config.db_user, config.db_pass);
|
||||||
db_conn.WaitForConnection();
|
db_conn.WaitForConnection();
|
||||||
|
@ -956,12 +930,12 @@ void App::ReadEnvHTTPVariables()
|
||||||
{
|
{
|
||||||
char * env = *e;
|
char * env = *e;
|
||||||
|
|
||||||
if( PT::IsSubStringNoCasep("HTTP_", env) )
|
if( PT::is_substr_nc("HTTP_", env) )
|
||||||
{
|
{
|
||||||
env += http_prefix_len;
|
env += http_prefix_len;
|
||||||
|
|
||||||
// cookies we have in a different table
|
// cookies we have in a different table
|
||||||
if( !PT::IsSubStringNoCasep("COOKIE=", env) )
|
if( !PT::is_substr_nc("COOKIE=", env) )
|
||||||
{
|
{
|
||||||
if( SaveEnvHTTPVariable(env) )
|
if( SaveEnvHTTPVariable(env) )
|
||||||
{
|
{
|
||||||
|
@ -991,7 +965,7 @@ bool App::SaveEnvHTTPVariable(const char * env)
|
||||||
|
|
||||||
for( ; env[i] != 0 && env[i] != '=' && i < Request::INPUT_HEADER_NAME_MAX_LENGTH ; ++i)
|
for( ; env[i] != 0 && env[i] != '=' && i < Request::INPUT_HEADER_NAME_MAX_LENGTH ; ++i)
|
||||||
{
|
{
|
||||||
header_name[i] = PT::ToLower(env[i]);
|
header_name[i] = PT::to_lower(env[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
header_name[i] = 0;
|
header_name[i] = 0;
|
||||||
|
@ -1039,7 +1013,7 @@ void App::ReadEnvRemoteIP()
|
||||||
{
|
{
|
||||||
http_header_name = L"HTTP_";
|
http_header_name = L"HTTP_";
|
||||||
http_header_name += config.proxy_ip_header;
|
http_header_name += config.proxy_ip_header;
|
||||||
PT::ToUpper(http_header_name);
|
PT::to_upper_emplace(http_header_name);
|
||||||
|
|
||||||
PT::WideToUTF8(http_header_name, http_header_8bit);
|
PT::WideToUTF8(http_header_name, http_header_8bit);
|
||||||
v = FCGX_GetParam(http_header_8bit.c_str(), fcgi_request.envp);
|
v = FCGX_GetParam(http_header_8bit.c_str(), fcgi_request.envp);
|
||||||
|
@ -1065,16 +1039,16 @@ void App::CheckRequestMethod()
|
||||||
|
|
||||||
if( !cur.request->env_request_method.empty() )
|
if( !cur.request->env_request_method.empty() )
|
||||||
{
|
{
|
||||||
if( PT::ToLower(cur.request->env_request_method[0]) == 'g' )
|
if( PT::to_lower(cur.request->env_request_method[0]) == 'g' )
|
||||||
cur.request->method = Request::get;
|
cur.request->method = Request::get;
|
||||||
else
|
else
|
||||||
if( PT::ToLower(cur.request->env_request_method[0]) == 'p' )
|
if( PT::to_lower(cur.request->env_request_method[0]) == 'p' )
|
||||||
cur.request->method = Request::post;
|
cur.request->method = Request::post;
|
||||||
else
|
else
|
||||||
if( PT::ToLower(cur.request->env_request_method[0]) == 'h' )
|
if( PT::to_lower(cur.request->env_request_method[0]) == 'h' )
|
||||||
cur.request->method = Request::head;
|
cur.request->method = Request::head;
|
||||||
else
|
else
|
||||||
if( PT::ToLower(cur.request->env_request_method[0]) == 'd' )
|
if( PT::to_lower(cur.request->env_request_method[0]) == 'd' )
|
||||||
cur.request->method = Request::delete_;
|
cur.request->method = Request::delete_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1090,7 +1064,7 @@ void App::CheckSSL()
|
||||||
if( config.assume_connection_is_through_ssl )
|
if( config.assume_connection_is_through_ssl )
|
||||||
cur.request->using_ssl = true;
|
cur.request->using_ssl = true;
|
||||||
else
|
else
|
||||||
if( PT::EqualNoCase(cur.request->env_https.c_str(), L"on") )
|
if( PT::is_equal_nc(cur.request->env_https.c_str(), L"on") )
|
||||||
cur.request->using_ssl = true;
|
cur.request->using_ssl = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1173,13 +1147,13 @@ void App::ReadPostVars()
|
||||||
|
|
||||||
if( cur.request->method == Request::post || cur.request->method == Request::delete_ )
|
if( cur.request->method == Request::post || cur.request->method == Request::delete_ )
|
||||||
{
|
{
|
||||||
if( PT::IsSubStringNoCase(L"multipart/form-data", cur.request->env_content_type.c_str()) )
|
if( PT::is_substr_nc(L"multipart/form-data", cur.request->env_content_type.c_str()) )
|
||||||
{
|
{
|
||||||
log << log3 << "App: post content type: multipart/form-data" << logend;
|
log << log3 << "App: post content type: multipart/form-data" << logend;
|
||||||
post_multi_parser.Parse(fcgi_request.in, cur.request->post_tab, cur.request->post_file_tab);
|
post_multi_parser.Parse(fcgi_request.in, cur.request->post_tab, cur.request->post_file_tab);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if( PT::IsSubStringNoCase(L"application/json", cur.request->env_content_type.c_str()) )
|
if( PT::is_substr_nc(L"application/json", cur.request->env_content_type.c_str()) )
|
||||||
{
|
{
|
||||||
log << log3 << "App: post content type: application/json" << logend;
|
log << log3 << "App: post content type: application/json" << logend;
|
||||||
ReadPostJson();
|
ReadPostJson();
|
||||||
|
|
|
@ -331,7 +331,7 @@ void CorrectUrlOnlyAllowedChar(std::wstring & url)
|
||||||
{
|
{
|
||||||
CorrectUrlDots(url);
|
CorrectUrlDots(url);
|
||||||
CorrectUrlChars(url);
|
CorrectUrlChars(url);
|
||||||
PT::ToLower(url);
|
PT::to_lower_emplace(url);
|
||||||
Trim(url, '_');
|
Trim(url, '_');
|
||||||
|
|
||||||
if( url.empty() || url == L"." )
|
if( url.empty() || url == L"." )
|
||||||
|
@ -1219,31 +1219,31 @@ int SelectFileType(const wchar_t * file_name)
|
||||||
|
|
||||||
// as an image we're using only those types which can be rendered
|
// as an image we're using only those types which can be rendered
|
||||||
// by a web browser
|
// by a web browser
|
||||||
if( PT::EqualNoCase(ext, L"jpg") ||
|
if( PT::is_equal_nc(ext, L"jpg") ||
|
||||||
PT::EqualNoCase(ext, L"jpeg") ||
|
PT::is_equal_nc(ext, L"jpeg") ||
|
||||||
PT::EqualNoCase(ext, L"jpe") ||
|
PT::is_equal_nc(ext, L"jpe") ||
|
||||||
PT::EqualNoCase(ext, L"pic") ||
|
PT::is_equal_nc(ext, L"pic") ||
|
||||||
PT::EqualNoCase(ext, L"tga") ||
|
PT::is_equal_nc(ext, L"tga") ||
|
||||||
PT::EqualNoCase(ext, L"gif") ||
|
PT::is_equal_nc(ext, L"gif") ||
|
||||||
PT::EqualNoCase(ext, L"bmp") ||
|
PT::is_equal_nc(ext, L"bmp") ||
|
||||||
PT::EqualNoCase(ext, L"png") )
|
PT::is_equal_nc(ext, L"png") )
|
||||||
return WINIX_ITEM_FILETYPE_IMAGE;
|
return WINIX_ITEM_FILETYPE_IMAGE;
|
||||||
|
|
||||||
if( PT::EqualNoCase(ext, L"pdf") ||
|
if( PT::is_equal_nc(ext, L"pdf") ||
|
||||||
PT::EqualNoCase(ext, L"doc") ||
|
PT::is_equal_nc(ext, L"doc") ||
|
||||||
PT::EqualNoCase(ext, L"xls") ||
|
PT::is_equal_nc(ext, L"xls") ||
|
||||||
PT::EqualNoCase(ext, L"txt") ||
|
PT::is_equal_nc(ext, L"txt") ||
|
||||||
PT::EqualNoCase(ext, L"ods") ||
|
PT::is_equal_nc(ext, L"ods") ||
|
||||||
PT::EqualNoCase(ext, L"odt") )
|
PT::is_equal_nc(ext, L"odt") )
|
||||||
return WINIX_ITEM_FILETYPE_DOCUMENT;
|
return WINIX_ITEM_FILETYPE_DOCUMENT;
|
||||||
|
|
||||||
if( PT::EqualNoCase(ext, L"avi") ||
|
if( PT::is_equal_nc(ext, L"avi") ||
|
||||||
PT::EqualNoCase(ext, L"mp4") ||
|
PT::is_equal_nc(ext, L"mp4") ||
|
||||||
PT::EqualNoCase(ext, L"flv") ||
|
PT::is_equal_nc(ext, L"flv") ||
|
||||||
PT::EqualNoCase(ext, L"mpg") ||
|
PT::is_equal_nc(ext, L"mpg") ||
|
||||||
PT::EqualNoCase(ext, L"mpeg") ||
|
PT::is_equal_nc(ext, L"mpeg") ||
|
||||||
PT::EqualNoCase(ext, L"mkv") ||
|
PT::is_equal_nc(ext, L"mkv") ||
|
||||||
PT::EqualNoCase(ext, L"wmv") )
|
PT::is_equal_nc(ext, L"wmv") )
|
||||||
return WINIX_ITEM_FILETYPE_VIDEO;
|
return WINIX_ITEM_FILETYPE_VIDEO;
|
||||||
|
|
||||||
return WINIX_ITEM_FILETYPE_UNKNOWN;
|
return WINIX_ITEM_FILETYPE_UNKNOWN;
|
||||||
|
|
|
@ -420,7 +420,7 @@ size_t i = 0;
|
||||||
|
|
||||||
while( i < buf.size() )
|
while( i < buf.size() )
|
||||||
{
|
{
|
||||||
if( PT::IsSubString(look_for.c_str(), buf.c_str() + i) )
|
if( PT::is_substr(look_for.c_str(), buf.c_str() + i) )
|
||||||
{
|
{
|
||||||
buf.erase(i, look_for.size());
|
buf.erase(i, look_for.size());
|
||||||
buf.insert(i, replace);
|
buf.insert(i, replace);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2008-2018, Tomasz Sowa
|
* Copyright (c) 2008-2021, Tomasz Sowa
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -382,7 +382,7 @@ void PostMultiParser::ReadContent()
|
||||||
|
|
||||||
log << log2 << "PMP: content size: " << content_len << " bytes" << logend;
|
log << log2 << "PMP: content size: " << content_len << " bytes" << logend;
|
||||||
|
|
||||||
if( !PT::IsSubStringNoCase("pass", name.c_str()) )
|
if( !PT::is_substr_nc("pass", name.c_str()) )
|
||||||
LogFirst(content, config->log_post_value_size);
|
LogFirst(content, config->log_post_value_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ protected:
|
||||||
{
|
{
|
||||||
log << log2 << "Method POST, name: \"" << name << "\"";
|
log << log2 << "Method POST, name: \"" << name << "\"";
|
||||||
|
|
||||||
if( log_value_size > 0 && !PT::IsSubStringNoCase(L"pass", name.c_str()) )
|
if( log_value_size > 0 && !PT::is_substr_nc(L"pass", name.c_str()) )
|
||||||
{
|
{
|
||||||
log << ", value: ";
|
log << ", value: ";
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,6 @@ return false;
|
||||||
void Env::SaveEnv()
|
void Env::SaveEnv()
|
||||||
{
|
{
|
||||||
const std::wstring & env_str = cur->request->PostVar(L"envvar");
|
const std::wstring & env_str = cur->request->PostVar(L"envvar");
|
||||||
long user_id = puser->id;
|
|
||||||
bool status = false;
|
bool status = false;
|
||||||
|
|
||||||
if( cur->request->IsParam(L"a") )
|
if( cur->request->IsParam(L"a") )
|
||||||
|
|
|
@ -119,7 +119,7 @@ SortPair sp;
|
||||||
|
|
||||||
for( ; i2 != cur->request->post_tab.end() ; ++i2 )
|
for( ; i2 != cur->request->post_tab.end() ; ++i2 )
|
||||||
{
|
{
|
||||||
if( PT::IsSubStringNoCase(L"sort", i2->first.c_str()) )
|
if( PT::is_substr_nc(L"sort", i2->first.c_str()) )
|
||||||
{
|
{
|
||||||
sp.id = Tol(i2->first.c_str() + 4);
|
sp.id = Tol(i2->first.c_str() + 4);
|
||||||
sp.sort_index = Toi(i2->second);
|
sp.sort_index = Toi(i2->second);
|
||||||
|
|
|
@ -58,7 +58,7 @@ void User::map_fields()
|
||||||
field(L"has_pass", has_pass);
|
field(L"has_pass", has_pass);
|
||||||
field(L"pass_type", pass_type);
|
field(L"pass_type", pass_type);
|
||||||
field(L"password", password);
|
field(L"password", password);
|
||||||
field(L"pass_encrypted", pass_encrypted);
|
field(L"pass_encrypted", pass_encrypted, morm::FT::binary);
|
||||||
field(L"pass_hash_salted", pass_hash_salted);
|
field(L"pass_hash_salted", pass_hash_salted);
|
||||||
|
|
||||||
field(L"email", email);
|
field(L"email", email);
|
||||||
|
|
|
@ -129,6 +129,7 @@ public:
|
||||||
std::vector<long> groups;
|
std::vector<long> groups;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
User();
|
User();
|
||||||
|
|
||||||
void map_fields();
|
void map_fields();
|
||||||
|
|
|
@ -143,7 +143,7 @@ bool ExportInfo::SkipDir(long dir_id, std::wstring & dir)
|
||||||
{
|
{
|
||||||
if( system->dirs.MakePath(dir_id, tmp_dir) )
|
if( system->dirs.MakePath(dir_id, tmp_dir) )
|
||||||
{
|
{
|
||||||
if( !tmp_dir.empty() && PT::IsSubString(tmp_dir, dir) )
|
if( !tmp_dir.empty() && PT::is_substr(tmp_dir, dir) )
|
||||||
{
|
{
|
||||||
// tmp_dir has a slash at the end
|
// tmp_dir has a slash at the end
|
||||||
// we want the slash at the beginning
|
// we want the slash at the beginning
|
||||||
|
|
|
@ -393,13 +393,13 @@ bool ExportThread::HasThumbInAdress(std::string & buf, size_t i)
|
||||||
|
|
||||||
for( ; i<buf.size() ; ++i)
|
for( ; i<buf.size() ; ++i)
|
||||||
{
|
{
|
||||||
if( PT::IsSubStringp(thumb1, &buf[i]) )
|
if( PT::is_substr(thumb1, &buf[i]) )
|
||||||
{
|
{
|
||||||
buf.erase(i, len1);
|
buf.erase(i, len1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( PT::IsSubStringp(thumb2, &buf[i]) )
|
if( PT::is_substr(thumb2, &buf[i]) )
|
||||||
{
|
{
|
||||||
buf.erase(i, len2);
|
buf.erase(i, len2);
|
||||||
return true;
|
return true;
|
||||||
|
@ -427,7 +427,7 @@ void ExportThread::ChangeAdressesThumb(std::string & buf, const char * http_pref
|
||||||
|
|
||||||
for(size_t i=0 ; i<buf.size() ; ++i)
|
for(size_t i=0 ; i<buf.size() ; ++i)
|
||||||
{
|
{
|
||||||
if( PT::IsSubStringp(look_for_url.c_str(), &buf[i]) )
|
if( PT::is_substr(look_for_url.c_str(), &buf[i]) )
|
||||||
{
|
{
|
||||||
i += look_for_url.size() - 1; // without skipping the last slash
|
i += look_for_url.size() - 1; // without skipping the last slash
|
||||||
|
|
||||||
|
|
|
@ -583,13 +583,13 @@ PostFileTab::iterator i2;
|
||||||
{
|
{
|
||||||
// !! CHECKME why ticket_form_prefix is in the global config?
|
// !! CHECKME why ticket_form_prefix is in the global config?
|
||||||
// (this is a plugin variable)
|
// (this is a plugin variable)
|
||||||
if( PT::IsSubString(config->ticket_form_prefix, i->first) )
|
if( PT::is_substr(config->ticket_form_prefix, i->first) )
|
||||||
{
|
{
|
||||||
long param_id = Tol(i->first.c_str() + config->ticket_form_prefix.size());
|
long param_id = Tol(i->first.c_str() + config->ticket_form_prefix.size());
|
||||||
ReadTicketParam(ticket, param_id, i->second, meta);
|
ReadTicketParam(ticket, param_id, i->second, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( PT::IsSubString(ticket_delete_prefix, i->first) )
|
if( PT::is_substr(ticket_delete_prefix, i->first) )
|
||||||
{
|
{
|
||||||
long file_id = Tol(i->first.c_str() + ticket_delete_prefix.size());
|
long file_id = Tol(i->first.c_str() + ticket_delete_prefix.size());
|
||||||
|
|
||||||
|
@ -602,7 +602,7 @@ PostFileTab::iterator i2;
|
||||||
|
|
||||||
for(i2=cur->request->post_file_tab.begin() ; i2!=cur->request->post_file_tab.end() ; ++i2)
|
for(i2=cur->request->post_file_tab.begin() ; i2!=cur->request->post_file_tab.end() ; ++i2)
|
||||||
{
|
{
|
||||||
if( PT::IsSubString(config->ticket_form_prefix, i2->first) )
|
if( PT::is_substr(config->ticket_form_prefix, i2->first) )
|
||||||
ReadTicketParam(Tol(i2->first.c_str() + config->ticket_form_prefix.size()), i2->second, meta);
|
ReadTicketParam(Tol(i2->first.c_str() + config->ticket_form_prefix.size()), i2->second, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -192,7 +192,7 @@ void dir_has_parents(Info & i)
|
||||||
dir_parents_str += '/';
|
dir_parents_str += '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
i.res = PT::IsSubString(i.par, dir_parents_str);
|
i.res = PT::is_substr(i.par, dir_parents_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2008-2018, Tomasz Sowa
|
* Copyright (c) 2008-2021, Tomasz Sowa
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -163,8 +163,8 @@ void doc_css_tab_file_is_global(Info & i)
|
||||||
// !! z konfiga wziasc przedrostki
|
// !! z konfiga wziasc przedrostki
|
||||||
|
|
||||||
if( doc_css_index < cur->session->last_css.size() )
|
if( doc_css_index < cur->session->last_css.size() )
|
||||||
i.res = PT::IsSubString(L"http://", cur->session->last_css[doc_css_index].c_str()) ||
|
i.res = PT::is_substr(L"http://", cur->session->last_css[doc_css_index].c_str()) ||
|
||||||
PT::IsSubString(L"https://", cur->session->last_css[doc_css_index].c_str());
|
PT::is_substr(L"https://", cur->session->last_css[doc_css_index].c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2008-2018, Tomasz Sowa
|
* Copyright (c) 2008-2021, Tomasz Sowa
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -122,8 +122,8 @@ void mount_css_tab_file_is_global(Info & i)
|
||||||
int parcss = system->mounts.MountParCss();
|
int parcss = system->mounts.MountParCss();
|
||||||
|
|
||||||
if( mount_css_index < cur->mount->param[parcss].arg.size() )
|
if( mount_css_index < cur->mount->param[parcss].arg.size() )
|
||||||
i.res = PT::IsSubString(L"http://", cur->mount->param[parcss].arg[mount_css_index].c_str()) ||
|
i.res = PT::is_substr(L"http://", cur->mount->param[parcss].arg[mount_css_index].c_str()) ||
|
||||||
PT::IsSubString(L"https://", cur->mount->param[parcss].arg[mount_css_index].c_str());
|
PT::is_substr(L"https://", cur->mount->param[parcss].arg[mount_css_index].c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue