mirror of https://github.com/CGAL/cgal
pre global replace
This commit is contained in:
parent
fd97c81e8a
commit
c1fd50a09b
|
|
@ -313,10 +313,10 @@ CGAL_expensive_assertion_code(if ( storage_[i].second == storage_.back().second)
|
|||
Data d;
|
||||
iss >> d;
|
||||
if (!iss) {
|
||||
CGAL_KINETIC_ERROR("ERROR reading object from line " << buf);
|
||||
CGAL_ERROR("ERROR reading object from line " << buf);
|
||||
++internal::io_errors__;
|
||||
} else {
|
||||
//CGAL_KINETIC_LOG(LOG_LOTS, "Read " << d << std::endl);
|
||||
//CGAL_LOG(LOG_LOTS, "Read " << d << std::endl);
|
||||
insert(d);
|
||||
}
|
||||
} while (true);
|
||||
|
|
|
|||
|
|
@ -747,7 +747,7 @@ void Default_simulator<S, PQ>::set_direction_of_time(CGAL::Sign dir)
|
|||
is_forward_= !is_forward_;
|
||||
//end_time_=-end_time_;
|
||||
//last_event_time_= -std::numeric_limits<Time>::infinity();
|
||||
CGAL_KINETIC_LOG(LOG_SOME, "Current time is " << cur_time_ << " and was " << oct
|
||||
CGAL_LOG(Log::SOME, "Current time is " << cur_time_ << " and was " << oct
|
||||
<< ", end_time() is " << end_time() << std::endl);
|
||||
for (typename std::vector<Listener*>::iterator it= kdss_.begin(); it != kdss_.end(); ++it) {
|
||||
(*it)->new_notification(Listener::DIRECTION_OF_TIME);
|
||||
|
|
@ -755,7 +755,7 @@ void Default_simulator<S, PQ>::set_direction_of_time(CGAL::Sign dir)
|
|||
}
|
||||
}
|
||||
else {
|
||||
CGAL_KINETIC_LOG(LOG_SOME, dir << " " << end_time() << " " << cur_time_ << std::endl);
|
||||
CGAL_LOG(Log::SOME, dir << " " << end_time() << " " << cur_time_ << std::endl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -765,7 +765,7 @@ void Default_simulator<S, PQ>::audit_all_kdss()
|
|||
{
|
||||
#ifdef CGAL_KINETIC_ENABLE_AUDITING
|
||||
cur_time_= Time(audit_time_);
|
||||
CGAL_KINETIC_LOG(LOG_SOME, "Auditing KDSs at time " << audit_time() << std::endl);
|
||||
CGAL_LOG(Log::SOME, "Auditing KDSs at time " << audit_time() << std::endl);
|
||||
for (typename std::vector<Listener*>::iterator it= kdss_.begin(); it != kdss_.end(); ++it) {
|
||||
//CGAL_exactness_postcondition_code((*it)->new_notification(Listener::HAS_VERIFICATION_TIME));
|
||||
CGAL_postcondition_code((*it)->new_notification(Listener::HAS_AUDIT_TIME));
|
||||
|
|
@ -775,12 +775,8 @@ void Default_simulator<S, PQ>::audit_all_kdss()
|
|||
}
|
||||
|
||||
|
||||
template <class S, class PQ>
|
||||
std::ostream &operator<<(std::ostream &out, const Default_simulator<S, PQ> &s)
|
||||
{
|
||||
s.write(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
CGAL_OUTPUT2(Default_simulator);
|
||||
|
||||
|
||||
CGAL_KINETIC_END_NAMESPACE;
|
||||
|
|
|
|||
|
|
@ -41,30 +41,30 @@ class HDRS{
|
|||
*/
|
||||
HDRS(const Function &uf, const Root& lb,
|
||||
const Root& ub, const Traits_t& k): solver_(k.root_stack_object(uf, lb, ub)) {
|
||||
CGAL_KINETIC_LOG(LOG_LOTS, "Function= " << uf << std::endl);
|
||||
CGAL_LOG(Log::LOTS, "Function= " << uf << std::endl);
|
||||
CGAL_expensive_precondition(solver_.empty() || solver_.top() >= lb);
|
||||
if (uf.degree() == -1) {
|
||||
CGAL_KINETIC_LOG(LOG_SOME, "Zero function found at time " << lb << std::endl);
|
||||
CGAL_LOG(Log::SOME, "Zero function found at time " << lb << std::endl);
|
||||
++ internal::zero_certificates__;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
if (!SLOPPY && k.sign_at_object()(uf, lb) == CGAL::NEGATIVE) {
|
||||
CGAL_KINETIC_ERROR( "Invalid certificate constructed for function " << uf << " between " << lb
|
||||
CGAL_ERROR( "Invalid certificate constructed for function " << uf << " between " << lb
|
||||
<< " and " << ub << " will fail immediately." << std::endl);
|
||||
CGAL_exactness_precondition(k.sign_at_object()(uf, lb) != CGAL::NEGATIVE);
|
||||
}
|
||||
#endif
|
||||
if (solver_.empty()) {
|
||||
CGAL_KINETIC_LOG(LOG_LOTS, "No failure" << std::endl);
|
||||
CGAL_LOG(Log::LOTS, "No failure" << std::endl);
|
||||
//sn = k.sign_between_roots_object()(uf, lb, ub);
|
||||
} else if (solver_.top() == lb) {
|
||||
CGAL_KINETIC_LOG(LOG_LOTS, "Degeneracy at " << solver_.top() << std::endl);
|
||||
CGAL_LOG(Log::LOTS, "Degeneracy at " << solver_.top() << std::endl);
|
||||
CGAL::Sign sn = k.sign_after_object()(uf, lb);
|
||||
if (sn == CGAL::NEGATIVE) {
|
||||
++internal::function_degeneracies__;
|
||||
CGAL_KINETIC_LOG(LOG_LOTS, "Extra root at lower bound of " << lb << std::endl);
|
||||
CGAL_LOG(Log::LOTS, "Extra root at lower bound of " << lb << std::endl);
|
||||
} else {
|
||||
CGAL_KINETIC_LOG(LOG_LOTS, "Popping extra root at lower bound of " << lb << std::endl);
|
||||
CGAL_LOG(Log::LOTS, "Popping extra root at lower bound of " << lb << std::endl);
|
||||
solver_.pop();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,15 +84,8 @@ Log_level;
|
|||
|
||||
CGAL_KINETIC_END_NAMESPACE
|
||||
|
||||
#include <CGAL/Kinetic/internal/Log.h>
|
||||
#include <CGAL/Tools/Log.h>
|
||||
|
||||
#define CGAL_KINETIC_LOG(level, expr) if (CGAL::Kinetic::internal::Logs::get().is_output(level))\
|
||||
{ CGAL::Kinetic::internal::Logs::get().stream(level) << expr;};
|
||||
#define CGAL_KINETIC_LOG_WRITE(level, expr) if (CGAL::Kinetic::internal::Logs::get().is_output(level))\
|
||||
{std::ostream &LOG_STREAM= CGAL::Kinetic::internal::Logs::get().stream(level); expr;}
|
||||
#define CGAL_KINETIC_ERROR(expr) std::cerr << expr << std::endl;
|
||||
#define CGAL_KINETIC_ERROR_WRITE(expr) {std::ostream &LOG_STREAM= std::cerr; expr; std::cerr << std::endl;}
|
||||
#define CGAL_KINETIC_SET_LOG_LEVEL(level) CGAL::Kinetic::internal::Logs::get().set_level(level);
|
||||
|
||||
#include <CGAL/Tools/utility_macros.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -20,103 +20,105 @@
|
|||
|
||||
#ifndef CGAL_KINETIC_LOG_H_
|
||||
#define CGAL_KINETIC_LOG_H_
|
||||
#include <CGAL/Kinetic/basic.h>
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Tools/utility_macros.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
|
||||
CGAL_KINETIC_BEGIN_INTERNAL_NAMESPACE
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
class Logs
|
||||
class Log
|
||||
{
|
||||
public:
|
||||
typedef enum Level {NONE=0, SOME=2, LOTS=3};
|
||||
|
||||
typedef enum Target {COUT, FILE, DEVNULL};
|
||||
private:
|
||||
struct State {
|
||||
Target target_;
|
||||
Level level_;
|
||||
std::ofstream fstream_;
|
||||
std::ofstream null_;
|
||||
std::ofstream maple_;
|
||||
bool maple_is_open_;
|
||||
bool output_maple_;
|
||||
State(){
|
||||
level_= NONE;
|
||||
target_= COUT;
|
||||
null_.open("/dev/null");
|
||||
//maple_.open("maple.log");
|
||||
maple_is_open_=false;
|
||||
output_maple_=true;
|
||||
}
|
||||
};
|
||||
static State state_;
|
||||
public:
|
||||
// The different types of logs supported
|
||||
/* MAPLE is a log which should be able to be fed directly in to
|
||||
maple and preferably will produce obviously good or bad outwhen
|
||||
when evaluated.
|
||||
*/
|
||||
typedef CGAL::Kinetic::Log_level Level;
|
||||
typedef enum Target {COUT, FILE, DEVNULL}
|
||||
Target;
|
||||
|
||||
Level level() const
|
||||
{
|
||||
return level_;
|
||||
}
|
||||
static Level level() {return state_.level_;}
|
||||
static void set_level(Level &l) {state_.level_=l;}
|
||||
|
||||
void set_level(Level l) {
|
||||
level_= l;
|
||||
}
|
||||
|
||||
std::ostream &stream(Level l) {
|
||||
static std::ostream &stream(Level l) {
|
||||
if (is_output(l)) {
|
||||
if (target_== COUT) {
|
||||
if (state_.target_== COUT) {
|
||||
return std::cout;
|
||||
}
|
||||
else {
|
||||
return fstream_;
|
||||
return state_.fstream_;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return null_;
|
||||
return state_.null_;
|
||||
}
|
||||
}
|
||||
bool is_output(Level l) {
|
||||
|
||||
static bool is_output(Level l) {
|
||||
return l <= level();
|
||||
}
|
||||
Target target() const
|
||||
{
|
||||
return target_;
|
||||
}
|
||||
void set_target(Target t) {
|
||||
target_=t;
|
||||
}
|
||||
static Target target() {return state_.target_;}
|
||||
static CGAL_SET(Target, target, state_.target_=k);
|
||||
static CGAL_SET(std::string, filename, state_.fstream_.open(k.c_str()));
|
||||
|
||||
void set_filename(const char *name) {
|
||||
fstream_.open(name);
|
||||
}
|
||||
|
||||
static Logs& get() ;
|
||||
|
||||
bool output_maple() const
|
||||
{
|
||||
return output_maple_;
|
||||
}
|
||||
void set_output_maple(bool b) {
|
||||
output_maple_=b;
|
||||
static bool is_output_maple(){return state_.output_maple_;}
|
||||
|
||||
static void set_output_maple(bool b) {
|
||||
state_.output_maple_=b;
|
||||
}
|
||||
std::ofstream &maple_stream() {
|
||||
if (!maple_is_open_) {
|
||||
maple_is_open_=true;
|
||||
maple_.open("maple.log");
|
||||
if (!state_.maple_is_open_) {
|
||||
state_.maple_is_open_=true;
|
||||
state_.maple_.open("maple.log");
|
||||
}
|
||||
return maple_;
|
||||
return state_.maple_;
|
||||
}
|
||||
Logs() {
|
||||
level_= LOG_NONE;
|
||||
target_= COUT;
|
||||
null_.open("/dev/null");
|
||||
//maple_.open("maple.log");
|
||||
maple_is_open_=false;
|
||||
output_maple_=true;
|
||||
private:
|
||||
Log() {
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
Target target_;
|
||||
Level level_;
|
||||
std::ofstream fstream_;
|
||||
std::ofstream null_;
|
||||
std::ofstream maple_;
|
||||
bool maple_is_open_;
|
||||
bool output_maple_;
|
||||
};
|
||||
|
||||
extern Logs kds_logs;
|
||||
|
||||
inline Logs& Logs::get() {
|
||||
return kds_logs;
|
||||
}
|
||||
|
||||
CGAL_KINETIC_END_INTERNAL_NAMESPACE
|
||||
#ifndef CGAL_DISABLE_LOGGING
|
||||
#define CGAL_LOG(level, expr) if (CGAL::Log::is_output(level))\
|
||||
{ CGAL::Log::stream(level) << expr << std::flush;};
|
||||
#define CGAL_LOG_WRITE(level, expr) if (CGAL::Log::is_output(level))\
|
||||
{std::ostream &LOG_STREAM= CGAL::Log::stream(level); expr;}
|
||||
#define CGAL_ERROR(expr) std::cerr << expr << std::endl;
|
||||
#define CGAL_ERROR_WRITE(expr) {std::ostream &LOG_STREAM= std::cerr; expr; std::cerr << std::endl;}
|
||||
#define CGAL_SET_LOG_LEVEL(level) CGAL::Logs::set_level(level);
|
||||
#else
|
||||
#define CGAL_LOG(l,e)
|
||||
#define CGAL_LOG_WRITE(l,e)
|
||||
#define CGAL_ERROR(e)
|
||||
#define CGAL_ERROR_WRITE(e)
|
||||
#define CGAL_SET_LOG_LEVEL(l)
|
||||
#endif
|
||||
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#define CGAL_ACCESSOR(type, name, expr) const type &name() const{expr;}
|
||||
#define CGAL_ACCESSORNR(type, name, expr) const type &name() const{expr;}
|
||||
|
||||
#define CGAL_IS(name, expor) bool is_##name() const {expr;}
|
||||
#define CGAL_IS(name, expr) bool is_##name() const {expr;}
|
||||
|
||||
#define CGAL_SET(type, name, expr) void set_##name(const type &k) {expr;}
|
||||
|
||||
|
|
@ -24,6 +24,18 @@
|
|||
return t.write(out); \
|
||||
}
|
||||
|
||||
#define CGAL_OUTPUT1(type) \
|
||||
template <class A> \
|
||||
inline std::ostream& operator<<(std::ostream&out, const type<A> &t){ \
|
||||
return t.write(out); \
|
||||
}
|
||||
|
||||
#define CGAL_OUTPUT2(type) \
|
||||
template <class A, class B> \
|
||||
inline std::ostream& operator<<(std::ostream&out, const type<A,B> &t){ \
|
||||
return t.write(out); \
|
||||
}
|
||||
|
||||
#define CGAL_ITERATOR(uc_name, lc_name, it_type, bexpr, eexpr) \
|
||||
typedef it_type uc_name##_iterator; \
|
||||
uc_name##_iterator lc_name##s_begin() {bexpr;} \
|
||||
|
|
@ -55,57 +67,46 @@
|
|||
#define CGAL_IFNONEQUAL(a,b,cmp) if (a cmp b) return true; \
|
||||
else if (b cmp a) return false;
|
||||
|
||||
#include CGAL_COMPARISONS1(ucname, field) bool operator==(const ucname &o) const {\
|
||||
return (field== o.field);\
|
||||
}\
|
||||
bool operator!=(const ucname &o) const { \
|
||||
return (field!= o.field);\
|
||||
}\
|
||||
bool operator<(const ucname &o) const { \
|
||||
return (field< o.field); \
|
||||
}\
|
||||
bool operator>(const ucname &o) const { \
|
||||
return (field> o.field);\
|
||||
}\
|
||||
bool operator>=(const ucname &o) const { \
|
||||
return (field>= o.field);\
|
||||
}\
|
||||
bool operator<=(const ucname &o) const { \
|
||||
return (field<= o.field);\
|
||||
#define CGAL_COMPARISONS1(ucname, field) bool operator==(const ucname &o) const { \
|
||||
return (field== o.field); \
|
||||
} \
|
||||
bool operator!=(const ucname &o) const { \
|
||||
return (field!= o.field); \
|
||||
} \
|
||||
bool operator<(const ucname &o) const { \
|
||||
return (field< o.field); \
|
||||
} \
|
||||
bool operator>(const ucname &o) const { \
|
||||
return (field> o.field); \
|
||||
} \
|
||||
bool operator>=(const ucname &o) const { \
|
||||
return (field>= o.field); \
|
||||
} \
|
||||
bool operator<=(const ucname &o) const { \
|
||||
return (field<= o.field); \
|
||||
}
|
||||
|
||||
#include CGAL_COMPARISONS2(ucname, a, b) bool operator==(const ucname &o) const { \
|
||||
return (a== o.a && b== o.b);\
|
||||
}\
|
||||
bool operator!=(const ucname &o) const { \
|
||||
return (a!= o.a || b != o.b);\
|
||||
}\
|
||||
bool operator<(const ucname &o) const { \
|
||||
if (a< o.a ) return true; \
|
||||
else if (a > o.a) return false; \
|
||||
else return b < o.b; \
|
||||
} \
|
||||
bool operator>(const ucname &o) const { \
|
||||
if (a> o.a ) return true; \
|
||||
else if (a < o.a) return false; \
|
||||
else return b > o.b; \
|
||||
} \
|
||||
bool operator>=(const ucname &o) const { \
|
||||
return !operator<(o); \
|
||||
} \
|
||||
bool operator<=(const ucname &o) const { \
|
||||
return !operator>(o); \
|
||||
#define CGAL_COMPARISONS2(ucname, a, b) bool operator==(const ucname &o) const { \
|
||||
return (a== o.a && b== o.b); \
|
||||
} \
|
||||
bool operator!=(const ucname &o) const { \
|
||||
return (a!= o.a || b != o.b); \
|
||||
} \
|
||||
bool operator<(const ucname &o) const { \
|
||||
if (a< o.a ) return true; \
|
||||
else if (a > o.a) return false; \
|
||||
else return b < o.b; \
|
||||
} \
|
||||
bool operator>(const ucname &o) const { \
|
||||
if (a> o.a ) return true; \
|
||||
else if (a < o.a) return false; \
|
||||
else return b > o.b; \
|
||||
} \
|
||||
bool operator>=(const ucname &o) const { \
|
||||
return !operator<(o); \
|
||||
} \
|
||||
bool operator<=(const ucname &o) const { \
|
||||
return !operator>(o); \
|
||||
}
|
||||
|
||||
#include <CGAL/Kinetic/internal/Log.h>
|
||||
|
||||
#define CGAL_LOG(level, expr) if (CGAL::Kinetic::internal::Logs::get().is_output(level))\
|
||||
{ CGAL::Kinetic::internal::Logs::get().stream(level) << expr;};
|
||||
#define CGAL_LOG_WRITE(level, expr) if (CGAL::Kinetic::internal::Logs::get().is_output(level))\
|
||||
{std::ostream &LOG_STREAM= CGAL::Kinetic::internal::Logs::get().stream(level); expr;}
|
||||
#define CGAL_ERROR(expr) std::cerr << expr << std::endl;
|
||||
#define CGAL_ERROR_WRITE(expr) {std::ostream &LOG_STREAM= std::cerr; expr; std::cerr << std::endl;}
|
||||
#define CGAL_SET_LOG_LEVEL(level) CGAL::Kinetic::internal::Logs::get().set_level(level);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -19,14 +19,14 @@
|
|||
// Author(s) : Daniel Russel <drussel@alumni.princeton.edu>
|
||||
|
||||
|
||||
#include <CGAL/Kinetic/internal/Log.h>
|
||||
#include <CGAL/Tools/Log.h>
|
||||
#include <CGAL/Kinetic/internal/debug_counters.h>
|
||||
#include <iostream>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
Log::State Log::state_;
|
||||
CGAL_END_NAMESPACE
|
||||
CGAL_KINETIC_BEGIN_INTERNAL_NAMESPACE
|
||||
|
||||
Logs kds_logs;
|
||||
|
||||
unsigned int function_degeneracies__=0;
|
||||
unsigned int zero_certificates__=0;
|
||||
unsigned int io_errors__=0;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
int main(int, char *[])
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
typedef CGAL::Kinetic::Exact_simulation_traits Simulation_traits;
|
||||
|
|
@ -20,26 +20,50 @@ int main(int, char *[])
|
|||
Simulation_traits::Simulator::Handle sp= simtr.simulator_handle();
|
||||
|
||||
KDel kdel(simtr);
|
||||
CGAL_KINETIC_SET_LOG_LEVEL(CGAL::Kinetic::LOG_NONE);
|
||||
std::ifstream in("data/Delaunay_triangulation_3.input");
|
||||
if (!in) {
|
||||
std::cerr << "Error opening input file: " << "data/Delaunay_triangulation_3.input" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
if (argc==1) {
|
||||
CGAL_KINETIC_SET_LOG_LEVEL(CGAL::Kinetic::LOG_NONE);
|
||||
std::ifstream in("data/Delaunay_triangulation_3.input");
|
||||
if (!in) {
|
||||
std::cerr << "Error opening input file: " << "data/Delaunay_triangulation_3.input" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
char buf[1000];
|
||||
int nread=0;
|
||||
while (true ) {
|
||||
in.getline(buf, 1000);
|
||||
if (!in) break;
|
||||
std::istringstream il(buf);
|
||||
Simulation_traits::Kinetic_kernel::Point_3 p;
|
||||
il >> p;
|
||||
//std::cout << p << std::endl;
|
||||
simtr.active_points_3_table_handle()->insert(p);
|
||||
++nread;
|
||||
}
|
||||
kdel.set_has_certificates(true);
|
||||
kdel.audit();
|
||||
|
||||
} else {
|
||||
CGAL_KINETIC_SET_LOG_LEVEL(CGAL::Kinetic::LOG_LOTS);
|
||||
std::ifstream in(argv[1]);
|
||||
if (!in) {
|
||||
std::cerr << "Error opening input file: " << argv[1] << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
char buf[1000];
|
||||
int nread=0;
|
||||
while (true ) {
|
||||
in.getline(buf, 1000);
|
||||
if (!in) break;
|
||||
std::istringstream il(buf);
|
||||
Simulation_traits::Kinetic_kernel::Point_3 p;
|
||||
il >> p;
|
||||
//std::cout << p << std::endl;
|
||||
simtr.active_points_3_table_handle()->insert(p);
|
||||
++nread;
|
||||
}
|
||||
kdel.set_has_certificates(true);
|
||||
kdel.audit();
|
||||
}
|
||||
char buf[1000];
|
||||
int nread=0;
|
||||
while (true ) {
|
||||
in.getline(buf, 1000);
|
||||
if (!in) break;
|
||||
std::istringstream il(buf);
|
||||
Simulation_traits::Kinetic_kernel::Point_3 p;
|
||||
il >> p;
|
||||
//std::cout << p << std::endl;
|
||||
simtr.active_points_3_table_handle()->insert(p);
|
||||
++nread;
|
||||
}
|
||||
kdel.set_has_certificates(true);
|
||||
kdel.audit();
|
||||
|
||||
while (simtr.simulator_handle()->next_event_time()
|
||||
< simtr.simulator_handle()->end_time()) {
|
||||
|
|
@ -78,6 +102,8 @@ int main(int, char *[])
|
|||
|
||||
if (error_count != 0) {
|
||||
std::cerr << "ERROR " << error_count << " errors in " << kdel.visitor().size() << " events.\n";
|
||||
} else {
|
||||
std::cout << "No errors for " << kdel.visitor().size() << " events" << std::endl;
|
||||
}
|
||||
|
||||
//std::cout << "Too late on " << too_late__ << " and filtered " << filtered__ << std::endl;
|
||||
|
|
|
|||
Loading…
Reference in New Issue