Of course the answer to many programming questions is yes it can be done and that sounds cool, but there is a big but. Given the necessary compiler support - eg: to stop inlining of methods you may wish to intercept - the question remains is this the best way to solve this problem.
On the server aop is often used to solve problems -like tx management - which are not present in a gwt app. I appreciate the problem with sending detached objects, however nothing has been said to refute my previous comments that maybe, just maybe detached objects in gwt are a bad idea...i'd like hear some thoughts on that. Btw I'm all for experimentation, don't get me wrong. In this case I did it one way and thinking back I believe there are alternatives and I am just voicing my opinions on my observations... Hth. On 23/04/2009, at 6:15 PM, Ray Cromwell <[email protected]> wrote: > > Volatile has a long history of disabling compiler optimizations, in > both Java, and C/C++, so it is not quite inappropriate to use it for > this purpose. GWT already uses volatile for this purpose, for example, > volatile fields are not subject to type-tightening or being promoted > to final, and in some areas, expressions that evaluate as volatile are > considered to have side effects, even if the operations themselves are > side effect free. Volatile in C/C++ prevents a bunch of optimizations > as well and must be used in some circumstances (like if you want a > busy-wait spin loop to not be dead-code-eliminated) > > Whether or not AOP is useful or not is besides the point. The point > is, the cost of AOP is not as high as the cost of reflection, and > implementing AOP isn't an 'all or nothing' proposition. I personally > don't use AOP, but if someone asks me whether there's an efficient way > to do it, the answer is, maybe there is. I don't think it is helpful > to just shutdown discussion over a particular pattern because one > doesn't like it. > > > > On Thu, Apr 23, 2009 at 12:47 AM, Miroslav Pokorny > <[email protected]> wrote: >> >> Too much extra nonsense adding annotations everywhere. You could have >> written a more efficient decorator fir less keystrokes and the >> decorator will always be faster at runtime and save the compiler from >> overheating with extra passes and complexity. >> >> It's never a good thing to chest and reuse something line volatile. >> Today you aNt it for this and tomorrow someone else will have an >> equally useful thing which they want to steel volatile for. >> >> Why not keep it simple and just writeba decorator ? >> >> On 23/04/2009, at 5:10 PM, Ray Cromwell <[email protected]> >> wrote: >> >>> >>> If there was a low cost way to disable inlining and conversion to >>> static methods of certain functions, you might be able handle the >>> interception dynamically, e.g. >>> >>> for(method in myClass.prototype) { >>> if(shouldIntercept(myClass.prototype[method])) { >>> myClass.prototype[method] = function() { >>> return @com.foo.InterceptorRegistry::methodInterceptor(...) >>> (...); >>> } >>> } >>> } >>> >>> You'd have to implement one method for Hosted Mode, and another for >>> web mode. This would not really add any bloat, as method names >>> could >>> be registered for interception using their obfuscated ids, and only >>> non-pruned methods would be picked up by the introspector. There are >>> quite a few JS frameworks that implement stuff like this. >>> >>> The problem is, if you can't force non-inlining and non-monomorphic >>> conversions, then you run the risk of inlined or statically invoked >>> callsites not invoking the interceptors. One way to force this is to >>> simply switch the parameter eval order in your methods, which >>> disables >>> inlining (for now, but not guaranteed to work in future). Preventing >>> the staticifier from running is more difficult. You have to induce >>> polymorphism by subclassing in a way that the method call can't be >>> inferred final, and this will lead to bloat. Perhaps future compiler >>> hints like "@DoNotInline" could help, or maybe reusing 'volatile' >>> some >>> how, like if a method references a violate parameter, it can't be >>> inlined or staticified. >>> >>> -Ray >>> >>> >>> On Wed, Apr 22, 2009 at 11:41 PM, Miroslav Pokorny >>> <[email protected]> wrote: >>>> >>>> To implement Interceptors in gwt one does just needs to follow the >>>> same general patterns that exist in real java and aop. >>>> >>>> I have already done interceptors / aop for gwt as part of my own di >>>> module in gwt. One does not need interceptors in gwt a lot of extra >>>> behind the scenes classes are needed both generated and framework >>>> to >>>> make it work. >>>> >>>> 1/ To intercept one class you need to subclass the target. >>>> 2/ every public method needs to include some stuff to handle firing >>>> of >>>> said interceptors. >>>> 3/ if u want the interceptors to be able to truly intercept and be >>>> able to modify parameters, veto the call to the target substitute a >>>> different return value etc a lot of extra code is needed. If u want >>>> too see am example download my project and run the test cases with >>>> the >>>> gen flag on. >>>> >>>> Supporting other dynamic mechanisms like reflection are also >>>> possible >>>> but the amount of generated stuff required bloats your javascript >>>> by >>>> significant amounts. >>>> >>>> One of the goals of gwt is to produce minimalist code and this goes >>>> against this mantra. >>>> >>>> On 23/04/2009, at 12:19 PM, Arthur Kalmenson >>>> <[email protected]> >>>> wrote: >>>> >>>>> >>>>>> Now, MyBean does not implement interface X, but a generator/AOP >>>>>> interceptor could make a subclass of MyBean that has interface X >>>>>> implement. IIRC, GWT RPC just invokes the default constructor, so >>>>>> there's no way to intercept this and substitute a replacement. >>>>> >>>>> Yeah, that is an interesting question. However, wouldn't the AOP >>>>> be >>>>> happening before you send the object over the wire? You wouldn't >>>>> really care about any interception at that point.... >>>>> >>>>> -- >>>>> Arthur Kalmenson >>>>> >>>>> >>>>> >>>>> On Wed, Apr 22, 2009 at 12:28 AM, Ray Cromwell >>>>> <[email protected]> wrote: >>>>>> >>>>>> On Tue, Apr 21, 2009 at 7:11 PM, Arthur Kalmenson <[email protected] >>>>>>> wrote: >>>>>>> >>>>>>> Hmm, but don't you normally send some kind of Model or domain >>>>>>> object >>>>>>> over the wire and not something that would need to be injected >>>>>>> with >>>>>>> dependencies by Gin? >>>>>> >>>>>> >>>>>> I think what he's saying is that he might have an RPC method like >>>>>> this: >>>>>> >>>>>> public interface MyService extends RemoteService { >>>>>> MyBean getBean(); >>>>>> } >>>>>> >>>>>> Now, MyBean does not implement interface X, but a generator/AOP >>>>>> interceptor could make a subclass of MyBean that has interface X >>>>>> implement. IIRC, GWT RPC just invokes the default constructor, so >>>>>> there's no way to intercept this and substitute a replacement. >>>>>> >>>>>> I think the other thing he might want to do is intercept client- >>>>>> side >>>>>> UI classes and make them call addPropertyChangeListener() on a >>>>>> model >>>>>> object based on certain invocations. >>>>>> >>>>>> -Ray >>>>>> >>>>>>> And Bruce, that's an interesting example. I was thinking how one >>>>>>> would >>>>>>> implement AOP in GWT, perhaps it's not as hard as I originally >>>>>>> thought. Is there a way to extend this example to dynamically >>>>>>> create >>>>>>> proxies for any class that'll be advised by some aspect? >>>>>>> >>>>>>> Also, Nicolas, AFAIK, the GWT team (bobv) is working on a data >>>>>>> binding >>>>>>> (and validation?) framework. I'm hoping something will hit the >>>>>>> incubator soon so we can all jump on board and help out. It'd >>>>>>> definitely have saved us thousands of lines of glue code ;). >>>>>>> >>>>>>> P.S. Sorry about not writing up that how-to for >>>>>>> GWTMockUtilities, >>>>>>> Bruce. I'll try to do it some time this week. >>>>>>> >>>>>>> Best regards, >>>>>>> -- >>>>>>> Arthur Kalmenson >>>>>>> >>>>>>> >>>>>>> >>>>>>> On Tue, Apr 21, 2009 at 2:58 PM, Ray Cromwell >>>>>>> <[email protected]> wrote: >>>>>>>> >>>>>>>> Interesting question. Gin auto-creates RPC interfaces as well, >>>>>>>> for >>>>>>>> example, if you have: >>>>>>>> >>>>>>>> public interface MyFoo extends Ginjector { >>>>>>>> MyServiceAsync getService(); >>>>>>>> } >>>>>>>> >>>>>>>> then Gin implicitly looks for MyService.class and invokes >>>>>>>> GWT.create(MyService.class) when calling getService(). Since >>>>>>>> Gin is >>>>>>>> handling the creation, I'm not sure if it handles RPC methods >>>>>>>> with >>>>>>>> classes have have @Inject annotations, but you could probably >>>>>>>> setup a >>>>>>>> separate binding. The de-serialization logic in RPC is not >>>>>>>> likely >>>>>>>> to >>>>>>>> allow Gin interception, since it apparently uses default >>>>>>>> constructors >>>>>>>> to create classes, and what you want it to do is delegate the >>>>>>>> construction to some injectable mechanism (e.g. to substitute >>>>>>>> your own >>>>>>>> subclasses) >>>>>>>> >>>>>>>> It doesn't sound impossible to make this work, and is probably >>>>>>>> easier >>>>>>>> to get right than trying to make new Foo() interceptable by the >>>>>>>> compiler. I would join the Gin groups and ask the guys there >>>>>>>> about it. >>>>>>>> >>>>>>>> -Ray >>>>>>>> >>>>>>>> >>>>>>>> On Tue, Apr 21, 2009 at 11:49 AM, nicolas de loof >>>>>>>> <[email protected]> wrote: >>>>>>>>> Sounds a good solution. >>>>>>>>> How would this solve the use case "data returned by RPC >>>>>>>>> call" ? >>>>>>>>> >>>>>>>>> 2009/4/21 Ray Cromwell <[email protected]> >>>>>>>>>> >>>>>>>>>> I really think Guice-style dependency injection is the way to >>>>>>>>>> go to >>>>>>>>>> solve this problem, rather than trying to emulate Java >>>>>>>>>> Proxies/Classloader in the compiler. If you use Guice/Gin, >>>>>>>>>> then >>>>>>>>>> in Gin >>>>>>>>>> you can inject GWT.create-d versions, and in JUnit-mode, you >>>>>>>>>> can use >>>>>>>>>> regular Guice injection. The code use is 99% between GWT and >>>>>>>>>> non-GWT >>>>>>>>>> versions test versions, with the exception of the >>>>>>>>>> Guice-config/Injector creation. >>>>>>>>>> >>>>>>>>>> Because of the way Gin works transitively, you only need a >>>>>>>>>> single >>>>>>>>>> GWT.create() and this is isolated to your startup code >>>>>>>>>> while in >>>>>>>>>> your >>>>>>>>>> JUnit version, you kick off a Guice-injected class instead. >>>>>>>>>> >>>>>>>>>> -Ray >>>>>>>>>> >>>>>>>>>> On Tue, Apr 21, 2009 at 11:28 AM, nicolas de loof >>>>>>>>>> <[email protected]> wrote: >>>>>>>>>>> A simple example : databinding >>>>>>>>>>> Lets consider I want to bind some Label text to some model >>>>>>>>>>> Bean value. >>>>>>>>>>> Gwt >>>>>>>>>>> Label widget "text" can be accessed as a javaBean >>>>>>>>>>> property, so >>>>>>>>>>> this >>>>>>>>>>> sound a >>>>>>>>>>> typical java.beans.binding use-case >>>>>>>>>>> This requires my model bean to support >>>>>>>>>>> PropertyChangeListeners. As I'm >>>>>>>>>>> lazy >>>>>>>>>>> I'd like a generator to create an "enhanced" model class >>>>>>>>>>> with >>>>>>>>>>> such >>>>>>>>>>> support >>>>>>>>>>> for the "value" property. >>>>>>>>>>> I can get this to work today if my model Bean is created >>>>>>>>>>> using >>>>>>>>>>> GWT.create(), >>>>>>>>>>> but this makes my code GWT-dependant and not testable in >>>>>>>>>>> "standalone" >>>>>>>>>>> junit. >>>>>>>>>>> If the generator "enhanced" class is used even when I use " >>>>>>>>>>> new Model() >>>>>>>>>>> " or >>>>>>>>>>> get a Model bean from RPC, my code can be easily unit >>>>>>>>>>> tested. >>>>>>>>>>> Cheers, >>>>>>>>>>> Nicolas >>>>>>>>>>> >>>>>>>>>>> 2009/4/21 Bruce Johnson <[email protected]> >>>>>>>>>>>> >>>>>>>>>>>> On Tue, Apr 21, 2009 at 12:38 PM, nicolas de loof >>>>>>>>>>>> <[email protected]> wrote: >>>>>>>>>>>>> >>>>>>>>>>>>> The only critism I'd have is the requirement to use >>>>>>>>>>>>> GWT.create() to >>>>>>>>>>>>> get >>>>>>>>>>>>> code from a generator. This is a requirement when the >>>>>>>>>>>>> generated code >>>>>>>>>>>>> doesn't >>>>>>>>>>>>> extend the source type (for example for Async interfaces) >>>>>>>>>>>>> but not when >>>>>>>>>>>>> the >>>>>>>>>>>>> genrator is used to add some capabilities (ie acts as a >>>>>>>>>>>>> decorator), >>>>>>>>>>>>> for >>>>>>>>>>>>> example to add PropertyChangeListener to a model bean. >>>>>>>>>>>> >>>>>>>>>>>> Perhaps if you could distill down a more concrete >>>>>>>>>>>> example, it >>>>>>>>>>>> could get >>>>>>>>>>>> the wheels turning. Enhancements to GWT.create() certainly >>>>>>>>>>>> aren't off >>>>>>>>>>>> the >>>>>>>>>>>> table. Ray Cromwell has made some pretty useful-sounding >>>>>>>>>>>> suggestions in >>>>>>>>>>>> the >>>>>>>>>>>> past. We just have to find large-group consensus on what >>>>>>>>>>>> makes the most >>>>>>>>>>>> sense, striking a balance between power, clarity, and of >>>>>>>>>>>> course, >>>>>>>>>>>> optimizability. >>>>>>>>>>>> >>>>>>>>>>>> Here's a quick back-of-envelope pattern that could possibly >>>>>>>>>>>> work: >>>>>>>>>>>> >>>>>>>>>>>> class PersonBean { >>>>>>>>>>>> void setName(String name): >>>>>>>>>>>> String getName(); >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> interface MethodCallLogger { >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> class MyEntryPoint { >>>>>>>>>>>> class PersonBeanWithMethodCallLogger extends PersonBean >>>>>>>>>>>> implements >>>>>>>>>>>> MethodCallLogger { >>>>>>>>>>>> // empty, but a subclass gets generated >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> public void onModuleLoad() { >>>>>>>>>>>> // Have a generate-with rule for >>>>>>>>>>>> MethodCallLoggerGenerator, >>>>>>>>>>>> triggered >>>>>>>>>>>> by assignability to "MethodCallLogger" >>>>>>>>>>>> PersonBean pb = >>>>>>>>>>>> GWT.create(PersonBeanWithMethodCallLogger.class); >>>>>>>>>>>> pb.setName("Nicolas"); >>>>>>>>>>>> } >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> // Generated... >>>>>>>>>>>> class PersonBeanWithMethodCallLoggerImpl extends >>>>>>>>>>>> PersonBeanWithMethodCallLogger { >>>>>>>>>>>> void setName(String name) { >>>>>>>>>>>> someLogger.log("setName('" + name + "') called"); >>>>>>>>>>>> super.setName(name); >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> ... >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> As formulated above, this pattern doesn't compose well. But >>>>>>>>>>>> it might be >>>>>>>>>>>> that we can forge a pattern like this into something >>>>>>>>>>>> everyone >>>>>>>>>>>> likes >>>>>>>>>>>> eventually. >>>>>>>>>>>> >>>>>>>>>>>> -- Bruce >>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> This makes unit testing more difficult as code that uses >>>>>>>>>>>>> GWT.create >>>>>>>>>>>>> cannot run in "classic" jUnit. It would be great to have >>>>>>>>>>>>> the >>>>>>>>>>>>> compiler >>>>>>>>>>>>> use >>>>>>>>>>>>> generator-extended classes even when created using the >>>>>>>>>>>>> standard "new" >>>>>>>>>>>>> keyword. >>>>>>>>>>>>> Thanks a lot for the explanation. >>>>>>>>>>>>> Nicolas >>>>>>>>>>>>> >>>>>>>>>>>>> 2009/4/21 Bruce Johnson <[email protected]> >>>>>>>>>>>>>> >>>>>>>>>>>>>> A sort of philosophical meta-point that may or may not be >>>>>>>>>>>>>> of >>>>>>>>>>>>>> interest... >>>>>>>>>>>>>> >>>>>>>>>>>>>> When we started GWT, we were worried about managing the >>>>>>>>>>>>>> complexity of >>>>>>>>>>>>>> compile-time code generation, so we tried to find the >>>>>>>>>>>>>> simplest, most >>>>>>>>>>>>>> easy-to-debug approach we could think of. GWT's model of >>>>>>>>>>>>>> never >>>>>>>>>>>>>> changing >>>>>>>>>>>>>> existing code[1], but only adding new Java source during >>>>>>>>>>>>>> the compile, >>>>>>>>>>>>>> is >>>>>>>>>>>>>> really a design choice, not a technical limitation. The >>>>>>>>>>>>>> benefit of >>>>>>>>>>>>>> the >>>>>>>>>>>>>> current design is that you can add -gen to hosted mode >>>>>>>>>>>>>> and >>>>>>>>>>>>>> map the >>>>>>>>>>>>>> corresponding folder into your source path, and then >>>>>>>>>>>>>> easily >>>>>>>>>>>>>> step >>>>>>>>>>>>>> through all >>>>>>>>>>>>>> your code, both handwritten and generated, in the >>>>>>>>>>>>>> debugger. >>>>>>>>>>>>>> This >>>>>>>>>>>>>> avoids >>>>>>>>>>>>>> tricky or confusing situations wherein the source code >>>>>>>>>>>>>> you >>>>>>>>>>>>>> see >>>>>>>>>>>>>> appears to be >>>>>>>>>>>>>> doing something different than the bytecode that's >>>>>>>>>>>>>> running. >>>>>>>>>>>>>> It seems >>>>>>>>>>>>>> good to >>>>>>>>>>>>>> avoid that kind of dichotomy, on the principle that >>>>>>>>>>>>>> straightforward-though-verbose is generally better than >>>>>>>>>>>>>> fancy-but-confusing. >>>>>>>>>>>>>> >>>>>>>>>>>>>> [1] Overlay types were the first time we ever even did >>>>>>>>>>>>>> bytecode >>>>>>>>>>>>>> rewriting, and that support is implemented at a very deep >>>>>>>>>>>>>> level. >>>>>>>>>>>>>> Also, JSOs >>>>>>>>>>>>>> are intended to be among only a very few "magic" things >>>>>>>>>>>>>> in >>>>>>>>>>>>>> GWT >>>>>>>>>>>>>> (basically, >>>>>>>>>>>>>> JSNI, GWT.create(), GWT.runAsync(), and JSOs). We went >>>>>>>>>>>>>> to a >>>>>>>>>>>>>> lot of >>>>>>>>>>>>>> effort to >>>>>>>>>>>>>> ensure that JSOs worked according to a fixed set of rules >>>>>>>>>>>>>> that are >>>>>>>>>>>>>> not hard >>>>>>>>>>>>>> to comply with, even if people don't fully understand why >>>>>>>>>>>>>> the >>>>>>>>>>>>>> implementation >>>>>>>>>>>>>> requires it. >>>>>>>>>>>>>> >>>>>>>>>>>>>> On Mon, Apr 20, 2009 at 11:11 AM, Thomas Broyer >>>>>>>>>>>>>> <[email protected] >>>>>>>>>>>>>>> >>>>>>>>>>>>>> wrote: >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> On 20 avr, 08:43, nicolas de loof >>>>>>>>>>>>>>> <[email protected]> wrote: >>>>>>>>>>>>>>>>>> I wonder if there is any way to also "pre-process" >>>>>>>>>>>>>>>>>> Java >>>>>>>>>>>>>>>>>> sources, >>>>>>>>>>>>>>>>>> for >>>>>>>>>>>>>>>>> example >>>>>>>>>>>>>>>>>> this would enable support for Aspect Oriented >>>>>>>>>>>>>>>>>> Programming or >>>>>>>>>>>>>>>>>> maybe some >>>>>>>>>>>>>>>>>> DataBinding framework. >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> Depends what you mean by "pre-process"... Generally, >>>>>>>>>>>>>>>>> generators >>>>>>>>>>>>>>>>> analyze the class they're called for (for example, >>>>>>>>>>>>>>>>> looking for >>>>>>>>>>>>>>>>> specific annotations on methods or on the class >>>>>>>>>>>>>>>>> itself) >>>>>>>>>>>>>>>>> and >>>>>>>>>>>>>>>>> according >>>>>>>>>>>>>>>>> to this generate a Java class extending the one >>>>>>>>>>>>>>>>> they've >>>>>>>>>>>>>>>>> been >>>>>>>>>>>>>>>>> called >>>>>>>>>>>>>>>>> for. >>>>>>>>>>>>>>>>> (is this understandable? is this at least no-so-bad >>>>>>>>>>>>>>>>> english?) >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> In many case the generator will create from MyClassX >>>>>>>>>>>>>>>> some >>>>>>>>>>>>>>>> MyClassXImpl or >>>>>>>>>>>>>>>> equivalent that extends the original one, bu not >>>>>>>>>>>>>>>> REPLACE >>>>>>>>>>>>>>>> it as >>>>>>>>>>>>>>>> Java >>>>>>>>>>>>>>>> source. >>>>>>>>>>>>>>>> This is what I mean by "pre-process". >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> For example, to implement a AOP framework I'd like to >>>>>>>>>>>>>>>> instrument >>>>>>>>>>>>>>>> all >>>>>>>>>>>>>>>> calls >>>>>>>>>>>>>>>> to some method. For this reason I'd like a generator / >>>>>>>>>>>>>>>> pre-processor >>>>>>>>>>>>>>>> to >>>>>>>>>>>>>>>> check the source files and detect the matching >>>>>>>>>>>>>>>> pointcuts >>>>>>>>>>>>>>>> to add >>>>>>>>>>>>>>>> some >>>>>>>>>>>>>>>> adived >>>>>>>>>>>>>>>> code. Many other example can apply, including >>>>>>>>>>>>>>>> annotation >>>>>>>>>>>>>>>> processing >>>>>>>>>>>>>>>> for >>>>>>>>>>>>>>>> declarative coding (ex : @Property annotation to >>>>>>>>>>>>>>>> automagically >>>>>>>>>>>>>>>> introduce the >>>>>>>>>>>>>>>> required PropertyChangeListeners) >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> You would generate a subclass that delegates to >>>>>>>>>>>>>>> super.method() >>>>>>>>>>>>>>> after/ >>>>>>>>>>>>>>> before the aspect(s) code. >>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> I never tried it myself, but I'n not sure a generator >>>>>>>>>>>>>>>> can >>>>>>>>>>>>>>>> REPLACE >>>>>>>>>>>>>>>> the >>>>>>>>>>>>>>>> original Java Source. >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> AFAICT, it can't, but there's probably no need for this. >>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> I may be wrong but I also thing the generated code is >>>>>>>>>>>>>>>> only available when using GWT.create(), >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> The generator is only called at the point where >>>>>>>>>>>>>>> GWT.create() is >>>>>>>>>>>>>>> called >>>>>>>>>>>>>>> (I may be wrong but you could generate a different >>>>>>>>>>>>>>> output >>>>>>>>>>>>>>> for each >>>>>>>>>>>>>>> GWT.create() call-point for the same class literal), so >>>>>>>>>>>>>>> yes, you're >>>>>>>>>>>>>>> right. >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>>>> >>>>>> >>>>> >>>>>> >>>> >>>>> >>>> >>> >>>> >>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>>>> >>>>>> >>>>> >>>>>> >>>> >>>>> >>>> >>> >>>>> >> >> >> >> > > --~--~---------~--~----~------------~-------~--~----~ > http://groups.google.com/group/Google-Web-Toolkit-Contributors > -~----------~----~----~----~------~----~------~--~--- > --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---
