Home » U++ Library support » Draw, Display, Images, Bitmaps, Icons » Strange issue with text in Painter
Strange issue with text in Painter [message #50852] |
Wed, 09 January 2019 11:23 ![Go to next message Go to next message](theme/default/images/down.png) |
Tom1
Messages: 1221 Registered: March 2007
|
Senior Contributor |
|
|
Hi,
Here's a strange issue: When I render a map using Painter, sometimes some letter does not render at all at specific scales. Alternatively, as you can see in the attached picture, it may render at false scale:
![index.php?t=getfile&id=5733&private=0](index.php?t=getfile&id=5733&private=0)
When rotating the map slightly, the same text renders correctly:
![index.php?t=getfile&id=5734&private=0](index.php?t=getfile&id=5734&private=0)
...Unless when the rotation is exactly 90, 180 or 270 degrees, which causes similar scaling error.
Another variant is that the letter appears to be completely absent.
BUT: when zooming the map, the letter renders perfectly OK.
There is no difference if Painter is in MT or ST mode.
Finally, this behavior persists for that run of the program only. If I close and restart the program, the same letter will likely render OK all the time, but there may (or may not) be another letter that suffers from the same problem.
I think this is some sort of initialization problem with fonts... but who knows.
Best regards,
Tom
-
Attachment: T1.png
(Size: 203.15KB, Downloaded 678 times)
-
Attachment: T2.png
(Size: 138.87KB, Downloaded 748 times)
|
|
|
Re: Strange issue with text in Painter [message #50854 is a reply to message #50852] |
Wed, 09 January 2019 13:38 ![Go to previous message Go to previous message](theme/default/images/up.png) ![Go to next message Go to next message](theme/default/images/down.png) |
Tom1
Messages: 1221 Registered: March 2007
|
Senior Contributor |
|
|
Hi,
Here's some more. In this picture two of the letters have shrinked in the middle of a word:
![index.php?t=getfile&id=5736&private=0](index.php?t=getfile&id=5736&private=0)
When zooming in, the text gets fixed:
![index.php?t=getfile&id=5735&private=0](index.php?t=getfile&id=5735&private=0)
Instead of a testcase, here's a clip of the code I use for rendering the text with Painter:
Font fnt(font);
fnt.Height((int)floor(height_dp)).Bold(object.bold).Italic(object.italic==1).Underline(object.selected);
Pointf p(project.Transform(object.x,object.y));
double rot=object.rotation+rotation;
rot+=object.no_rotate?-GetViewRotation():0;
painter.Begin();
painter.Translate(p);
if(rot) painter.Rotate(-rot*DEGR2RAD);
switch(object.italic){
case 2:
painter.Transform(Xform2D::Sheer(-0.3));
break;
case 3:
painter.Transform(Xform2D::Sheer(0.2));
break;
}
Vector<String> lines=Split(text,10);
for(int row=0;row<lines.GetCount();row++){
Size sz=GetTextSize(lines[row],fnt);
Pointf delta(0,0);
switch(object.attpoint){
case 1: // 1 = Top left
break;
case 2: // Top Center
delta.x=-sz.cx/2;
break;
case 3: // Top Right
delta.x=-sz.cx;
break;
case 4: // Middle Left
delta.y=-sz.cy/2;
break;
case 5: // Middle Center
delta.y=-sz.cy/2;
delta.x=-sz.cx/2;
break;
case 6: // Middle Right
delta.y=-sz.cy/2;
delta.x=-sz.cx;
break;
default:
case 7: // Bottom Left
delta.y=-sz.cy;
break;
case 8: // Bottom Center
delta.y=-sz.cy;
delta.x=-sz.cx/2;
break;
case 9: // Bottom Right
delta.y=-sz.cy;
delta.x=-sz.cx;
break;
}
delta.y+=row*height_dp*1.5; // sz.cy
painter.Text(delta,lines[row],fnt);
}
if(edgecolor.a) painter.Stroke(height_dp*0.1,edgecolor);
painter.Fill(textcolor);
painter.End();
Best regards,
Tom
-
Attachment: T4.png
(Size: 80.69KB, Downloaded 670 times)
-
Attachment: T3.png
(Size: 82.44KB, Downloaded 681 times)
|
|
|
Re: Strange issue with text in Painter [message #50859 is a reply to message #50854] |
Thu, 10 January 2019 17:09 ![Go to previous message Go to previous message](theme/default/images/up.png) ![Go to next message Go to next message](theme/default/images/down.png) |
![](https://www.ultimatepp.org/forums/images/custom_avatars/3.png) |
mirek
Messages: 14003 Registered: November 2005
|
Ultimate Member |
|
|
I can see nothing obvious, but it feels like caching issue.
Please try this:
void ApproximateChar(LinearPathConsumer& t, Pointf at, int ch, Font fnt, double tolerance)
{
PAINTER_TIMING("ApproximateChar");
Value v;
INTERLOCKED {
PAINTER_TIMING("ApproximateChar::Fetch");
static LRUCache<Value, GlyphKey> cache;
cache.Shrink(500000);
sMakeGlyph h;
h.gk.fnt = fnt;
h.gk.chr = ch;
h.gk.tolerance = tolerance;
v = cache.Get(h);
}
#if 1
GlyphPainter chp;
chp.move = chp.pos = Null;
chp.tolerance = tolerance;
PaintCharacter(chp, Pointf(0, 0), ch, fnt);
Vector<float>& g = chp.glyph;
#else
const Vector<float>& g = ValueTo< Vector<float> >(v);
#endif
int i = 0;
while(i < g.GetCount()) {
Pointf p;
p.x = g[i++];
if(p.x > 1e30) {
p.x = g[i++];
p.y = g[i++];
t.Move(p + at);
}
else {
PAINTER_TIMING("ApproximateChar::Line");
p.y = g[i++];
t.Line(p + at);
}
}
}
(This switches caching off.)
Mirek
|
|
|
Re: Strange issue with text in Painter [message #50861 is a reply to message #50859] |
Thu, 10 January 2019 17:26 ![Go to previous message Go to previous message](theme/default/images/up.png) ![Go to next message Go to next message](theme/default/images/down.png) |
Tom1
Messages: 1221 Registered: March 2007
|
Senior Contributor |
|
|
Hi,
Thanks! I will check this too tomorrow!
Anyway, if this does not sort out easily, I can store the problematic sequence in a Painting and serialize it in a file for you to check out. (The same procedure as last time, when there was a complex Painter issue.)
Thanks,
Tom
|
|
|
Re: Strange issue with text in Painter [message #50862 is a reply to message #50861] |
Thu, 10 January 2019 17:46 ![Go to previous message Go to previous message](theme/default/images/up.png) ![Go to next message Go to next message](theme/default/images/down.png) |
![](https://www.ultimatepp.org/forums/images/custom_avatars/3.png) |
mirek
Messages: 14003 Registered: November 2005
|
Ultimate Member |
|
|
Tom1 wrote on Thu, 10 January 2019 17:26Hi,
Thanks! I will check this too tomorrow!
Anyway, if this does not sort out easily, I can store the problematic sequence in a Painting and serialize it in a file for you to check out. (The same procedure as last time, when there was a complex Painter issue.)
Thanks,
Tom
Yes, good idea.
Also, if my code change does not solve the problem, try this:
void BufferPainter::CharacterOp(const Pointf& p, int ch, Font fnt)
{
LLOG("@ CharacterOp " << p << ", " << ch << ", " << fnt);
#if 1
DoMove0();
PaintCharacter(*this, p, ch, fnt);
#else
move = current = EndPoint(p, false);
auto& m = PathAdd<CharData>(CHAR);
m.p = EndPoint(p, false);
m.ch = ch;
m.fnt = fnt;
path_info->ischar = true;
EvenOdd();
#endif
}
(It is similar - removing caching - just on another level)
|
|
|
Re: Strange issue with text in Painter [message #50866 is a reply to message #50862] |
Fri, 11 January 2019 09:40 ![Go to previous message Go to previous message](theme/default/images/up.png) ![Go to next message Go to next message](theme/default/images/down.png) |
Tom1
Messages: 1221 Registered: March 2007
|
Senior Contributor |
|
|
Hi Mirek,
The change in ApproximateChar() appears to fix the issue. However, as can be expected, the rendering speed drops dramatically.
I will next revert the ApproximateChar() changes and then test the BufferPainter::CharacterOp() change...
Best regards,
Tom
|
|
|
Re: Strange issue with text in Painter [message #50867 is a reply to message #50866] |
Fri, 11 January 2019 10:07 ![Go to previous message Go to previous message](theme/default/images/up.png) ![Go to next message Go to next message](theme/default/images/down.png) |
Tom1
Messages: 1221 Registered: March 2007
|
Senior Contributor |
|
|
Hi,
Also the change in BufferPainter::CharacterOp() seems to fix the issue. Similarly, the rendering speed drops.
The special thing about these maps I'm rendering is that they have an extremely small change in the text rotation thorough out the map page as they have been transformed from one coordinate projection to another (Transverse Mercator to Mercator in this case) and this involves a change in text rotation by the amount of meridian convergence value. This boils down to just parts of a degree through out the entire map width. I do not know if the caching gets affected by this or not.
I also generated a serialized painting, but it did not exhibit the issue. I think this is because the history for the cache is different and therefore the problem does not show up.
Best regards,
Tom
|
|
|
|
|
Re: Strange issue with text in Painter [message #50870 is a reply to message #50869] |
Fri, 11 January 2019 11:05 ![Go to previous message Go to previous message](theme/default/images/up.png) ![Go to next message Go to next message](theme/default/images/down.png) |
![](https://www.ultimatepp.org/forums/images/custom_avatars/3.png) |
mirek
Messages: 14003 Registered: November 2005
|
Ultimate Member |
|
|
Could you add these DLOGs
struct GlyphKey {
Font fnt;
int chr;
double tolerance;
bool operator==(const GlyphKey& b) const {
DLOG("*** operator==");
DDUMP(fnt);
DDUMP(b.fnt);
DDUMP(chr);
DDUMP(b.chr);
return fnt == b.fnt && chr == b.chr && tolerance == b.tolerance;
}
unsigned GetHashValue() const {
return CombineHash(fnt, chr, tolerance);
}
};
struct sMakeGlyph : LRUCache<Value, GlyphKey>::Maker {
GlyphKey gk;
GlyphKey Key() const { return gk; }
int Make(Value& v) const {
GlyphPainter gp;
gp.move = gp.pos = Null;
gp.tolerance = gk.tolerance;
DLOG("*** Make");
DDUMP(GetHashValue(gk));
DDUMP(gk.fnt);
DDUMP(gk.chr);
PaintCharacter(gp, Pointf(0, 0), gk.chr, gk.fnt);
int sz = gp.glyph.GetCount() * 4;
v = RawPickToValue(pick(gp.glyph));
return sz;
}
};
void ApproximateChar(LinearPathConsumer& t, Pointf at, int ch, Font fnt, double tolerance)
{
PAINTER_TIMING("ApproximateChar");
Value v;
INTERLOCKED {
DLOG("==== ApproximateChar " << ch << " " << fnt);
PAINTER_TIMING("ApproximateChar::Fetch");
static LRUCache<Value, GlyphKey> cache;
cache.Shrink(500000);
sMakeGlyph h;
h.gk.fnt = fnt;
h.gk.chr = ch;
h.gk.tolerance = tolerance;
DDUMP(GetHashValue(h.gk));
v = cache.Get(h);
}
#if 0
GlyphPainter chp;
chp.move = chp.pos = Null;
chp.tolerance = tolerance;
PaintCharacter(chp, Pointf(0, 0), ch, fnt);
const Vector<float>& g = chp.glyph;
#else
const Vector<float>& g = ValueTo< Vector<float> >(v);
#endif
int i = 0;
while(i < g.GetCount()) {
Pointf p;
p.x = g[i++];
if(p.x > 1e30) {
p.x = g[i++];
p.y = g[i++];
t.Move(p + at);
}
else {
PAINTER_TIMING("ApproximateChar::Line");
p.y = g[i++];
t.Line(p + at);
}
}
}
then bring it into error state, send me the screenshot and .log?
Thanks,
Mirek
[Updated on: Fri, 11 January 2019 11:16] Report message to a moderator
|
|
|
Re: Strange issue with text in Painter [message #50871 is a reply to message #50870] |
Fri, 11 January 2019 11:46 ![Go to previous message Go to previous message](theme/default/images/up.png) ![Go to next message Go to next message](theme/default/images/down.png) |
Tom1
Messages: 1221 Registered: March 2007
|
Senior Contributor |
|
|
Hi,
Here you go! Please find attached a the log, a screenshot and the serialized painting of the same.
As you can see in the painting, the text should read 'Perttilä', not ' erttilä'.
(You can view the painting using the PainterBench -tool.)
BR,
Tom
PS: The DLOG and DDUMP cause errors in RELEASE mode, but not in DEBUG mode though:
----- Painter ( GUI PROTECT MSC17X64 MSC WIN32 ) (8 / 32)
RenderChar.cpp
C:\upp-12610\upp.src\uppsrc\Painter\RenderChar.cpp(96): error C2018: unknown character '0x40'
C:\upp-12610\upp.src\uppsrc\Painter\RenderChar.cpp(97): error C2018: unknown character '0x40'
C:\upp-12610\upp.src\uppsrc\Painter\RenderChar.cpp(98): error C2018: unknown character '0x40'
C:\upp-12610\upp.src\uppsrc\Painter\RenderChar.cpp(99): error C2018: unknown character '0x40'
C:\upp-12610\upp.src\uppsrc\Painter\RenderChar.cpp(100): error C2018: unknown character '0x40'
C:\upp-12610\upp.src\uppsrc\Painter\RenderChar.cpp(116): error C2018: unknown character '0x40'
C:\upp-12610\upp.src\uppsrc\Painter\RenderChar.cpp(117): error C2018: unknown character '0x40'
C:\upp-12610\upp.src\uppsrc\Painter\RenderChar.cpp(118): error C2018: unknown character '0x40'
C:\upp-12610\upp.src\uppsrc\Painter\RenderChar.cpp(119): error C2018: unknown character '0x40'
C:\upp-12610\upp.src\uppsrc\Painter\RenderChar.cpp(132): error C2018: unknown character '0x40'
C:\upp-12610\upp.src\uppsrc\Painter\RenderChar.cpp(140): error C2018: unknown character '0x40'
Painter: 1 file(s) built in (0:00.90), 902 msecs / file, duration = 910 msecs, parallelization 0%
-
Attachment: T5.7z
(Size: 407.08KB, Downloaded 191 times)
[Updated on: Fri, 11 January 2019 11:52] Report message to a moderator
|
|
|
|
|
Re: Strange issue with text in Painter [message #50874 is a reply to message #50872] |
Fri, 11 January 2019 12:33 ![Go to previous message Go to previous message](theme/default/images/up.png) ![Go to next message Go to next message](theme/default/images/down.png) |
![](https://www.ultimatepp.org/forums/images/custom_avatars/3.png) |
mirek
Messages: 14003 Registered: November 2005
|
Ultimate Member |
|
|
No luck... Let us add more logging:
struct GlyphKey {
Font fnt;
int chr;
double tolerance;
bool operator==(const GlyphKey& b) const {
DLOG("*** operator==");
DDUMP(fnt);
DDUMP(b.fnt);
DDUMP(chr);
DDUMP(b.chr);
return fnt == b.fnt && chr == b.chr && tolerance == b.tolerance;
}
unsigned GetHashValue() const {
return CombineHash(fnt, chr, tolerance);
}
};
struct sMakeGlyph : LRUCache<Value, GlyphKey>::Maker {
GlyphKey gk;
GlyphKey Key() const { return gk; }
int Make(Value& v) const {
GlyphPainter gp;
gp.move = gp.pos = Null;
gp.tolerance = gk.tolerance;
DLOG("*** Make");
DDUMP(GetHashValue(gk));
DDUMP(gk.fnt);
DDUMP(gk.chr);
PaintCharacter(gp, Pointf(0, 0), gk.chr, gk.fnt);
int sz = gp.glyph.GetCount() * 4;
v = RawPickToValue(pick(gp.glyph));
return sz;
}
};
void ApproximateChar(LinearPathConsumer& t, Pointf at, int ch, Font fnt, double tolerance)
{
PAINTER_TIMING("ApproximateChar");
Value v;
INTERLOCKED {
DLOG("==== ApproximateChar " << ch << " " << fnt);
PAINTER_TIMING("ApproximateChar::Fetch");
static LRUCache<Value, GlyphKey> cache;
cache.Shrink(500000);
sMakeGlyph h;
h.gk.fnt = fnt;
h.gk.chr = ch;
h.gk.tolerance = tolerance;
DDUMP(GetHashValue(h.gk));
v = cache.Get(h);
DDUMP(ValueTo< Vector<float> >(v));
}
#if 0
GlyphPainter chp;
chp.move = chp.pos = Null;
chp.tolerance = tolerance;
PaintCharacter(chp, Pointf(0, 0), ch, fnt);
const Vector<float>& g = chp.glyph;
#else
const Vector<float>& g = ValueTo< Vector<float> >(v);
#endif
int i = 0;
while(i < g.GetCount()) {
Pointf p;
p.x = g[i++];
if(p.x > 1e30) {
p.x = g[i++];
p.y = g[i++];
t.Move(p + at);
}
else {
PAINTER_TIMING("ApproximateChar::Line");
p.y = g[i++];
t.Line(p + at);
}
}
}
the same (no need to send painting, just .log and tell me what letter is missing / wrong).
Thanks,
Mirek
|
|
|
|
Re: Strange issue with text in Painter [message #50877 is a reply to message #50875] |
Fri, 11 January 2019 14:33 ![Go to previous message Go to previous message](theme/default/images/up.png) ![Go to next message Go to next message](theme/default/images/down.png) |
Tom1
Messages: 1221 Registered: March 2007
|
Senior Contributor |
|
|
Hi,
Here's one sequence (of log) where the first letter 'J' is rendered too large:
==== ApproximateChar 74 <Arial:27>
GetHashValue(h.gk) = 3041017192
*** operator==
fnt = <Arial:27>
b.fnt = <Arial:5 Italic>
chr = 74
b.chr = 214
*** operator==
fnt = <Arial:27>
b.fnt = <Arial:27>
chr = 74
b.chr = 74
ValueTo< Vector<float> >(v) = [9.99999984824321e30, 1, 17.46875, 4, 17, 4.39453125, 19.908203125, 5.296875, 21.7265625, 6.671875, 22.681640625, 8.484375, 23, 9.892578125, 22.84765625, 11.0859375, 22.390625, 12.00390625, 21.671875, 12.5859375, 20.734375, 13, 17.390625, 13, -1, 16, -1, 16, 17.09375, 15.79296875, 20.046875, 15.171875, 22.25, 14.1015625, 23.861328125, 12.546875, 25.0390625, 10.59375, 25.759765625, 8.328125, 26, 6.63671875, 25.86572265625, 5.15625, 25.462890625, 3.88671875, 24.79150390625, 2.828125, 23.8515625, 1.9990234375, 22.64697265625, 1.41796875, 21.181640625, 1, 17.46875]
==== ApproximateChar 111 <Arial:27>
GetHashValue(h.gk) = 3041016509
*** operator==
fnt = <Arial:27>
b.fnt = <Arial:27>
chr = 111
b.chr = 111
ValueTo< Vector<float> >(v) = [9.99999984824321e30, 1, 18.5, 1.1337890625, 16.63671875, 1.53515625, 15.03125, 2.2041015625, 13.68359375, 3.140625, 12.59375, 5.12890625, 11.3984375, 7.5, 11, 10.109375, 11.484375, 12.1875, 12.9375, 13.546875, 15.24609375, 14, 18.296875, 13.798828125, 20.76953125, 13.1953125, 22.65625, 12.208984375, 24.0703125, 10.859375, 25.125, 9.25390625, 25.78125, 7.5, 26, 4.87109375, 25.517578125, 2.796875, 24.0703125, 2.0107421875, 22.99853515625, 1.44921875, 21.712890625, 1, 18.5, 9.99999984824321e30, 3, 18.5, 3.3203125, 20.90625, 4.28125, 22.625, 5.7265625, 23.65625, 7.5, 24, 9.2734375, 23.654296875, 10.71875, 22.6171875, 11.6796875, 20.873046875, 12, 18.40625, 11.677734375, 16.0703125, 10.7109375, 14.375, 9.263671875, 13.34375, 7.5, 13, 5.7265625, 13.341796875, 4.28125, 14.3671875, 3.3203125, 16.083984375, 3, 18.5]
==== ApproximateChar 101 <Arial:27>
GetHashValue(h.gk) = 3041016535
*** operator==
fnt = <Arial:27>
b.fnt = <Arial:27>
chr = 101
b.chr = 101
ValueTo< Vector<float> >(v) = [9.99999984824321e30, 11.96875, 22, 13.9375, 22, 13.107421875, 23.69140625, 11.7734375, 24.953125, 9.970703125, 25.73828125, 7.734375, 26, 4.94921875, 25.515625, 2.8125, 24.0625, 1.453125, 21.734375, 1, 18.625, 1.458984375, 15.40625, 2.03271484375, 14.1015625, 2.8359375, 13, 4.943359375, 11.5, 7.59375, 11, 10.162109375, 11.482421875, 12.2109375, 12.9296875, 13.552734375, 15.251953125, 14, 18.359375, 13.984375, 19, 3, 19, 3.44921875, 21.138671875, 4.484375, 22.7109375, 5.9765625, 23.677734375, 7.796875, 24, 10.3125, 23.5234375, 11.25, 22.904296875, 11.96875, 22, 9.99999984824321e30, 3, 17, 12, 17, 11.6484375, 15.46484375, 10.96875, 14.359375, 9.46484375, 13.33984375, 7.578125, 13, 5.8515625, 13.271484375, 4.421875, 14.0859375, 3.42578125, 15.357421875, 3, 17]
Interestingly it always has two operator== hash compares until a match is found. (I repeated the rendering multiple times to find the spot in log more easily.) Is this multiple hash match affecting the caching in some way?
BR,
Tom
PS: When a wrong cache item is picked for a character, it may have wrong size and wrong Italic/Normal coding, but it always is the correct letter (if it is visible at all). I think the complete lack of visibility might come from very small size of the cached character. This is almost like the LRUCache only looked at the character code when picking the result. Well, of course this is not the case, since otherwise most of the text items would be trash I guess...
[Updated on: Fri, 11 January 2019 15:25] Report message to a moderator
|
|
|
|
Re: Strange issue with text in Painter [message #50880 is a reply to message #50879] |
Fri, 11 January 2019 15:33 ![Go to previous message Go to previous message](theme/default/images/up.png) ![Go to next message Go to next message](theme/default/images/down.png) |
Tom1
Messages: 1221 Registered: March 2007
|
Senior Contributor |
|
|
Hi,
The first message in this thread portrays that: The 'Örviksudden' should have been in italic, but was instead shown with straight up 'Ö', if you look at it carefully. I have seen this in other tests too occasionally, so I can confirm it.
Best regards,
Tom
|
|
|
Re: Strange issue with text in Painter [message #50881 is a reply to message #50880] |
Fri, 11 January 2019 15:43 ![Go to previous message Go to previous message](theme/default/images/up.png) ![Go to next message Go to next message](theme/default/images/down.png) |
![](https://www.ultimatepp.org/forums/images/custom_avatars/3.png) |
mirek
Messages: 14003 Registered: November 2005
|
Ultimate Member |
|
|
Still no clues... Anyway, let us modify logging a bit:
void ApproximateChar(LinearPathConsumer& t, Pointf at, int ch, Font fnt, double tolerance)
{
PAINTER_TIMING("ApproximateChar");
Value v;
INTERLOCKED {
DLOG("==== ApproximateChar " << ch << " " << (char)ch << " " << fnt << ", tolerance: " << tolerance);
PAINTER_TIMING("ApproximateChar::Fetch");
static LRUCache<Value, GlyphKey> cache;
cache.Shrink(500000);
sMakeGlyph h;
h.gk.fnt = fnt;
h.gk.chr = ch;
h.gk.tolerance = tolerance;
v = cache.Get(h);
DDUMP(ValueTo< Vector<float> >(v));
#if 1
GlyphPainter chp;
chp.move = chp.pos = Null;
chp.tolerance = tolerance;
PaintCharacter(chp, Pointf(0, 0), ch, fnt);
DDUMP(chp.glyph);
ASSERT(ValueTo< Vector<float> >(v) == chp.glyph);
#endif
}
const Vector<float>& g = ValueTo< Vector<float> >(v);
int i = 0;
while(i < g.GetCount()) {
Pointf p;
p.x = g[i++];
if(p.x > 1e30) {
p.x = g[i++];
p.y = g[i++];
t.Move(p + at);
}
else {
PAINTER_TIMING("ApproximateChar::Line");
p.y = g[i++];
t.Line(p + at);
}
}
}
(If error is here, it should also assert....)
|
|
|
|
Goto Forum:
Current Time: Sun Sep 01 06:59:54 CEST 2024
Total time taken to generate the page: 0.05469 seconds
|