When Windows has the visual option "show window contents while dragging" is enabled then dragging a window over a VisualWorks window schedules thousands of invalidation/refresh events. It takes
a few seconds for VW to catch up as jagged rectangle regions are each repainted in sequence. I'm wondering if a VW 7.5 patch exists that avoids this problem. I seems like an easy thing to optimize.
Paul Baumann
This message may contain confidential information and is intended for specific recipients unless explicitly noted otherwise. If you have reason to believe you are not an intended recipient of this message, please delete it and notify the sender. This message may not represent the opinion of IntercontinentalExchange, Inc. (ICE), its subsidiaries or affiliates, and does not constitute a contract or guarantee. Unencrypted electronic mail is not secure and the recipient of this message is expected to provide safeguards from viruses and pursue alternate means of communication where privacy or a binding message is desired. _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
> When Windows has the visual option "show window contents while dragging" is
> enabled then dragging a window over a VisualWorks window schedules thousands > of invalidation/refresh events. It takes a few seconds for VW to catch up as > jagged rectangle regions are each repainted in sequence. I'm wondering if a VW > 7.5 patch exists that avoids this problem. I seems like an easy thing to > optimize. > > Paul Baumann This is a problem which dates back to approximately the time when Hannibal crossed the Alps. ;-) It has two causes which neatly combine into a medium sized disaster on Windows. The first cause is of course rooted in Windows itself (maybe not in all versions). I have seen Windows create a flood of damage events with zero width or height, or even both, when dragging a window. I have no idea why Windows thinks that this is a good idea. In addition Windows often creates a series of adjacent but not intersecting damage rectangles. The second root of evil lurks in WindowSensor>>privateAddDamage:. This method and the methods calling it do not check for damage rectangles of zero width or height, which could safely be ignored. The method tries to optimize damage lists by merging intersecting damage areas. However, it does not merge adjacent rectangles. E.g., the rectangles (0@0 corner: 10@1) and (0@1 corner: 10@2) will not be merged into (0@0 corner: 10@2). Given the behaviour of Windows, this means that you may end up with thousands of damage rectangles which are 0 or 1 pixel wide or high. Once this happens, repairing the damage behaves as you described. WindowDisplayPolicy>>displayDamageList:in: will happily iterate over thousands of small rectangles, painting the background and sending displayOn: to the window's component for each of them. It will also copy the window's GraphicsContext for each of the rectangles, thus creating a huge amount of garbage. A quick workaround which may be viable in many cases is to use the DoubleBufferingDisplayPolicy which merges all the damage areas into their bounding rectangle before repairing the damage. The downside of this DisplayPolicy is that it needs a bit more memory for an additional pixmap, and that it may redraw a large rectangle when only some small spots need to be updated. If the displayOn: method of the window's component is expensive, this may be prohibitive. It's easy to change privateAddDamage: to skip empty rectangles. It's also not hard to merge adjacent rectangles or rectangles which are "near enough". One could also cap the number of separate damage areas, and merge them all into one when there are more than e.g. 100. I think that in practically all cases, it is quicker to redraw one large rectangle than hundreds of small ones - in particular because the most likely source of hundreds of damage areas is dragging the window, where the damage areas are adjacent anyway. BTW, I'd be happy to see one of these messages saying "AR xyz created" for this problem. ;-) It's easy enough to fix, and it has been a PITA for decades literally. A patch is attached (just in case: don't sue me if it doesn't work, use it at your own risk). It discards empty areas and merges adjacent rectangles. It even has test cases. :) Cheers, Joachim Geidel _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc WindowSensor-privateAddDamage.st.zip (1K) Download Attachment WindowSensorTest.st.zip (1K) Download Attachment |
Thanks Joachim,
That is just the kind of response I was hoping for--and so many details too. I agree, the problem is decades older than it should be. I think I'd worked around it myself several years ago, but changes like that tend to be left with earlier jobs or VW releases. At the time, I think ongoing Pollock work was going to make the problem go away. I hope your changes get carried forward. I suspect the problem creates in inverse relationship between the speed of your computer and the time it takes to refresh a dragged-over VW window. A faster computer generates more damaged rectangles. Some people had negotiated hardware upgrades over this issue. Regards, Paul Baumann -----Original Message----- From: Joachim Geidel [mailto:[hidden email]] Sent: Saturday, October 11, 2008 9:35 AM To: Paul Baumann; [hidden email] Subject: Re: [vwnc] Optimizing window invalidation events Importance: High > When Windows has the visual option "show window contents while > dragging" is enabled then dragging a window over a VisualWorks window > schedules thousands of invalidation/refresh events. It takes a few > seconds for VW to catch up as jagged rectangle regions are each > repainted in sequence. I'm wondering if a VW > 7.5 patch exists that avoids this problem. I seems like an easy thing > to optimize. > > Paul Baumann This is a problem which dates back to approximately the time when Hannibal crossed the Alps. ;-) It has two causes which neatly combine into a medium sized disaster on Windows. The first cause is of course rooted in Windows itself (maybe not in all versions). I have seen Windows create a flood of damage events with zero width or height, or even both, when dragging a window. I have no idea why Windows thinks that this is a good idea. In addition Windows often creates a series of adjacent but not intersecting damage rectangles. The second root of evil lurks in WindowSensor>>privateAddDamage:. This method and the methods calling it do not check for damage rectangles of zero width or height, which could safely be ignored. The method tries to optimize damage lists by merging intersecting damage areas. However, it does not merge adjacent rectangles. E.g., the rectangles (0@0 corner: 10@1) and (0@1 corner: 10@2) will not be merged into (0@0 corner: 10@2). Given the behaviour of Windows, this means that you may end up with thousands of damage rectangles which are 0 or 1 pixel wide or high. Once this happens, repairing the damage behaves as you described. WindowDisplayPolicy>>displayDamageList:in: will happily iterate over thousands of small rectangles, painting the background and sending displayOn: to the window's component for each of them. It will also copy the window's GraphicsContext for each of the rectangles, thus creating a huge amount of garbage. A quick workaround which may be viable in many cases is to use the DoubleBufferingDisplayPolicy which merges all the damage areas into their bounding rectangle before repairing the damage. The downside of this DisplayPolicy is that it needs a bit more memory for an additional pixmap, and that it may redraw a large rectangle when only some small spots need to be updated. If the displayOn: method of the window's component is expensive, this may be prohibitive. It's easy to change privateAddDamage: to skip empty rectangles. It's also not hard to merge adjacent rectangles or rectangles which are "near enough". One could also cap the number of separate damage areas, and merge them all into one when there are more than e.g. 100. I think that in practically all cases, it is quicker to redraw one large rectangle than hundreds of small ones - in particular because the most likely source of hundreds of damage areas is dragging the window, where the damage areas are adjacent anyway. BTW, I'd be happy to see one of these messages saying "AR xyz created" for this problem. ;-) It's easy enough to fix, and it has been a PITA for decades literally. A patch is attached (just in case: don't sue me if it doesn't work, use it at your own risk). It discards empty areas and merges adjacent rectangles. It even has test cases. :) Cheers, Joachim Geidel This message may contain confidential information and is intended for specific recipients unless explicitly noted otherwise. If you have reason to believe you are not an intended recipient of this message, please delete it and notify the sender. This message may not represent the opinion of IntercontinentalExchange, Inc. (ICE), its subsidiaries or affiliates, and does not constitute a contract or guarantee. Unencrypted electronic mail is not secure and the recipient of this message is expected to provide safeguards from viruses and pursue alternate means of communication where privacy or a binding message is desired. _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Joachim Geidel
Travis nixed this. It's very nice and enjoyable now. AR 55395.
-----Original Message----- From: [hidden email] [mailto:[hidden email]] On Behalf Of Joachim Geidel Sent: Saturday, October 11, 2008 6:35 AM To: Paul Baumann; [hidden email] Subject: Re: [vwnc] Optimizing window invalidation events > When Windows has the visual option "show window contents while > dragging" is enabled then dragging a window over a VisualWorks window > schedules thousands of invalidation/refresh events. It takes a few > seconds for VW to catch up as jagged rectangle regions are each > repainted in sequence. I'm wondering if a VW > 7.5 patch exists that avoids this problem. I seems like an easy thing > to optimize. > > Paul Baumann This is a problem which dates back to approximately the time when Hannibal crossed the Alps. ;-) It has two causes which neatly combine into a medium sized disaster on Windows. The first cause is of course rooted in Windows itself (maybe not in all versions). I have seen Windows create a flood of damage events with zero width or height, or even both, when dragging a window. I have no idea why Windows thinks that this is a good idea. In addition Windows often creates a series of adjacent but not intersecting damage rectangles. The second root of evil lurks in WindowSensor>>privateAddDamage:. This method and the methods calling it do not check for damage rectangles of zero width or height, which could safely be ignored. The method tries to optimize damage lists by merging intersecting damage areas. However, it does not merge adjacent rectangles. E.g., the rectangles (0@0 corner: 10@1) and (0@1 corner: 10@2) will not be merged into (0@0 corner: 10@2). Given the behaviour of Windows, this means that you may end up with thousands of damage rectangles which are 0 or 1 pixel wide or high. Once this happens, repairing the damage behaves as you described. WindowDisplayPolicy>>displayDamageList:in: will happily iterate over thousands of small rectangles, painting the background and sending displayOn: to the window's component for each of them. It will also copy the window's GraphicsContext for each of the rectangles, thus creating a huge amount of garbage. A quick workaround which may be viable in many cases is to use the DoubleBufferingDisplayPolicy which merges all the damage areas into their bounding rectangle before repairing the damage. The downside of this DisplayPolicy is that it needs a bit more memory for an additional pixmap, and that it may redraw a large rectangle when only some small spots need to be updated. If the displayOn: method of the window's component is expensive, this may be prohibitive. It's easy to change privateAddDamage: to skip empty rectangles. It's also not hard to merge adjacent rectangles or rectangles which are "near enough". One could also cap the number of separate damage areas, and merge them all into one when there are more than e.g. 100. I think that in practically all cases, it is quicker to redraw one large rectangle than hundreds of small ones - in particular because the most likely source of hundreds of damage areas is dragging the window, where the damage areas are adjacent anyway. BTW, I'd be happy to see one of these messages saying "AR xyz created" for this problem. ;-) It's easy enough to fix, and it has been a PITA for decades literally. A patch is attached (just in case: don't sue me if it doesn't work, use it at your own risk). It discards empty areas and merges adjacent rectangles. It even has test cases. :) Cheers, Joachim Geidel _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Paul Baumann
Why is it that VW doesn’t update underlying windows if you drag
one VW window over another? Most regular Windows programs do. Wouldn’t processing
window invalidation events as they are posted, instead of queuing them all up
until the dragged windows is released, eliminate most of the catch-up delay? Cheers, /axl From:
[hidden email] [mailto:[hidden email]] On Behalf Of Paul
Baumann When
Windows has the visual option "show window contents while
dragging" is enabled then dragging a window over a VisualWorks
window schedules thousands of invalidation/refresh events. It takes a few
seconds for VW to catch up as jagged rectangle regions are each repainted in
sequence. I'm wondering if a VW 7.5 patch exists that avoids this
problem. I seems like an easy thing to optimize. Paul Baumann This message may contain confidential information and is intended
for specific recipients unless explicitly noted otherwise. If you have reason
to believe you are not an intended recipient of this message, please delete it
and notify the sender. This message may not represent the opinion of
IntercontinentalExchange, Inc. (ICE), its subsidiaries or affiliates, and does
not constitute a contract or guarantee. Unencrypted electronic mail is not
secure and the recipient of this message is expected to provide safeguards from
viruses and pursue alternate means of communication where privacy or a binding
message is desired. _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Drag a VW window over another VW window and the repair happens when the window is released. Drag a window from another application over a VW window and
the repair happens as fast as VW can. I'd venture a guess that the VW VM does a minimal amount in response to window move events (from the OS) because VW manages non-native widgets that are repaired at a different priority. VisualAge has native widgets and
had to use a complex event queuing mechanism to ensure that a single UIProcess handles all UI callins and required callbacks to use the UIProcess too to say in sync; those would get queued in semaphores and near equivalents. I bring up VA because that approach
had problems too--like with use of application semaphores invoked through callbacks that can not #wait. I wonder how Java how responds to window damage.
The repair cost is sub-second for VW tool windows. Repair can take several seconds for our application notebooks with many editable fields in table views.
The workaround that Joachim posted Saturday works well.
Paul Baumann
From: Andreas Axelsson [mailto:[hidden email]] Sent: Tuesday, October 14, 2008 4:11 AM To: Paul Baumann; [hidden email] Subject: RE: [vwnc] Optimizing window invalidation events Importance: High Why is it that VW doesn’t update underlying windows if you drag one VW window over another? Most regular Windows programs do. Wouldn’t processing window
invalidation events as they are posted, instead of queuing them all up until the dragged windows is released, eliminate most of the catch-up delay? Cheers, /axl From: [hidden email] [mailto:[hidden email]]
On Behalf Of Paul Baumann When Windows has the visual option "show window contents while dragging" is enabled then dragging a window over a VisualWorks window schedules thousands of invalidation/refresh
events. It takes a few seconds for VW to catch up as jagged rectangle regions are each repainted in sequence. I'm wondering if a VW 7.5 patch exists that avoids this problem. It seems like
an easy thing to optimize. Paul Baumann This message may contain confidential information and is intended for specific recipients unless explicitly noted otherwise. If you have reason to believe you
are not an intended recipient of this message, please delete it and notify the sender. This message may not represent the opinion of IntercontinentalExchange, Inc. (ICE), its subsidiaries or affiliates, and does not constitute a contract or guarantee. Unencrypted
electronic mail is not secure and the recipient of this message is expected to provide safeguards from viruses and pursue alternate means of communication where privacy or a binding message is desired. This message may contain confidential information and is intended for specific recipients unless explicitly noted otherwise. If you have reason to believe you are not an intended recipient of this message, please delete it and notify the sender. This message may not represent the opinion of IntercontinentalExchange, Inc. (ICE), its subsidiaries or affiliates, and does not constitute a contract or guarantee. Unencrypted electronic mail is not secure and the recipient of this message is expected to provide safeguards from viruses and pursue alternate means of communication where privacy or a binding message is desired. _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Joachim Geidel
For some reason I have some code which draws to device context for a VisualPart subclass and the code works exactly as I would expect on Windows, but on the Mac it behaves erratically, not always painting everything. If I mess with the scrollbars or if I click on another window it will often suddenly show me everything, but then if I click back to that window or scroll around some more it will get funky again.
I'm not drawing to a bitmap and then to my widget. The displayOn: method draws everything from scratch each time, if that's helpful. I tried using double buffering, but that didn't help. Why would the Mac behave any differently under VW? Thanks, -Carl Gundel http://www.libertybasic.com http://www.runbasic.com _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Is there something different about the way that graphicsContexts are handled on the Mac? Are they somehow less durable so that they stop working quickly, or something?
I'm not doing anything fancy here, just drawing some lines. I get the graphicsContext from the VisualPart for each line. myVisualPart graphicsContext displayLineFrom: self position to: position + (newX @ newY) The example I'm running is a BASIC program that draws the classic dragon fractal. It draws the first couple of dozen lines. It goes through the motions of drawing them all. This works fine on Windows. Baffled. -Carl On Aug 22, 2011, at 12:48 AM, Carl Gundel wrote: > For some reason I have some code which draws to device context for a VisualPart subclass and the code works exactly as I would expect on Windows, but on the Mac it behaves erratically, not always painting everything. If I mess with the scrollbars or if I click on another window it will often suddenly show me everything, but then if I click back to that window or scroll around some more it will get funky again. > > I'm not drawing to a bitmap and then to my widget. The displayOn: method draws everything from scratch each time, if that's helpful. I tried using double buffering, but that didn't help. > > Why would the Mac behave any differently under VW? > > Thanks, > > -Carl Gundel > http://www.libertybasic.com > http://www.runbasic.com > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
On Aug 22, 2011, at 10:34 AM, Carl Gundel wrote: > Is there something different about the way that graphicsContexts are handled on the Mac? Are they somehow less durable so that they stop working quickly, or something? > > I'm not doing anything fancy here, just drawing some lines. I get the graphicsContext from the VisualPart for each line. > > myVisualPart graphicsContext displayLineFrom: self position to: position + (newX @ newY) > > The example I'm running is a BASIC program that draws the classic dragon fractal. It draws the first couple of dozen lines. It goes through the motions of drawing them all. > > This works fine on Windows. Baffled. I'm not seeing issues with it on latest builds. I used the following (st11a oct11.3 on OSX Lion) t := ScheduledWindow new openWithExtent: 400@400. r := Random new. 1 to: 100 do: [:n | t graphicsContext displayLineFrom: (r next @ r next) * t displayBox extent to:(r next @ r next) * t displayBox extent] And executed each line one at a time, doing the last a couple of times. It seemed to show up fine. I do know that just scribbling to a GC like this is frowned upon for regular stuff. There may come a day in the not too distant future when we outlaw it completely, demanding you do stuff inside of an invalidate where we can control the composition better. -- Travis Griggs Objologist Light travels faster than sound. This is why some people appear bright until you hear them speak... _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Thanks. I have to try and reproduce this with some example code. Wish me luck.
-Carl Gundel Liberty BASIC for Windows - http://www.libertybasic.com Run BASIC, easy web programming - http://www.runbasic.com On Aug 22, 2011, at 6:31 PM, Travis Griggs <[hidden email]> wrote: > > On Aug 22, 2011, at 10:34 AM, Carl Gundel wrote: > >> Is there something different about the way that graphicsContexts are handled on the Mac? Are they somehow less durable so that they stop working quickly, or something? >> >> I'm not doing anything fancy here, just drawing some lines. I get the graphicsContext from the VisualPart for each line. >> >> myVisualPart graphicsContext displayLineFrom: self position to: position + (newX @ newY) >> >> The example I'm running is a BASIC program that draws the classic dragon fractal. It draws the first couple of dozen lines. It goes through the motions of drawing them all. >> >> This works fine on Windows. Baffled. > > I'm not seeing issues with it on latest builds. I used the following (st11a oct11.3 on OSX Lion) > > t := ScheduledWindow new openWithExtent: 400@400. > r := Random new. > 1 to: 100 do: [:n | t graphicsContext displayLineFrom: (r next @ r next) * t displayBox extent to:(r next @ r next) * t displayBox extent] > > And executed each line one at a time, doing the last a couple of times. It seemed to show up fine. > > I do know that just scribbling to a GC like this is frowned upon for regular stuff. There may come a day in the not too distant future when we outlaw it completely, demanding you do stuff inside of an invalidate where we can control the composition better. > > -- > Travis Griggs > Objologist > Light travels faster than sound. This is why some people appear bright until you hear them speak... > > > > _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
On Aug 22, 2011, at 6:35 PM, Carl Gundel wrote: > Thanks. I have to try and reproduce this with some example code. Wish me luck. Are you perchance intermingling any text display with it? Also… what VM version are you using? -- Travis Griggs Objologist "The project was so plagued by politics and ego that when the engineers requested technical oversight, our manager hired a psychologist instead." -- Ron Avitzur _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Travis Griggs-4
Am 23.08.2011 um 00:31 schrieb Travis Griggs: > I do know that just scribbling to a GC like this is frowned upon for > regular stuff. There may come a day in the not too distant future > when we outlaw it completely, demanding you do stuff inside of an > invalidate where we can control the composition better. Travis, that's a wonderful perspective. I'm looking forward to it! The whole display/refresh thing only works properly with a strict delegation to the event loop that runs on the "UI thread" (although VW is using a different terminology). Only this way it can be assured that the OS' own double buffering (lock/unlock) works as intended. The flickering artifacts we still see here and there are all due to a violation of that simple principle. To enforce a clean nesting of drawing actions, I had to change large portions of the OSX virtual machine. I /had/ to do it this way, because I did not have the resources to rewrite the entire UI framework in Smalltalk. Now seeing you doing this, is good news. Definitely a move into the right direction. If the Smalltalk framework becomes clean and simple, the VM's native level (or its Cairo equivalent) will be much easier to implement. This btw is not limited to the Mac. A clean UI framework will also be of huge benefit on Windows and other platforms. Andre _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Travis Griggs-4
Travis, no I'm not displaying any text.
My VM datestamp is July 1, 2011 12:12AM. In About Visualworks in the System tab I get this: Version Id: #[70 52 70 128 78 0 0 0 70 40 70 80] Here is a small as possible example which demonstrates what I'm seeing. File it into a base visual.im and evaluate DragonTest new open. It may display initially correctly (it should display a good sized dragon), but then try dragging the scroll bars or just click on the right button on the horizontal scrollbar to see a very strange effect, especially clicking several times quickly in a row, and then wait a couple of seconds and click again. There seems to be some sort of timing issue. Is it possible I'm just doing something wrong? -Carl Gundel http://www.libertybasic.com http://www.runbasic.com On Aug 22, 2011, at 10:38 PM, Travis Griggs wrote: > > On Aug 22, 2011, at 6:35 PM, Carl Gundel wrote: > >> Thanks. I have to try and reproduce this with some example code. Wish me luck. > > Are you perchance intermingling any text display with it? Also… what VM version are you using? > > -- > Travis Griggs > Objologist > "The project was so plagued by politics and ego that when the engineers requested technical oversight, our manager hired a psychologist instead." -- Ron Avitzur > > > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc drawingobjects.st (64K) Download Attachment |
Hey Travis,
Are you back from ESUG yet? How was it? :-) I've attached a modified (simplified) example of what isn't working for me on OSX. And taking a cue from you... here is a link to a screencast showing what I see. http://screencast.com/t/AMlzSiBU5 Thanks a ton! -Carl On Aug 25, 2011, at 1:11 AM, Travis Griggs wrote: > - _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc drawingobjects.st (69K) Download Attachment |
Thanks Travis. I'm going to try and bang on this some more too. I'm a bit out of my depth with it but perhaps I will still manage to figure something out. I'll be in a bit of a mess if I can't make this work. It should be a simple matter to draw a bunch of lines using a command pattern, right? -Carl Gundel Liberty BASIC for Windows - http://www.libertybasic.com Run BASIC, easy web programming - http://www.runbasic.com
_______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by Carl Gundel
I'm adding a TextEditorView in my tabbed interface. It works fine but I need a horizontal scrollbar. It has eluded me thus far. Any thoughts?
self partPort partCreationBlock: [:object | | view | view := TextEditorView model: '' asValue. view setTextStyle: self class textStyle; wordWrap: false. view widgetState isTabStop: true. BorderDecorator on: view]. Thanks. -Carl Gundel http://www.libertybasic.com http://www.runbasic.com _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Free forum by Nabble | Edit this page |