mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-10-31 19:36:16 +00:00
factored generate_random_path from yendor out
This commit is contained in:
parent
f567f0012b
commit
d7a7447699
167
geometry2.cpp
167
geometry2.cpp
@ -808,5 +808,172 @@ int brm_hook = addHook(hooks_clearmemory, 0, []() {
|
|||||||
brm_structure.clear();
|
brm_structure.clear();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
EX bool exhaustive_distance_appropriate() {
|
||||||
|
if(euclid && (kite::in() || arcm::in() || arb::in() || quotient)) return true;
|
||||||
|
#if MAXMDIM >= 4
|
||||||
|
if(nil && quotient) return true;
|
||||||
|
#endif
|
||||||
|
#if CAP_SOLV
|
||||||
|
if(asonov::in() && asonov::period_xy && asonov::period_xy <= 256) return true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(bounded) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HDR
|
||||||
|
struct pathgen {
|
||||||
|
cellwalker start;
|
||||||
|
vector<cell*> path;
|
||||||
|
bignum full_id_0;
|
||||||
|
int last_id;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EX pathgen generate_random_path_randomdir(cellwalker start, int length, bool for_yendor) {
|
||||||
|
start.spin = hrand(start.at->type);
|
||||||
|
return generate_random_path(start, length, for_yendor);
|
||||||
|
}
|
||||||
|
|
||||||
|
EX pathgen generate_random_path(cellwalker start, int length, bool for_yendor) {
|
||||||
|
pathgen p;
|
||||||
|
p.start = start;
|
||||||
|
p.path.resize(length+1);
|
||||||
|
p.path[0] = start.at;
|
||||||
|
p.last_id = 0;
|
||||||
|
|
||||||
|
int turns = 0;
|
||||||
|
|
||||||
|
if(exhaustive_distance_appropriate()) {
|
||||||
|
permanent_long_distances(start.at);
|
||||||
|
int dist = max_saved_distance(start.at);
|
||||||
|
dist = min(dist, length);
|
||||||
|
auto at = random_in_distance(start.at, dist);
|
||||||
|
permanent_long_distances(at);
|
||||||
|
for(int a=length-1; a>=0; a--) {
|
||||||
|
p.path[a+1] = at;
|
||||||
|
vector<cell*> prev;
|
||||||
|
forCellCM(c2, at) if(celldistance(start.at, c2) == a) prev.push_back(c2);
|
||||||
|
if(isize(prev)) at = prev[hrand(isize(prev))];
|
||||||
|
}
|
||||||
|
p.path[0] = start.at;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(hybri) {
|
||||||
|
/* I am lazy */
|
||||||
|
for(int i=1; i<=length; i++) p.path[i] = p.path[i-1]->cmove(p.path[i-1]->type-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
int t = -1;
|
||||||
|
bignum full_id;
|
||||||
|
bool onlychild = true;
|
||||||
|
|
||||||
|
cellwalker ycw = start;
|
||||||
|
ycw--; if(S3 == 3) ycw--;
|
||||||
|
if(for_yendor) setdist(p.path[0], 7, NULL);
|
||||||
|
|
||||||
|
for(int i=0; i<length; i++) {
|
||||||
|
|
||||||
|
if(for_yendor && yendor::control(p, i, ycw)) { }
|
||||||
|
|
||||||
|
else if(bt::in()) {
|
||||||
|
// make it challenging
|
||||||
|
vector<int> ds;
|
||||||
|
for(int d=0; d<ycw.at->type; d++) {
|
||||||
|
bool increase;
|
||||||
|
if(sol)
|
||||||
|
increase = i < YDIST / 4 || i > 3 * YDIST / 4;
|
||||||
|
else
|
||||||
|
increase = i < YDIST/2;
|
||||||
|
if(increase) {
|
||||||
|
if(celldistAlt((ycw+d).cpeek()) < celldistAlt(ycw.at))
|
||||||
|
ds.push_back(d);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(celldistAlt((ycw+d).cpeek()) > celldistAlt(ycw.at) && (ycw+d).cpeek() != p.path[i-1])
|
||||||
|
ds.push_back(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(isize(ds)) ycw += ds[hrand(isize(ds))];
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(trees_known()) {
|
||||||
|
if(i == 0) {
|
||||||
|
t = type_in(expansion, start.at, [start] (cell *c) { return celldistance(start.at, c); });
|
||||||
|
bignum b = expansion.get_descendants(length, t);
|
||||||
|
p.full_id_0 = full_id = hrand(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG_YENDORGEN
|
||||||
|
printf("#%3d t%d %s / %s\n", i, t, full_id.get_str(100).c_str(), expansion.get_descendants(length-i, t).get_str(100).c_str());
|
||||||
|
for(int tch: expansion.children[t]) {
|
||||||
|
printf(" t%d %s\n", tch, expansion.get_descendants(length-i-1, t).get_str(100).c_str());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(i == 1)
|
||||||
|
onlychild = true;
|
||||||
|
if(!onlychild) ycw++;
|
||||||
|
if(valence() == 3) ycw++;
|
||||||
|
|
||||||
|
onlychild = false;
|
||||||
|
|
||||||
|
for(int tch: expansion.children[t]) {
|
||||||
|
ycw++;
|
||||||
|
if(i == 1)
|
||||||
|
tch = type_in(expansion, ycw.cpeek(), [start] (cell *c) { return celldistance(start.at, c); });
|
||||||
|
auto& sub_id = expansion.get_descendants(length-1-i, tch);
|
||||||
|
if(full_id < sub_id) { t = tch; break; }
|
||||||
|
|
||||||
|
full_id.addmul(sub_id, -1);
|
||||||
|
onlychild = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(WDIM == 3) {
|
||||||
|
int d = celldistance(p.path[0], ycw.at);
|
||||||
|
vector<cell*> next;
|
||||||
|
forCellCM(c, ycw.at) if(celldistance(p.path[0], c) > d) next.push_back(c);
|
||||||
|
if(!isize(next)) {
|
||||||
|
printf("error: no more cells");
|
||||||
|
ycw.at = ycw.at->move(hrand(ycw.at->type));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ycw.at = next[hrand(isize(next))];
|
||||||
|
}
|
||||||
|
p.path[i+1] = ycw.at;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
// stupid
|
||||||
|
ycw += rev;
|
||||||
|
// well, make it a bit more clever on bitruncated a4 grids
|
||||||
|
if(a4 && BITRUNCATED && S7 <= 5) {
|
||||||
|
if(ycw.at->type == 8 && ycw.cpeek()->type != 8)
|
||||||
|
ycw++;
|
||||||
|
if(hrand(100) < 10) {
|
||||||
|
if(euclid ? (turns&1) : (hrand(100) < 50))
|
||||||
|
ycw+=2;
|
||||||
|
else
|
||||||
|
ycw-=2;
|
||||||
|
turns++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(for_yendor) while(p.last_id < i && (p.path[p.last_id]->land == laMirror || inmirror(p.path[p.last_id]))) {
|
||||||
|
p.last_id++;
|
||||||
|
setdist(p.path[p.last_id], 7, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(for_yendor && inmirror(ycw.at)) ycw = mirror::reflect(ycw);
|
||||||
|
ycw += wstep;
|
||||||
|
p.path[i+1] = ycw.at;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1818,7 +1818,7 @@ EX namespace patterns {
|
|||||||
}
|
}
|
||||||
case 'P': {
|
case 'P': {
|
||||||
cell *s = currentmap->gamestart()->move(0);
|
cell *s = currentmap->gamestart()->move(0);
|
||||||
if(yendor::exhaustive_distance_appropriate() && !keep_distances_from.count(s))
|
if(exhaustive_distance_appropriate() && !keep_distances_from.count(s))
|
||||||
permanent_long_distances(s);
|
permanent_long_distances(s);
|
||||||
int d = celldistance(s, c);
|
int d = celldistance(s, c);
|
||||||
color_t res = distcolors[d];
|
color_t res = distcolors[d];
|
||||||
|
@ -458,7 +458,7 @@ EX void generate_track() {
|
|||||||
makeEmpty(s);
|
makeEmpty(s);
|
||||||
cview(); // needed for some virtualRebases
|
cview(); // needed for some virtualRebases
|
||||||
|
|
||||||
use_exhaustive_distance = yendor::exhaustive_distance_appropriate();
|
use_exhaustive_distance = exhaustive_distance_appropriate();
|
||||||
|
|
||||||
if(use_exhaustive_distance)
|
if(use_exhaustive_distance)
|
||||||
permanent_long_distances(s);
|
permanent_long_distances(s);
|
||||||
|
197
yendor.cpp
197
yendor.cpp
@ -140,7 +140,7 @@ EX namespace yendor {
|
|||||||
|
|
||||||
EX yendorlevel& clev() { return levels[challenge]; }
|
EX yendorlevel& clev() { return levels[challenge]; }
|
||||||
|
|
||||||
eLand changeland(int i, eLand l) {
|
EX eLand changeland(int i, eLand l) {
|
||||||
if(l == laIvoryTower) return laNone;
|
if(l == laIvoryTower) return laNone;
|
||||||
if((clev().flags & YF_START_ANY) && i < 20 && l != clev().l) return clev().l;
|
if((clev().flags & YF_START_ANY) && i < 20 && l != clev().l) return clev().l;
|
||||||
if((clev().flags & YF_END) && i > 80 && l == clev().l) return laIce;
|
if((clev().flags & YF_END) && i > 80 && l == clev().l) return laIce;
|
||||||
@ -195,77 +195,14 @@ EX namespace yendor {
|
|||||||
return ysUntouched;
|
return ysUntouched;
|
||||||
}
|
}
|
||||||
|
|
||||||
EX bool exhaustive_distance_appropriate() {
|
EX bool control(pathgen& p, int i, cellwalker& ycw) {
|
||||||
if(euclid && (kite::in() || arcm::in() || arb::in() || quotient)) return true;
|
|
||||||
#if MAXMDIM >= 4
|
|
||||||
if(nil && quotient) return true;
|
|
||||||
#endif
|
|
||||||
#if CAP_SOLV
|
|
||||||
if(asonov::in() && asonov::period_xy && asonov::period_xy <= 256) return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(bounded) return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
EX bool check(cell *yendor) {
|
|
||||||
int byi = isize(yi);
|
|
||||||
for(int i=0; i<isize(yi); i++) if(yi[i].path[0] == yendor) byi = i;
|
|
||||||
if(byi < isize(yi) && yi[byi].found) return false;
|
|
||||||
if(byi == isize(yi)) {
|
|
||||||
retry:
|
|
||||||
int creation_attempt = 0;
|
|
||||||
yendorinfo nyi;
|
|
||||||
nyi.path[0] = yendor;
|
|
||||||
nyi.howfar = 0;
|
|
||||||
|
|
||||||
generating = true;
|
|
||||||
|
|
||||||
int turns = 0;
|
|
||||||
|
|
||||||
bignum full_id_0;
|
|
||||||
|
|
||||||
int odir = 0;
|
|
||||||
|
|
||||||
if(exhaustive_distance_appropriate()) {
|
|
||||||
permanent_long_distances(yendor);
|
|
||||||
int dist = max_saved_distance(yendor);
|
|
||||||
dist = min(dist, YDIST-1);
|
|
||||||
auto at = random_in_distance(yendor, dist);
|
|
||||||
permanent_long_distances(at);
|
|
||||||
for(int a=YDIST-2; a>=0; a--) {
|
|
||||||
nyi.path[a+1] = at;
|
|
||||||
vector<cell*> prev;
|
|
||||||
forCellCM(c2, at) if(celldistance(yendor, c2) == a) prev.push_back(c2);
|
|
||||||
if(isize(prev)) at = prev[hrand(isize(prev))];
|
|
||||||
}
|
|
||||||
nyi.path[0] = yendor;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if(hybri) {
|
|
||||||
/* I am lazy */
|
|
||||||
for(int i=1; i<=YDIST-1; i++) nyi.path[i] = nyi.path[i-1]->cmove(nyi.path[i-1]->type-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
int t = -1;
|
|
||||||
bignum full_id;
|
|
||||||
bool onlychild = true;
|
|
||||||
|
|
||||||
cellwalker ycw(yendor, odir = hrand(yendor->type));
|
|
||||||
ycw--; if(S3 == 3) ycw--;
|
|
||||||
setdist(nyi.path[0], 7, NULL);
|
|
||||||
|
|
||||||
int last_id = 0;
|
|
||||||
|
|
||||||
for(int i=0; i<YDIST-1; i++) {
|
|
||||||
|
|
||||||
|
// change lands in the Challenge
|
||||||
if(i > BARLEV-6) {
|
if(i > BARLEV-6) {
|
||||||
last_id = i+7-BARLEV;
|
p.last_id = i+7-BARLEV;
|
||||||
setdist(nyi.path[last_id], 7, nyi.path[i+6-BARLEV]);
|
setdist(p.path[p.last_id], 7, p.path[i+6-BARLEV]);
|
||||||
if(challenge && !euclid && ycw.at->land != laIvoryTower) {
|
if(yendor::challenge && !euclid && ycw.at->land != laIvoryTower) {
|
||||||
eLand ycl = changeland(i, ycw.at->land);
|
eLand ycl = yendor::changeland(i, ycw.at->land);
|
||||||
if(ycl) {
|
if(ycl) {
|
||||||
if(weirdhyperbolic) {
|
if(weirdhyperbolic) {
|
||||||
buildBarrierNowall(ycw.at, ycl);
|
buildBarrierNowall(ycw.at, ycl);
|
||||||
@ -280,8 +217,8 @@ EX namespace yendor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ycw.at->land == laEndorian) {
|
|
||||||
// follow the branch in Yendorian
|
// follow the branch in Yendorian
|
||||||
|
if(ycw.at->land == laEndorian) {
|
||||||
int bestval = -2000;
|
int bestval = -2000;
|
||||||
int best = 0, qbest = 0;
|
int best = 0, qbest = 0;
|
||||||
for(int d=0; d<ycw.at->type; d++) {
|
for(int d=0; d<ycw.at->type; d++) {
|
||||||
@ -293,103 +230,25 @@ EX namespace yendor {
|
|||||||
if(val == bestval) if(hrand(++qbest) == 0) best = d;
|
if(val == bestval) if(hrand(++qbest) == 0) best = d;
|
||||||
}
|
}
|
||||||
ycw += best;
|
ycw += best;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(bt::in()) {
|
EX bool check(cell *yendor) {
|
||||||
// make it challenging
|
int byi = isize(yi);
|
||||||
vector<int> ds;
|
for(int i=0; i<isize(yi); i++) if(yi[i].path[0] == yendor) byi = i;
|
||||||
for(int d=0; d<ycw.at->type; d++) {
|
if(byi < isize(yi) && yi[byi].found) return false;
|
||||||
bool increase;
|
if(byi == isize(yi)) {
|
||||||
if(sol)
|
retry:
|
||||||
increase = i < YDIST / 4 || i > 3 * YDIST / 4;
|
int creation_attempt = 0;
|
||||||
else
|
yendorinfo nyi;
|
||||||
increase = i < YDIST/2;
|
nyi.howfar = 0;
|
||||||
if(increase) {
|
|
||||||
if(celldistAlt((ycw+d).cpeek()) < celldistAlt(ycw.at))
|
|
||||||
ds.push_back(d);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(celldistAlt((ycw+d).cpeek()) > celldistAlt(ycw.at) && (ycw+d).cpeek() != nyi.path[i-1])
|
|
||||||
ds.push_back(d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(isize(ds)) ycw += ds[hrand(isize(ds))];
|
|
||||||
}
|
|
||||||
|
|
||||||
else if(trees_known()) {
|
generating = true;
|
||||||
if(i == 0) {
|
|
||||||
t = type_in(expansion, yendor, [yendor] (cell *c) { return celldistance(yendor, c); });
|
|
||||||
bignum b = expansion.get_descendants(YDIST-1, t);
|
|
||||||
full_id_0 = full_id = hrand(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG_YENDORGEN
|
auto p = generate_random_path_randomdir(yendor, YDIST-1, true);
|
||||||
printf("#%3d t%d %s / %s\n", i, t, full_id.get_str(100).c_str(), expansion.get_descendants(YDIST-1-i, t).get_str(100).c_str());
|
for(int i=0; i<YDIST; i++) nyi.path[i] = p.path[i];
|
||||||
for(int tch: expansion.children[t]) {
|
|
||||||
printf(" t%d %s\n", tch, expansion.get_descendants(YDIST-2-i, t).get_str(100).c_str());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(i == 1)
|
|
||||||
onlychild = true;
|
|
||||||
if(!onlychild) ycw++;
|
|
||||||
if(valence() == 3) ycw++;
|
|
||||||
|
|
||||||
onlychild = false;
|
|
||||||
|
|
||||||
for(int tch: expansion.children[t]) {
|
|
||||||
ycw++;
|
|
||||||
if(i == 1)
|
|
||||||
tch = type_in(expansion, ycw.cpeek(), [yendor] (cell *c) { return celldistance(yendor, c); });
|
|
||||||
auto& sub_id = expansion.get_descendants(YDIST-i-2, tch);
|
|
||||||
if(full_id < sub_id) { t = tch; break; }
|
|
||||||
|
|
||||||
full_id.addmul(sub_id, -1);
|
|
||||||
onlychild = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if(WDIM == 3) {
|
|
||||||
int d = celldistance(nyi.path[0], ycw.at);
|
|
||||||
vector<cell*> next;
|
|
||||||
forCellCM(c, ycw.at) if(celldistance(nyi.path[0], c) > d) next.push_back(c);
|
|
||||||
if(!isize(next)) {
|
|
||||||
printf("error: no more cells");
|
|
||||||
ycw.at = ycw.at->move(hrand(ycw.at->type));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ycw.at = next[hrand(isize(next))];
|
|
||||||
}
|
|
||||||
nyi.path[i+1] = ycw.at;
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
// stupid
|
|
||||||
ycw += rev;
|
|
||||||
// well, make it a bit more clever on bitruncated a4 grids
|
|
||||||
if(a4 && BITRUNCATED && S7 <= 5) {
|
|
||||||
if(ycw.at->type == 8 && ycw.cpeek()->type != 8)
|
|
||||||
ycw++;
|
|
||||||
if(hrand(100) < 10) {
|
|
||||||
if(euclid ? (turns&1) : (hrand(100) < 50))
|
|
||||||
ycw+=2;
|
|
||||||
else
|
|
||||||
ycw-=2;
|
|
||||||
turns++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while(last_id < i && (nyi.path[last_id]->land == laMirror || inmirror(nyi.path[last_id]))) {
|
|
||||||
last_id++;
|
|
||||||
setdist(nyi.path[last_id], 7, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(inmirror(ycw.at)) ycw = mirror::reflect(ycw);
|
|
||||||
ycw += wstep;
|
|
||||||
nyi.path[i+1] = ycw.at;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nyi.found = false;
|
nyi.found = false;
|
||||||
nyi.foundOrb = false;
|
nyi.foundOrb = false;
|
||||||
@ -405,7 +264,7 @@ EX namespace yendor {
|
|||||||
setdist(nyi.path[YDIST-1], 7, nyi.path[YDIST-2]);
|
setdist(nyi.path[YDIST-1], 7, nyi.path[YDIST-2]);
|
||||||
cell *key = nyi.path[YDIST-1];
|
cell *key = nyi.path[YDIST-1];
|
||||||
|
|
||||||
generating = false;
|
yendor::generating = false;
|
||||||
|
|
||||||
for(int b=10; b>=5; b--) setdist(key, b, nyi.path[YDIST-2]);
|
for(int b=10; b>=5; b--) setdist(key, b, nyi.path[YDIST-2]);
|
||||||
|
|
||||||
@ -464,10 +323,10 @@ EX namespace yendor {
|
|||||||
maxage *= 10;
|
maxage *= 10;
|
||||||
|
|
||||||
nyi.age = maxage - hrand(maxage/2);
|
nyi.age = maxage - hrand(maxage/2);
|
||||||
bignum full_id = full_id_0 - nyi.age;
|
bignum full_id = p.full_id_0 - nyi.age;
|
||||||
bool onlychild = true;
|
bool onlychild = true;
|
||||||
|
|
||||||
cellwalker ycw(yendor, odir);
|
cellwalker ycw = p.start;
|
||||||
ycw--; if(S3 == 3) ycw--;
|
ycw--; if(S3 == 3) ycw--;
|
||||||
|
|
||||||
for(int i=0; i<YDIST-1; i++) {
|
for(int i=0; i<YDIST-1; i++) {
|
||||||
@ -484,7 +343,7 @@ EX namespace yendor {
|
|||||||
tch = type_in(expansion, ycw.cpeek(), [yendor] (cell *c) { return celldistance(yendor, c); });
|
tch = type_in(expansion, ycw.cpeek(), [yendor] (cell *c) { return celldistance(yendor, c); });
|
||||||
auto& sub_id = expansion.get_descendants(YDIST-i-2, tch);
|
auto& sub_id = expansion.get_descendants(YDIST-i-2, tch);
|
||||||
if(full_id < sub_id) {
|
if(full_id < sub_id) {
|
||||||
if(!split_found && !(full_id_0 < sub_id)) {
|
if(!split_found && !(p.full_id_0 < sub_id)) {
|
||||||
// ycw.at->item = itRuby;
|
// ycw.at->item = itRuby;
|
||||||
split_found = true;
|
split_found = true;
|
||||||
setdist(ycw.at, 6, NULL);
|
setdist(ycw.at, 6, NULL);
|
||||||
@ -501,7 +360,7 @@ EX namespace yendor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
full_id.addmul(sub_id, -1);
|
full_id.addmul(sub_id, -1);
|
||||||
if(!split_found) full_id_0.addmul(sub_id, -1);
|
if(!split_found) p.full_id_0.addmul(sub_id, -1);
|
||||||
onlychild = true;
|
onlychild = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user