• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content

Loading…

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

Like this presentation? Why not share!

How to build rich web apps with GWT

on

  • 2,401 views

How to build rich web apps with GWT -- Brazil Google Developer Day 2010

How to build rich web apps with GWT -- Brazil Google Developer Day 2010

Statistics

Views

Total Views
2,401
Views on SlideShare
2,401
Embed Views
0

Actions

Likes
2
Downloads
56
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />

How to build rich web apps with GWT How to build rich web apps with GWT Presentation Transcript

  • Google Developer Day 2010
  • How to build rich web apps using Google Web Toolkit Chris Ramsdale, GWT Developer Relations @cramsdale @googledevtools Google Developer Day 2010 Google Developer Day 2010
  • Agenda • GWT Overview • Tools for developers • Optimizations for users Google Developer Day 2010
  • Agenda • GWT Overview • Tools for developpers • Optimizations for users Google Developer Day 2010
  • From 25,000 feet - GWT • Development toolkit, not a framework • Code in Java, run as Javascript • One codebase, any browser • Makes Ajax a piece of cake...and faster • Used within many Google products including Ad Words, Orkut, and hundreds of internal apps Google Developer Day 2010
  • The GWT Family GWTSDK Google Plugin GWT SDK Google Plugin Speed Tracer GWT Designer Speed Tracer GWT Designer For Eclipse For Eclipse Google Developer Day 2010
  • End-to-end Design/ Develop Debug Optimize Google Developer Day 2010
  • End-to-end Design/ Develop Debug Develop Optimize Google Developer Day 2010
  • End-to-end Design/ Develop Debug Develop Debug Optimize Google Developer Day 2010
  • End-to-end Design/ Develop Debug Develop Debug Optimize Optimize Google Developer Day 2010
  • Focus on the users Google Developer Day 2010
  • Focus on the users • Our users - developers - Leverage existing IDEs and tools - Minimize refresh time between codes changes - Automate where possible Google Developer Day 2010
  • Focus on the users • Our users - developers - Leverage existing IDEs and tools - Minimize refresh time between codes changes - Automate where possible • Your users - customers - Minimize startup time - Make it a comfortable experience Google Developer Day 2010
  • Different Goals Google Developer Day 2010
  • Different Goals Developers Next killer feature Making it look good Code refactoring Google Developer Day 2010
  • Different Goals Developers Customers Next killer feature Make it fast Making it look good ...oh, and don’t charge my credit Code refactoring card twice Google Developer Day 2010
  • Different Goals Developers Customers Next killer feature Make it fast Making it look good ...oh, and don’t charge my credit Code refactoring card twice Google Developer Day 2010
  • No plugins required VML Silverlight Flash Google Developer Day 2010
  • Nothing against them, but... Foo Player not available for your device We restrict use of technologies required by products like Foo Player... Google Developer Day 2010
  • Quirkiness Firefox Webkit Opera IE Typical portable 2876 ms 1276 ms 2053 ms 4078 ms setInnerText() textContent=... - 908 ms 1386 ms - innerText=... 2477 ms 918 ms 1520 ms 2469 ms DOM manipulation 7148 ms 1997 ms 4836 ms 14800 ms Improvement 14% 29% 32% 39% Google Developer Day 2010
  • Quirkiness Firefox Webkit Opera IE Typical portable 2876 ms 1276 ms 2053 ms 4078 ms setInnerText() textContent=... - 908 ms 1386 ms - innerText=... 2477 ms 918 ms 1520 ms 2469 ms DOM manipulation 7148 ms 1997 ms 4836 ms 14800 ms Improvement 14% 29% 32% 39% http://quirksmode.org/blog/ Google Developer Day 2010
  • Can you find the bug? function getMax(values) { var maximum = values[0]; for (var i = 0; i < values.length; ++i) { if (values[i] > maximum) { maxinum = values[i]; } } return maximum; } Google Developer Day 2010
  • Our plugin can public int getMax(int values) { int maximum = values[0]; for (int i = 0; i < values.length; ++i) { if (values[i] > maximum) { maxinum = values[i]; } } return maximum; } Java is a static language Google Developer Day 2010
  • Our plugin can public int getMax(int values) { int maximum = values[0]; for (int i = 0; i < values.length; ++i) { if (values[i] > maximum) { maxinum = values[i]; } } return maximum; } Java is a static language Google Developer Day 2010
  • Demo time • To see this in action, let’s - Create a new web app - Debug within the browser - Update, refresh, run Google Developer Day 2010
  • A Java to Javascript compiler right? 16 Google Developer Day 2010
  • Assembly-level JS function rd(a,b){var c;if(b.b){b.b=false;b.c=null}c=b.c;b.c=a.f;try{++a.c;Cd(a.e,b,a.d)}finally{--a.c;a.c==0&&sd(a)}if(c==null) {b.b=true;b.c=null}else{b.c=c}} function Hb(b,c){yb();$wnd.setTimeout(function(){var a=$entry(Eb)(b);a&&$wnd.setTimeout(arguments.callee,c)},c)} function ih(a,b){var c,d;if(b.e!=a){return false}try{Vg(b,null)}finally{c=b.f;(d=(hc(),c).parentNode,(!d||d.nodeType! =1)&&(d=null),d).removeChild(c);ki(a.b,b)}return true} function hj(c){if(c.length==0||c[0]>ao&&c[c.length-1]>ao){return c}var a=c.replace(/^(s*)/,cn);var b=a.replace(/s*$/,cn);return b} function qj(a){var b,c,d,e;b=0;d=a.length;e=d-4;c=0;while(c<e){b=a.charCodeAt(c+3)+31*(a.charCodeAt(c+2)+31*(a.charCodeAt(c +1)+31*(a.charCodeAt(c)+31*b)))|0;c+=4}while(c<d){b=b*31+a.charCodeAt(c++)}return b|0} function Bj(a){var b,c,d,e;e=this.v();a.length<e&&(a=Pd(a,e));d=a;c=this.p();for(b=0;b<e;++b){Ud(d,b,c.s())}a.length>e&&Ud(a,e,null);return a} function xl(a){var b,c,d;a.length<this.c&&(a=(c=a,d=Qd(0,this.c),Sd(c.aC,c.tI,c.qI,d),d));for(b=0;b<this.c;++b) {Ud(a,b,this.b[b])}a.length>this.c&&Ud(a,this.c,null);return a} function Ud(a,b,c){if(c!=null){if(a.qI>0&&!ee(c.tI,a.qI)){throw wi(new ui)}if(a.qI<0&&(c.tM==gm||c.tI==2)){throw wi(new ui)}}return a[b]=c} function hi(a,b,c){var d,e;if(c<0||c>a.c){throw Qi(new Oi)}if(a.c==a.b.length){e=Rd(we,47,8,a.b.length*2,0);for(d=0;d<a.b.length;++d) {Ud(e,d,a.b[d])}a.b=e}++a.c;for(d=a.c-1;d>c;--d){Ud(a.b,d,a.b[d-1])}Ud(a.b,c,b)} function th(b,c){var i;rh();var a,e,f,g,h;e=null;for(h=b.p();h.r();){g=fe(h.s(),8);try{c.q(g)}catch(a){a=Ge(a);if(ie(a,11)){f=a;! e&&(e=Fl(new Dl));i=Sj(e.b,f,e)}else throw a}}if(e){throw sh(new oh,e)}} function Tj(j,a,b,c){var d=j.b[c];if(d){for(var e=0,f=d.length;e<f;++e){var g=d[e];var h=g.y();if(j.x(a,h)){var i=g.z();g.A(b);return i}}}else{d=j.b[c]=[]}var g=Ul(new Sl,a,b);d.push(g);++j.e;return null} function bk(a){var b,c,d;if((a==null?null:a)===this){return true}if(!(a!=null&&de(a.tI,18))){return false}c=fe(a,18);if(c.v()!=this.v()) {return false}for(b=c.p();b.r();){d=b.s();if(!this.u(d)){return false}}return true} function Cd(a,b,c){var d,e,f,g,h,i,j;g=b.j();d=(h=fe(Nj(a.b,g),4),!h?0:h.c);if(c){for(f=d-1;f>=0;--f){e=(i=fe(Nj(a.b,g), 4),fe((Nk(f,i.c),i.b[f]),13));b.i(e)}}else{for(f=0;f<d;++f){e=(j=fe(Nj(a.b,g),4),fe((Nk(f,j.c),j.b[f]),13));b.i(e)}}} function Fb(a){var b,c,d,e,f,g;b=false;d=a.length;f=(new Date).getTime();while((new Date).getTime()-f<100){for(c=0;c<d;++c){g=a[c];if(!g) {continue}if(!g[0].h()){a[c]=null;b=true}}}if(b){e=[];for(c=0;c<d;++c){if(!a[c]){continue}e[e.length]=a[c]}return e}else{return a}} function cf() {cf=gm;af={};bf=[];af[pn]=[lg,kg,mg];af[qn]=[tg,sg];af[rn]=[xg,wg];af[sn]=[Bg,Ag,Cg];_e(bf,se,pn);_e(bf,te,qn);_e(bf,ue,rn);_e(bf,ve,sn)} function Ok(a){var b,c,d,e,f;if((a==null?null:a)===this){return true}if(!(a!=null&&de(a.tI,4))){return false}f=fe(a,4);if(this.v()!=f.c) {return false}d=Vk(new Sk,fe(this,4));e=Vk(new Sk,f);while(d.b<d.c.c){b=Xk(d);c=Xk(e);if(!(b==null?c==null:U(b,c))){return false}}return true} function Sg(a){var b;if(a.c){throw Ni(new Li,Rn)}a.c=true;a.f.__listener=a;b=a.d;a.d=-1;b>0&&(a.d==-1?_f(a.f,b|(a.f.__eventBits||0)):(a.d| =b),undefined);a.l();a.n()} Google Developer Day 2010
  • I can haz pretty print plz Simply adjust the output style of the compiler via the plugin Google Developer Day 2010
  • Yes a Java to JS compiler function init(){ $GreetingService_Proxy(new GreetingService_Proxy); $add_0(($clinit_99() , get_0(null)), $Label(new Label, 'Foo')); $wnd.alert('foo'); } function caught_0(e){ if (e != null && canCast(e.typeId$, 11)) { return e; } return $JavaScriptException(new JavaScriptException, e); } function $RemoteServiceProxy(this$static){ return this$static; } function RemoteServiceProxy(){ } Google Developer Day 2010
  • A deeper dive 20 Google Developer Day 2010
  • Agenda • GWT Overview • Tools for developers • Optimizations for users Google Developer Day 2010
  • From Eclipse to your browser Eclipse Browser Plugins package com.google.gwt.samples.eclipsecon.client; import com.google.gwt.core.client.EntryPoint; Code TCP import com.google.gwt.core.client.GWT; @SuppressWarnings("unused") Server public class EclipseCon implements EntryPoint { public void onModuleLoad() { } Window.alert("foo"); Jetty HTTP } Server 22 Google Developer Day 2010
  • From Eclipse to deployment Your code... Generators Translators Linkers package com.google.gwt.samples.eclipsecon.client; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; @SuppressWarnings("unused") public class EclipseCon implements EntryPoint { public void onModuleLoad() { Window.alert("foo"); } } Google Developer Day 2010
  • From Eclipse to deployment Your code... Generators Translators Linkers package com.google.gwt.samples.eclipsecon.client; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; @SuppressWarnings("unused") public class EclipseCon implements EntryPoint { public void onModuleLoad() { Window.alert("foo"); } } Google Developer Day 2010
  • Generators Provide the power behind your GWT app Automate away boilerplate code Foundation for permutations 25 Google Developer Day 2010
  • Use Case: GWT RPCs Typical Ajax call Serialization Serialization Code Code Client XHR Server Google Developer Day 2010
  • Use Case: GWT RPCs GWT-enabled Ajax Serialization Serialization GWT Proxy GWT Proxy Code Code Client XHR Server Google Developer Day 2010
  • GWT RPCs Define your service (shared code) You write code that looks like this: // Define your service (shared code) @RemoteServiceRelativePath("getSuggestions") @RemoteServiceRelativePath("getSuggestions") public interface SuggestService extends RemoteService { public interface SuggestService extends RemoteService { } String[] getSuggestions(String str); String[] getSuggestions(String str); // Call the service (client code) } public onClick() { SuggestService.getSuggestions(searchTextBox.getText(), new new AsyncCallback<String[]>() { public void onSuccess(String result) { // do great stuff here // } } } Google Developer Day 2010
  • Use Case #2: Creating UIs • Goals - Utilize common dev practices - Minimize boilerplate code - Remove a few other frustrations along the way Google Developer Day 2010
  • Use Case #2: Creating UIs You write code that looks like this: You write code that looks like this: <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"> <ui:style> .contactsViewButtonHPanel { margin: 5px 0px 0x 5px; } </ui:style> <g:HorizontalPanel addStyleNames="{style.contactsViewButtonHPanel}"> <g:Button ui:field="addButton">Add</g:Button> <g:Button ui:field="deleteButton">Delete</g:Button> </g:HorizontalPanel> </ui:UiBinder> Google Developer Day 2010
  • GWT Tips and Tricks -gen will output a copy of the generated classes Google Developer Day 2010
  • From Eclipse to your browser Your code... Generators Translators Linkers package com.google.gwt.samples.eclipsecon.client; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; @SuppressWarnings("unused") public class EclipseCon implements EntryPoint { public void onModuleLoad() { Window.alert("foo"); } } Google Developer Day 2010
  • A Java to Javascript compiler right? 33 Google Developer Day 2010
  • From Eclipse to your browser Your code... Generators Translators Linkers package com.google.gwt.samples.eclipsecon.client; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; @SuppressWarnings("unused") public class EclipseCon implements EntryPoint { public void onModuleLoad() { Window.alert("foo"); } } Google Developer Day 2010
  • Entry points for your GWT app 35 Google Developer Day 2010
  • Permutations Each *.cache.html is a browser and language specific version of the app Google Developer Day 2010
  • Developer time time suck Developer suck Google Developer Day 2010
  • Developer time time suck Developer suck 1. Write some code Google Developer Day 2010
  • Developer time time suck Developer suck 1. Write some code 2. Run it Google Developer Day 2010
  • Developer time time suck Developer suck 1. Write some code 2. Run it 3. Push a few pixels around Google Developer Day 2010
  • Developer time time suck Developer suck 1. Write some code 2. Run it 3. Push a few pixels around 4. Compile Google Developer Day 2010
  • Developer time time suck Developer suck 1. Write some code 2. Run it 3. Push a few pixels around 4. Compile 5. Read XKCD Google Developer Day 2010
  • Developer time time suck Developer suck 1. Write some code 2. Run it 3. Push a few pixels around 4. Compile 5. Read XKCD 6. Debate what color to paint the bikeshed Google Developer Day 2010
  • Developer time time suck Developer suck 1. Write some code 2. Run it 3. Push a few pixels around 4. Compile 5. Read XKCD 6. Debate what color to paint the bikeshed 7. Revel in your accomplishments Google Developer Day 2010
  • Developer time time suck Developer suck 1. Write some code 2. Run it 3. Push a few pixels around 4. Compile 5. Read XKCD 6. Debate what color to paint the bikeshed 7. Revel in your accomplishments Rinse, wash, repeat Google Developer Day 2010
  • Tradeoffs: Speed function rd(a,b){var c;if(b.b){b.b=false;b.c=null}c=b.c;b.c=a.f;try{++a.c;Cd(a.e,b,a.d)}finally{--a.c;a.c==0&&sd(a)}if(c==null) {b.b=true;b.c=null}else{b.c=c}} function Hb(b,c){yb();$wnd.setTimeout(function(){var a=$entry(Eb)(b);a&&$wnd.setTimeout(arguments.callee,c)},c)} function ih(a,b){var c,d;if(b.e!=a){return false}try{Vg(b,null)}finally{c=b.f;(d=(hc(),c).parentNode,(!d||d.nodeType! =1)&&(d=null),d).removeChild(c);ki(a.b,b)}return true} function hj(c){if(c.length==0||c[0]>ao&&c[c.length-1]>ao){return c}var a=c.replace(/^(s*)/,cn);var b=a.replace(/s*$/,cn);return b} function qj(a){var b,c,d,e;b=0;d=a.length;e=d-4;c=0;while(c<e){b=a.charCodeAt(c+3)+31*(a.charCodeAt(c+2)+31*(a.charCodeAt(c +1)+31*(a.charCodeAt(c)+31*b)))|0;c+=4}while(c<d){b=b*31+a.charCodeAt(c++)}return b|0} function Bj(a){var b,c,d,e;e=this.v();a.length<e&&(a=Pd(a,e));d=a;c=this.p();for(b=0;b<e;++b){Ud(d,b,c.s())}a.length>e&&Ud(a,e,null);return a} function xl(a){var b,c,d;a.length<this.c&&(a=(c=a,d=Qd(0,this.c),Sd(c.aC,c.tI,c.qI,d),d));for(b=0;b<this.c;++b) {Ud(a,b,this.b[b])}a.length>this.c&&Ud(a,this.c,null);return a} function Ud(a,b,c){if(c!=null){if(a.qI>0&&!ee(c.tI,a.qI)){throw wi(new ui)}if(a.qI<0&&(c.tM==gm||c.tI==2)){throw wi(new ui)}}return a[b]=c} function hi(a,b,c){var d,e;if(c<0||c>a.c){throw Qi(new Oi)}if(a.c==a.b.length){e=Rd(we,47,8,a.b.length*2,0);for(d=0;d<a.b.length;++d) {Ud(e,d,a.b[d])}a.b=e}++a.c;for(d=a.c-1;d>c;--d){Ud(a.b,d,a.b[d-1])}Ud(a.b,c,b)} function th(b,c){var i;rh();var a,e,f,g,h;e=null;for(h=b.p();h.r();){g=fe(h.s(),8);try{c.q(g)}catch(a){a=Ge(a);if(ie(a,11)){f=a;! e&&(e=Fl(new Dl));i=Sj(e.b,f,e)}else throw a}}if(e){throw sh(new oh,e)}} function Tj(j,a,b,c){var d=j.b[c];if(d){for(var e=0,f=d.length;e<f;++e){var g=d[e];var h=g.y();if(j.x(a,h)){var i=g.z();g.A(b);return i}}}else{d=j.b[c]=[]}var g=Ul(new Sl,a,b);d.push(g);++j.e;return null} function bk(a){var b,c,d;if((a==null?null:a)===this){return true}if(!(a!=null&&de(a.tI,18))){return false}c=fe(a,18);if(c.v()!=this.v()) {return false}for(b=c.p();b.r();){d=b.s();if(!this.u(d)){return false}}return true} function Cd(a,b,c){var d,e,f,g,h,i,j;g=b.j();d=(h=fe(Nj(a.b,g),4),!h?0:h.c);if(c){for(f=d-1;f>=0;--f){e=(i=fe(Nj(a.b,g), 4),fe((Nk(f,i.c),i.b[f]),13));b.i(e)}}else{for(f=0;f<d;++f){e=(j=fe(Nj(a.b,g),4),fe((Nk(f,j.c),j.b[f]),13));b.i(e)}}} function Fb(a){var b,c,d,e,f,g;b=false;d=a.length;f=(new Date).getTime();while((new Date).getTime()-f<100){for(c=0;c<d;++c){g=a[c];if(!g) {continue}if(!g[0].h()){a[c]=null;b=true}}}if(b){e=[];for(c=0;c<d;++c){if(!a[c]){continue}e[e.length]=a[c]}return e}else{return a}} function cf() {cf=gm;af={};bf=[];af[pn]=[lg,kg,mg];af[qn]=[tg,sg];af[rn]=[xg,wg];af[sn]=[Bg,Ag,Cg];_e(bf,se,pn);_e(bf,te,qn);_e(bf,ue,rn);_e(bf,ve,sn)} function Ok(a){var b,c,d,e,f;if((a==null?null:a)===this){return true}if(!(a!=null&&de(a.tI,4))){return false}f=fe(a,4);if(this.v()!=f.c) {return false}d=Vk(new Sk,fe(this,4));e=Vk(new Sk,f);while(d.b<d.c.c){b=Xk(d);c=Xk(e);if(!(b==null?c==null:U(b,c))){return false}}return true} function Sg(a){var b;if(a.c){throw Ni(new Li,Rn)}a.c=true;a.f.__listener=a;b=a.d;a.d=-1;b>0&&(a.d==-1?_f(a.f,b|(a.f.__eventBits||0)):(a.d| =b),undefined);a.l();a.n()} Google Developer Day 2010
  • Trade offs: User experience Each *.cache.html is a browser and language specific version of the app Google Developer Day 2010
  • GWT Tips and Tricks Reduce permutations, reduce compile time myapp.gwt.xml <extend-property name="locale" values="en_US" /> <set-property name="user.agent" value="gecko" /> Now a single permutation targeting US English in Firefox browsers Google Developer Day 2010
  • GWT Tips and Tricks Reduce optimizations, reduce compile time -draftCompile • Skip all optimizations • Development only Google Developer Day 2010
  • GWT Tips and Tricks Reduce optimizations, reduce compile time -draftCompile • Skip all optimizations • Development only Why worry about compiling at all? Google Developer Day 2010
  • A more efficient SDLC Refresh Does it work? Yes Compile No Develop Deploy Google Developer Day 2010
  • We’re happy 43 Google Developer Day 2010
  • But what about our users? 44 Google Developer Day 2010
  • Agenda • GWT Overview • Tools for developers • Optimizations for users Google Developer Day 2010
  • Optimize for the user • Bundle Resources • Split Code Google Developer Day 2010
  • Resource Bundling Example - associating icons with a contact Google Developer Day 2010
  • Resource Bundling One at a time Image image = new Image("images/image1.gif"); image.setHeight("50px"); image.setWidth("50px"); imagesPanel.add(image); Google Developer Day 2010
  • Resource Bundling Initial download Call to display images Google Developer Day 2010
  • Resource Bundling All at once public interface Resources extends ClientBundle { public static final Resources INSTANCE = GWT.create(Resources.class); @Source("Contacts.css") public ContactsCss contactsCss(); @Source("images0.gif") public ImageResource image0(); @Source("images1.gif") public ImageResource image1(); ... } Google Developer Day 2010
  • Resource Bundling Initial download Call to display images Google Developer Day 2010
  • Code splitting Initial download Not needed on startup Google Developer Day 2010
  • Code splitting Split points - runAsync() @UiHandler("showImagesButton") void onOkClicked(ClickEvent event) { GWT.runAsync(new RunAsyncCallback() { public void onSuccess() { showImagesDialog(); } }); } Google Developer Day 2010
  • Code splitting Initial download Call to display images Google Developer Day 2010
  • Recap • Java for front-end development • Tools for large scale applications • Efficient developers • Happy end-users Google Developer Day 2010
  • </presentation> Chris Ramsdale, GWT Developer Relations @cramsdale @googledevtools http://googlewebtoolkit.blogspot.com/ Google Developer Day 2010