<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-198572703290404229</id><updated>2024-08-28T21:23:18.382-07:00</updated><category term="GWT"/><category term="Google Maps"/><category term="Java"/><category term="Programming"/><category term="javascript"/><category term="Drag and drop"/><category term="RPC"/><category term="custom overlayview"/><category term="dom"/><category term="web"/><category term="BCrypt"/><category term="Eclipse Google Plugin"/><category term="Fusion Tables"/><category term="Open Source Software GIS"/><category term="Open Source Software GIS Geography Free List OSGEO"/><category term="Password"/><category term="PlaceHolder"/><category term="Reset"/><category term="Serialization"/><category term="StreetView"/><category term="UiBinder"/><category term="css"/><category term="div"/><category term="errors"/><category term="files"/><category term="float"/><category term="fun"/><category term="performance measurement"/><category term="polygon"/><category term="rating"/><category term="servlets"/><category term="teleport"/><category term="tiles"/><category term="tms"/><category term="upload"/><category term="widget"/><title type='text'>Maps Notes</title><subtitle type='html'>An attempt to produce something with my little head, Google Maps and GWT. A step by step journal.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>23</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-7680594446346723167</id><published>2016-04-14T01:23:00.003-07:00</published><updated>2016-04-14T01:40:39.759-07:00</updated><title type='text'>How to add on demand quicklook projections on Google Maps</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I have been working on our flagship applications &lt;a href=&quot;https://imagery.geocento.com/&quot; target=&quot;_blank&quot;&gt;EarthImages &lt;/a&gt;and &lt;a href=&quot;https://earthimages.geocento.com/&quot; target=&quot;_blank&quot;&gt;EarthImages Pro &lt;/a&gt;for a few years now. EarthImages is an e-commerce web application for Satellite Imagery.&lt;br /&gt;
&lt;br /&gt;
If you search for satellite imagery, it is rather normal that you wish to see the said imagery before you buy it.&lt;br /&gt;
Full satellite images comes in large files, sometimes GBs of data. Of course you cannot show the full res image to a user. The solution is to use thumbnails and quicklooks. Quicklooks are lower res versions of the full image. They are typically 1k pixels wide images. Thumbnails are even lower, generally 100-200 pixels wide.&lt;br /&gt;
Quicklooks and thumbnails are provided by the image suppliers and they come in various formats, sizes and projections.&lt;br /&gt;
&lt;br /&gt;
In EarthImages we want to show these images both as thumbnails and projected quicklooks on the map. Here&#39;s what it looks like for a search around Tunis, Tunisia.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZdUYO1pSkVJU5tFF33NX_mmft5wxy4s8DEthHY4yx-6vbUhS4TMBed1gwMGlIjmYwcbMfxvdYyDiXYdUBj0kvLFmNjnxS0BxYv1509vou3wkjZ8CvKQaPNuR2TjA3HKT9VmP6oNtcoeH5/s1600/tunisiaSearch.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;299&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZdUYO1pSkVJU5tFF33NX_mmft5wxy4s8DEthHY4yx-6vbUhS4TMBed1gwMGlIjmYwcbMfxvdYyDiXYdUBj0kvLFmNjnxS0BxYv1509vou3wkjZ8CvKQaPNuR2TjA3HKT9VmP6oNtcoeH5/s640/tunisiaSearch.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://imagery.geocento.com/#mapviewer:query=r2EZSq9t9gLnEhW8&quot; target=&quot;_blank&quot;&gt;EarthImages search results&lt;/a&gt; for Tunis, Tunisia&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
The challenge is to be able to display the quicklooks on the Google Maps (oh by the way we also do it for &lt;a href=&quot;http://cesiumjs.org/&quot; target=&quot;_blank&quot;&gt;CesiumJs&lt;/a&gt;! but that&#39;s for another blog post).&lt;br /&gt;
&lt;br /&gt;
Our solution: &lt;a href=&quot;http://gdal.org/&quot; target=&quot;_blank&quot;&gt;GDAL &lt;/a&gt;+ &lt;a href=&quot;http://mapserver.org/&quot; target=&quot;_blank&quot;&gt;MapServer&lt;/a&gt;&amp;nbsp;to the rescue!&lt;br /&gt;
&lt;br /&gt;
The basic idea is to georeference the image file, reproject it and store it on the disk as a GTiff so that they can be served by MapServer.&lt;br /&gt;
&lt;br /&gt;
Now there are many twists, including:&lt;br /&gt;
- all suppliers have different types of quicklooks, eg formats are different, projections are different, etc... and of course they are not georeferenced.&lt;br /&gt;
- we have more than 30 millions records in our database of catalogue imagery. Needless to say we cannot generate all projected quicklooks beforehand, it has to be on demand only&lt;br /&gt;
&lt;br /&gt;
Our implementation is a custom WMS service running as a Java servlet. Here are the main steps:&lt;br /&gt;
- user requests overlay of image on the map by clicking on an overlay button&lt;br /&gt;
- browser sends WMS requests with the product ID (the image)&lt;br /&gt;
- servlet checks for existing reprojected quicklook on disk&lt;br /&gt;
- if not existing, it retrieves the image and its parameters, especially the footprint and generates a GDAL script to reproject the image&lt;br /&gt;
- it forwards the call with the quicklook file name to MapServer which then serves the tiles as per user request&lt;br /&gt;
&lt;br /&gt;
The overall process is quite fast. But sometimes quicklooks can be long to load from the supplier&#39;s servers. To provide feedback to the user whilst waiting we implemented this nifty trick:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGlfliTLqNTv69lqsoci1oZ948AKIDSHz2ul73o5zCyIhgO-C7uWjH4FcGO0mohGmy7lqOL0IdBA9KyZUhmq1XSGsbFCwTwiD5xsTnIERq8GUXxFICMtZ4Rq4qF5ZgtZjlxCaDGV4vwIhp/s1600/loadingIndicator.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;151&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGlfliTLqNTv69lqsoci1oZ948AKIDSHz2ul73o5zCyIhgO-C7uWjH4FcGO0mohGmy7lqOL0IdBA9KyZUhmq1XSGsbFCwTwiD5xsTnIERq8GUXxFICMtZ4Rq4qF5ZgtZjlxCaDGV4vwIhp/s320/loadingIndicator.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
This turns out quite easy to implement. All you need is when the user clicks on the overlay button to add an image to the DOM with its source url set to a meaningful WMS query for the image. Make the image element 1px by 1px so it is not visible. Once the image is loaded you remove it from the DOM and change the map overlay indicator to &#39;loaded&#39;, et voila!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/7680594446346723167/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2016/04/on-demand-quicklook-projections-on.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/7680594446346723167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/7680594446346723167'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2016/04/on-demand-quicklook-projections-on.html' title='How to add on demand quicklook projections on Google Maps'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZdUYO1pSkVJU5tFF33NX_mmft5wxy4s8DEthHY4yx-6vbUhS4TMBed1gwMGlIjmYwcbMfxvdYyDiXYdUBj0kvLFmNjnxS0BxYv1509vou3wkjZ8CvKQaPNuR2TjA3HKT9VmP6oNtcoeH5/s72-c/tunisiaSearch.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-6665831218758057420</id><published>2013-12-18T00:55:00.000-08:00</published><updated>2013-12-18T00:59:19.284-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="fun"/><category scheme="http://www.blogger.com/atom/ns#" term="Google Maps"/><category scheme="http://www.blogger.com/atom/ns#" term="StreetView"/><category scheme="http://www.blogger.com/atom/ns#" term="teleport"/><category scheme="http://www.blogger.com/atom/ns#" term="web"/><title type='text'>StreetView Teleport</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I had never really played with the Google StreetView Map API before. A &lt;a href=&quot;http://blogs.wsj.com/digits/2013/12/11/googles-mapped-6-million-miles-of-roads-only-54-million-to-go/&quot;&gt;fascinating article in the NY Times&lt;/a&gt; enticed me to do so. &lt;br /&gt;
&lt;br /&gt;
I love travelling, I guess like pretty much all of us. And like most of us I don&#39;t really have the time to do so!&lt;br /&gt;
What I like most in travelling is the cultural shock, finding differences, changing the routine.&lt;br /&gt;
With this desire in mind I quickly put together a &quot;teleport&quot; application between the main cities of the world (I need to work on the list), so you can navigate a town and decide to randomly teleport yourself to the next town in the list. The contrasts can be quite staggering, eg when you move from NY to, let&#39;s say, some poorer area of Caracas.&lt;br /&gt;
&lt;br /&gt;
The application is available on this &lt;a href=&quot;http://demos.metaaps.com/teleport&quot;&gt;webpage&lt;/a&gt;. I&#39;ll write some explanation later on on the code etc... Nothing difficult.&lt;br /&gt;
&lt;br /&gt;
The application is easy to use. Double click on the Teleport signs in the panorama, you will recognize them!&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/6665831218758057420/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2013/12/streetview-teleport.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/6665831218758057420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/6665831218758057420'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2013/12/streetview-teleport.html' title='StreetView Teleport'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-4693217263307769530</id><published>2013-10-18T01:06:00.001-07:00</published><updated>2013-10-18T01:07:39.358-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GWT"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="PlaceHolder"/><title type='text'>How to add PlaceHolders in GWT</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
The placeholder property is not (yet) supported in GWT. They are however quite a nice UX feature especially if you are running short on space.&lt;br /&gt;
Setting a placeholder is however very simple for compatible browsers:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;java&quot;&gt;widget.getElement().setPropertyString(&quot;placeholder&quot;, message);
&lt;/pre&gt;
&lt;br /&gt;
Of course your widget would have to support placeholders, eg TextBox, PasswordTextBox...
&lt;br /&gt;
You can easily check that with a simple JSNI:
&lt;br /&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot;&gt;public native static boolean isSupported(Element element, String property) /*-{
        return element[property] != undefined;
}-*/;
&lt;/pre&gt;
&lt;br /&gt;
Use your widget and the &quot;placeholder&quot; property name.

&lt;br /&gt;
Things get slightly trickier when you want to support it for less recent browsers like IE9 and before. Then you need some level of programming.

&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;java&quot;&gt;public class TextBox extends com.google.gwt.user.client.ui.TextBox {

 private String message;

 public TextBox() {
 }
 
 public void setPlaceHolder(final String message) {
  this.message = message;
  sinkEvents(Event.ONKEYPRESS);
  sinkEvents(Event.ONBLUR);
  addDomHandler(new BlurHandler() {
    
   @Override
   public void onBlur(BlurEvent event) {
    refreshPlaceHolder();
   }
   }, BlurEvent.getType());
  addDomHandler(new KeyPressHandler() {
    
   @Override
   public void onKeyPress(KeyPressEvent event) {
    if(getStyleName().contains(&quot;placeHolder&quot;)) {
     TextBox.super.setText(&quot;&quot;);
     removeStyleName(&quot;placeHolder&quot;);
    }
   }
  }, KeyPressEvent.getType());
  refreshPlaceHolder();
 }
 
 protected void refreshPlaceHolder() {
  if(getText().length() == 0 &amp;amp;&amp;amp; message != null) {
   super.setText(message);
   addStyleName(&quot;placeHolder&quot;);
  }
 }

 @Override
 public String getText() {
  if(getStyleName().contains(&quot;placeHolder&quot;)) {
   return &quot;&quot;;
  }
  return super.getText();
 }
 
 @Override
 public void setText(String text) {
  super.setText(text);
  // if text is empty, display the placeholder
  refreshPlaceHolder();
 }
 
}

&lt;/pre&gt;
Pretty straightforward, if not text has been entered display some text in the textbox until an actual key is being pressed, in which case remove the placeholder. The trick is to not forget to override the getText and setText methods to make sure you return a sensible value!&lt;br /&gt;
&lt;br /&gt;
This works well for TextBox and TextArea but for PasswordTextBox, things get slightly more complicated. The problem being that the placeholder will appear as hidden characters!&lt;br /&gt;
One way of handling this is to change the type of the field, ie temporarily change it to a TextBox when the placeholder is being displayed.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;java&quot;&gt;public class PasswordTextBox extends com.google.gwt.user.client.ui.PasswordTextBox {

... same as before ...
 
 public void setPlaceHolder(final String message) {

... same as before ...

Changes:

   addDomHandler(new KeyPressHandler() {
    
    @Override
    public void onKeyPress(KeyPressEvent event) {
     if(getStyleName().contains(&quot;placeHolder&quot;)) {
      PasswordTextBox.super.setText(&quot;&quot;);
      removeStyleName(&quot;placeHolder&quot;);
      getElement().setAttribute(&quot;type&quot;, &quot;password&quot;);
     }
    }
   }, KeyPressEvent.getType());

... same as before ...
  }
 }
 
 protected void refreshPlaceHolder() {
  if(getText().length() == 0 &amp;amp;&amp;amp; message != null) {
   super.setText(message);
   addStyleName(&quot;placeHolder&quot;);
Changes:
   getElement().setAttribute(&quot;type&quot;, &quot;text&quot;);
  }
 }
}

&lt;/pre&gt;
&lt;br /&gt;
This works fine for IE9, however if you try it for IE8 and below it won&#39;t work! These browsers won&#39;t allow you to change the input type on the fly. Your only solution is to have a TextBox or Span element on top.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/4693217263307769530/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2013/10/placeholders-in-gwt.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/4693217263307769530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/4693217263307769530'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2013/10/placeholders-in-gwt.html' title='How to add PlaceHolders in GWT'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-9010187931959708624</id><published>2013-07-26T05:52:00.004-07:00</published><updated>2013-07-26T05:53:18.593-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GWT"/><category scheme="http://www.blogger.com/atom/ns#" term="rating"/><category scheme="http://www.blogger.com/atom/ns#" term="widget"/><title type='text'>Super simple GWT rating widget</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Not much to add except some code ;-)&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;public class Rating extends Composite {

 static private StyleResources style = GWT.create(StyleResources.class);
 
 static public interface Presenter {
  void onRatingChanged(int value);
 }
 
 private int rating;
 
 private Presenter presenter;

 private HTMLPanel container;

 public Rating() {
  this(5);
 }

 public Rating(final int starCount) {
  container = new HTMLPanel(&quot;&quot;);
  initWidget(container);
  getElement().getStyle().setDisplay(Display.INLINE_BLOCK);
  getElement().getStyle().setCursor(Cursor.POINTER);
  getElement().getStyle().setPadding(2, Unit.PX);
  for(int index = 0; index &amp;lt; starCount; index++) {
   Image starImage = new Image();
   container.add(starImage);
  }
  setRating(0);
  sinkEvents(Event.ONMOUSEMOVE | Event.ONMOUSEOUT | Event.ONMOUSEDOWN);
  addDomHandler(new MouseMoveHandler() {
   
   @Override
   public void onMouseMove(MouseMoveEvent event) {
    int rating = (int) Math.ceil((double) event.getRelativeX(getElement()) / getOffsetWidth() * starCount);
    displayRating(rating);
   }
  }, MouseMoveEvent.getType());
  addDomHandler(new MouseOutHandler() {
   
   @Override
   public void onMouseOut(MouseOutEvent event) {
    // revert to old value
    displayRating(Rating.this.rating);
   }
  }, MouseOutEvent.getType());
  addDomHandler(new ClickHandler() {
   
   @Override
   public void onClick(ClickEvent event) {
    setRating((int) Math.ceil((double) event.getRelativeX(getElement()) / getOffsetWidth() * starCount));
    if(presenter != null) {
     presenter.onRatingChanged(Rating.this.rating);
    }
   }
  }, ClickEvent.getType());
 }

 protected void displayRating(int rating) {
  int starCounter = 0;
  for(int index = 0; index &amp;lt; container.getWidgetCount(); index++) {
   Widget widget = container.getWidget(index);
   if(widget instanceof Image) {
    ((Image) widget).setResource(starCounter &amp;lt; rating ? style.star() : style.starEmpty());
    widget.getElement().getStyle().setPadding(2, Unit.PX);
    starCounter++;
   }
  }
 }
 
 public void setPresenter(Presenter presenter) {
  this.presenter = presenter;
 }

 public int getRating() {
  return rating;
 }
 
 public void setRating(int rating) {
  this.rating = rating;
  displayRating(rating);
 }
 
}
&lt;/pre&gt;
Of course you should provide a cssresource class of your own to get the stars, or you can use some url or define locally your ImageResource element. It&#39;s all up to you...&lt;br /&gt;
Set the presenter to take action on rating changed.&lt;br /&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/9010187931959708624/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2013/07/super-simple-gwt-rating-widget.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/9010187931959708624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/9010187931959708624'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2013/07/super-simple-gwt-rating-widget.html' title='Super simple GWT rating widget'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-3557125148416324136</id><published>2013-05-19T12:58:00.001-07:00</published><updated>2013-06-04T01:51:24.559-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Google Maps"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="Open Source Software GIS"/><category scheme="http://www.blogger.com/atom/ns#" term="tiles"/><category scheme="http://www.blogger.com/atom/ns#" term="tms"/><title type='text'>Add a TMS layer in Google Maps</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I had to enable TMS layers in Google Maps. Whilst this is very easy in OpenLayers, because it has built in support for it, turns out it requires a couple more lines of code in Google Maps. Here&#39;s some code to do so.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;var TMSLayer = (function() {
function t(map, baseUrlPattern, yFlip, bounds) {
   var _map = map;
   var layer = new gm.ImageMapType({
       getTileUrl: function(coord, zoom){
              var proj = _map.getProjection();
              var zfactor = Math.pow(2, zoom);
              // get Long Lat coordinates
              var swCoord = proj.fromPointToLatLng(new gm.Point(coord.x * 256 / zfactor, (coord.y + 1) * 256 / zfactor));
              var neCoord = proj.fromPointToLatLng(new gm.Point((coord.x + 1) * 256 / zfactor, coord.y * 256 / zfactor));
              if(bounds) {
                    var tileLatLng = new gm.LatLngBounds(swCoord, neCoord);
                    if(!tileLatLng.intersects(bounds)) {
                          return &quot;http://maps.gstatic.com/intl/en_us/mapfiles/transparent.png&quot;;
                    }
              }
              return baseUrlPattern.replace(&quot;$z&quot;, zoom).replace(&quot;$y&quot;, yFlip ? coord.y : (1 &amp;lt;&amp;lt; zoom) - coord.y - 1).replace(&quot;$x&quot;, coord.x);
      },
      tileSize: new gm.Size(256,256),
              isPng:true
      });
      this._map = _map;
      this._layer = layer;
   }
      t.prototype.setVisible = function (visible) {
         var overlayMaps = this._map.overlayMapTypes;
         // find the layer
         for (var i = 0, I = overlayMaps.length; i &amp;lt; I &amp;amp;&amp;amp; overlayMaps.getAt(i) != this._layer; ++i);
         if(visible) {
                 // add if the map was not already added
                 if(i == overlayMaps.length) {
                      overlayMaps.push(this._layer);
                 }
         } else {
                 // remove if the map was added
                 if(i &amp;lt; overlayMaps.length) {
                      overlayMaps.removeAt(i);
                 }
         }
      }
      t.prototype.remove = function() {
            this.setVisible(false);
      }
      t.prototype.setOpacity = function(opacity) {
            if(this._layer) {
                 this._layer.setOpacity(opacity);
            }
      }
      t.prototype.getOpacity = function() {
            if(this._layer) {
                 return this._layer.getOpacity();
            } else {
                 return 1.0;
            }
      }
      t.prototype.setZIndex = function(zIndex) {
            var i = this.getZIndex();
            var overlayMaps = this._map.overlayMapTypes;
            overlayMaps.removeAt(i);
            overlayMaps.insertAt(zIndex, this._layer);
      }
  
      t.prototype.getZIndex = function() {
            var overlayMaps = this._map.overlayMapTypes;
            for (var i = 0, I = overlayMaps.length; i &amp;lt; I &amp;amp;&amp;amp; overlayMaps.getAt(i) != this._layer; ++i);
            return i;
      }
  
   return t;
})();
&lt;/pre&gt;
&lt;br /&gt;
Using the layer is extremly straightfoward, just create the layer passing the google maps object, the base URL pattern, the x/y flip flag and optionally the bounds of the TMS layer. The base URL is the base URL to call for the TMS tiles with the following special characters in the string $z for zoom, $x and $y for the tile number. The x/y flip flag is to say whether the x/y tiling number starts from the top left corner or from the bottom left corner.&lt;br /&gt;
To move the layers up or down, you can use the zindex methods. It will actually move the layer within the overlays array.&lt;br /&gt;
&lt;br /&gt;
An example code:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;// create the layer
var tmsLayer = new TMSLayer(map, &quot;https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/$z/$y/$x&quot;, true);
// you need to set it visible
tmsLayer.setVisible(true);
// set the opacity of the layer
tmsLayer.setOpacity(0.5);
&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/3557125148416324136/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2013/05/add-tms-layer-in-google-maps.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/3557125148416324136'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/3557125148416324136'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2013/05/add-tms-layer-in-google-maps.html' title='Add a TMS layer in Google Maps'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-8569605069694422244</id><published>2013-05-15T01:38:00.001-07:00</published><updated>2013-05-15T01:38:13.278-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="css"/><category scheme="http://www.blogger.com/atom/ns#" term="div"/><category scheme="http://www.blogger.com/atom/ns#" term="float"/><title type='text'>Most mind boggling css trick I am aware of</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
This has to be the most mind boglling css trick I am aware of...&lt;br /&gt;
&lt;br /&gt;
Suppose you have a div that contains floated elements and at the end a &amp;lt;div style=&quot;clear: both;&quot;/&amp;gt; to force the parent div to account for floated elements dimensions and get the right dimensions. This simple trick works fine for me. There are more elegant ways of doing so but I am not that bothered about css optimisation...&lt;br /&gt;
&lt;br /&gt;
Now, if that same div has a floating element in its ascendance tree, it shifts everything down in a seemingly unpredictable manner (looks like it is the height of the floating element though), UNLESS you specify &quot;overflow: hidden;&quot; in the div element...&lt;br /&gt;
&lt;br /&gt;
NOW why is that so? I need to check the w3c specs...&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/8569605069694422244/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2013/05/most-mind-boggling-css-trick-i-am-aware.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/8569605069694422244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/8569605069694422244'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2013/05/most-mind-boggling-css-trick-i-am-aware.html' title='Most mind boggling css trick I am aware of'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-3671709338821654651</id><published>2013-05-15T01:09:00.001-07:00</published><updated>2013-05-15T01:11:16.401-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Google Maps"/><category scheme="http://www.blogger.com/atom/ns#" term="GWT"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><title type='text'>Ruler with elevation</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
I built a simple ruler application, whereby a user can create a multi segment line path and view the total distance, each segment&#39;s length and the elevation along the full path. The path can be edited like any line path, the difference being the measuring information displayed along the path. Of course all this makes heavy use of Google map&#39;s library features: elevation API, geometry library.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjg_OUpTsaHzWJTRuyhPgzYyPZt7XmOZZwCFaH1E5NLGawWrV8-rAkvQ_CJ0uNlbX38MTifkf7uO4VCDL9V9zNllj-O9CyEcQpOXRtN7CL2CBn1ZadxTmIKT8zFFioKJcAB7MjYE3SRDhyp/s1600/Screen+Shot+2013-05-15+at+09.47.55.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;292&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjg_OUpTsaHzWJTRuyhPgzYyPZt7XmOZZwCFaH1E5NLGawWrV8-rAkvQ_CJ0uNlbX38MTifkf7uO4VCDL9V9zNllj-O9CyEcQpOXRtN7CL2CBn1ZadxTmIKT8zFFioKJcAB7MjYE3SRDhyp/s640/Screen+Shot+2013-05-15+at+09.47.55.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
I found it&#39;s first use when checking how far a walking distance was my new house to my daughter&#39;s school ;-) Not sure the elevation is very useful in this case...&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0pT0HRxinBsp1e4wg8xw06RxZLY3drbNgbX-3_cLknelxE3Iu-COjsJwFOlKUoUWbyh15waISPDO1mrlbuj0vFH9eONejMyi_R_iU9skpp8c7xFt_NaIDvZulMjXKLYGwSwexBio6As2c/s1600/Screen+Shot+2013-05-15+at+10.05.08.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;291&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0pT0HRxinBsp1e4wg8xw06RxZLY3drbNgbX-3_cLknelxE3Iu-COjsJwFOlKUoUWbyh15waISPDO1mrlbuj0vFH9eONejMyi_R_iU9skpp8c7xFt_NaIDvZulMjXKLYGwSwexBio6As2c/s640/Screen+Shot+2013-05-15+at+10.05.08.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/3671709338821654651/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2013/05/ruler-with-elevation.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/3671709338821654651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/3671709338821654651'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2013/05/ruler-with-elevation.html' title='Ruler with elevation'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjg_OUpTsaHzWJTRuyhPgzYyPZt7XmOZZwCFaH1E5NLGawWrV8-rAkvQ_CJ0uNlbX38MTifkf7uO4VCDL9V9zNllj-O9CyEcQpOXRtN7CL2CBn1ZadxTmIKT8zFFioKJcAB7MjYE3SRDhyp/s72-c/Screen+Shot+2013-05-15+at+09.47.55.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-6429349356675277196</id><published>2013-01-21T01:07:00.001-08:00</published><updated>2013-01-21T01:27:07.789-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Drag and drop"/><category scheme="http://www.blogger.com/atom/ns#" term="Google Maps"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="polygon"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><title type='text'>Enabling polygon dragging in Google Maps API v3</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Until now, I have used a central marker to provide dragging capability to a surface (Polygon, Circle, etc...) in Google Maps v3, but this time I needed direct drag capability.&lt;br /&gt;
The effect I need is the following: keeping the mouse down on a polygon and moving the mouse around moves the polygon by the equivalent amount, ie the polygon &quot;follows&quot; the mouse.&lt;br /&gt;
&lt;br /&gt;
It turns out to be very easy to implement, simply add the &quot;usual&quot; drag and drop mouse handlers to the polygon and move the polygon by the amount (of lat lng) your mouse has moved.&lt;br /&gt;
There is one trick though: you need to temporarily disable the map drag, otherwise the map will move with your polygon (and therefore the polygon will not move on the map!).&lt;br /&gt;
&lt;br /&gt;
Anyway, here&#39;s a simple code to add drag to your polygon. To use it simply call the setDraggable function with your polygon name.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;function setDraggable(polygon) {
 
 var position = null;
 
 google.maps.event.addListener(polygon, &quot;mousedown&quot;, function(e) {
  if(position == null) {
   position = e.latLng;
   displayDragged(true);
   map.setOptions({draggable: false});
  }
 });
 
 google.maps.event.addListener(polygon, &quot;mouseup&quot;, function(e) {
  position = null;
  displayDragged(false);
  map.setOptions({draggable: true});
 });

 google.maps.event.addListener(polygon, &quot;mouseout&quot;, function(e) {
  position = null;
  displayDragged(false);
  map.setOptions({draggable: true});
 });

 google.maps.event.addListener(polygon, &quot;mousemove&quot;, function(e) {
  if(position != null) {
   shiftStraight(polygon.getPath(), position, e.latLng);
   position = e.latLng;
  }
 });

 // shifts a polygon following from to lat lng values
 function shiftStraight(path, fromLatLng, toLatLng) {
  // calculate shift
     var deltaLat = toLatLng.lat() - fromLatLng.lat();
     var deltaLng = toLatLng.lng() - fromLatLng.lng();
     // update polygon
     var index;
     for(index = 0; index &amp;lt; path.getLength(); index++) {
   var latLng = path.getAt(index);
         var wraps = Math.abs(fromLatLng.lat() + deltaLat) &amp;gt; 90;
         if(wraps) {
          path.setAt(index, new google.maps.LatLng(latLng.lat() + deltaLat, latLng.lng() + deltaLng + 180.0, true));
         } else {
          path.setAt(index, new google.maps.LatLng(latLng.lat() + deltaLat, latLng.lng() + deltaLng));
   }
     }
 }
 
 // update the display of the polygon when dragging or not dragging
 // override this function to add more fancy effects
 function displayDragged(dragged) {
  if(dragged) {
   polygon.setOptions({fillColor: &quot;#fff&quot;});
  } else {
   polygon.setOptions({fillColor: &quot;#f00&quot;});
  }
 }

}

&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/6429349356675277196/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2013/01/enabling-polygon-dragging-in-google.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/6429349356675277196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/6429349356675277196'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2013/01/enabling-polygon-dragging-in-google.html' title='Enabling polygon dragging in Google Maps API v3'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-6778774092947245515</id><published>2013-01-19T14:24:00.003-08:00</published><updated>2013-01-19T14:25:51.385-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="BCrypt"/><category scheme="http://www.blogger.com/atom/ns#" term="GWT"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Password"/><category scheme="http://www.blogger.com/atom/ns#" term="Reset"/><category scheme="http://www.blogger.com/atom/ns#" term="web"/><title type='text'>A good old reset password workflow</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
For my web application, I had to implement a good old reset password functionality - you know the one where you say I forgot my password, etc...&lt;br /&gt;
&lt;br /&gt;
Following a seemingly well established procedure (twitter, facebook, yahoo...), 1) you are requested to provide your your account name (or your email) and a reset link is sent to your email account 2) when clicking on the link you are asked to change the password 3) the password is changed to the new one and you can try to log in again.&lt;br /&gt;
&lt;br /&gt;
I like to reinvent the wheel, but not that much. So I decided to provide and implement the exact same procedure.&lt;br /&gt;
These are my steps for doing so:&lt;br /&gt;
1) I added a &quot;forgot password&quot; link on my sign in page. The link takes the new user to a &quot;reset password&quot; view/activity. &lt;br /&gt;
2) on the page, the user is asked to provide his account name and click a button to request a password reset. When the button is clicked, the account name is sent to the server.&lt;br /&gt;
3) on the server side, the request is received with the user name If the user indeed exists, I generate a very unique and strong token using a free java implementation of &lt;a href=&quot;http://en.wikipedia.org/wiki/Bcrypt&quot;&gt;BCrypt&lt;/a&gt;. I then store a user reset token entity in my database. The user reset token is basically comprised of the user name, the BCrypt generated token and an expiry date.&lt;br /&gt;
4) I send the OK back to the client, which in turns display a message to the user, ie &quot;Password reset request processed, an email was sent to you, etc...&quot;. Concurrently, I send the email to the user ;-), using the email address I have in the database (provided at registration).&lt;br /&gt;
5) The email I send contains a link to the change password view/activity of my application. The link has a resetToken token, which obviously equals the BCrypt token I generated and stored.&lt;br /&gt;
6) The user receives the email I sent and clicks on the link provided. The change password view/activity is opened. Through the interface, the user is requested to provide user name and a new password. When done, the user name and new password are sent back to the server, together with the token included in the link.&lt;br /&gt;
7) on the server side, the database is queried for a user reset token with user name and token value are the ones provided by the client. If the user reset token is found and it is not expired, the password is changed to the new one and all existing user reset token are removed from the database. The server sends the OK back to the client and the client is rerouted to the sign in page of the application.&lt;br /&gt;
&lt;br /&gt;
Et voila! not completely trivial, but quite simple to implement, especially with all the java and GWT goodies available ;-)&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/6778774092947245515/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2013/01/a-good-old-reset-password-workflow.html#comment-form' title='2 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/6778774092947245515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/6778774092947245515'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2013/01/a-good-old-reset-password-workflow.html' title='A good old reset password workflow'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-5577645462287981460</id><published>2013-01-18T04:29:00.001-08:00</published><updated>2013-01-18T04:31:03.297-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Drag and drop"/><category scheme="http://www.blogger.com/atom/ns#" term="files"/><category scheme="http://www.blogger.com/atom/ns#" term="GWT"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="upload"/><title type='text'>A minimalistic implementation of file drag and drop widget for uploading (or more...)</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I have this need to add a drag and drop panel to directly upload files to my web application, without having to go through the sooooo outdated input file select element - you know, gmail like stuff.&lt;br /&gt;
Of course all this has to be done in GWT ;-)&lt;br /&gt;
&lt;br /&gt;
I have found &lt;a href=&quot;https://github.com/laaglu/lib-gwt-file&quot;&gt;some implementation here&lt;/a&gt;, but, in the end and as usual, I decided to implement my own.&lt;br /&gt;
&lt;br /&gt;
I started from the API and &lt;a href=&quot;http://www.sitepoint.com/html5-file-drag-and-drop/&quot;&gt;this blog on a js implementation&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
As I am not a great writer and I don&#39;t have much time for writing neither, here is my code:&lt;br /&gt;
&lt;pre&gt;package com.metaaps.webapps.test.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.event.dom.client.DragEnterEvent;
import com.google.gwt.event.dom.client.DragEnterHandler;
import com.google.gwt.event.dom.client.DragLeaveEvent;
import com.google.gwt.event.dom.client.DragLeaveHandler;
import com.google.gwt.event.dom.client.DragOverEvent;
import com.google.gwt.event.dom.client.DragOverHandler;
import com.google.gwt.event.dom.client.DropEvent;
import com.google.gwt.event.dom.client.DropHandler;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.SimplePanel;

public class DropFilesPanel extends SimplePanel {

 private FileUploadHandler fileUploadHandler = null;
 
 public DropFilesPanel() {
  
  // check file api is supported
  // if not supported simply hides
  if(!fileDragAndDropSupported()) {
   setVisible(false);
   return;
  }
  
  addDomHandler(new DragEnterHandler() {
   
   @Override
   public void onDragEnter(DragEnterEvent event) {
    highlight(true);
   }
  }, DragEnterEvent.getType());
  
  addDomHandler(new DragLeaveHandler() {
   
   @Override
   public void onDragLeave(DragLeaveEvent event) {
    highlight(false);
   }
  }, DragLeaveEvent.getType());
  
  addDomHandler(new DropHandler() {
   
   @Override
   public void onDrop(DropEvent event) {
    // stop default behaviour
    event.preventDefault();
    event.stopPropagation();
    // starts the fetching, reading and callbacks
    if(fileUploadHandler != null) {
     handleFiles(event.getDataTransfer(), fileUploadHandler);
    }
    highlight(false);
   }
  }, DropEvent.getType());
 }
 
        // native method to make use of the HTML5 file API functionality
 private final native void handleFiles(JavaScriptObject dataTransfer, FileUploadHandler fileUploadHandler) /*-{
  var files = dataTransfer.files;
  var i;
  var file;
  var reader = new FileReader();
  for(i = 0; i &amp;lt; files.length; i++) {
   file = files[i];
   if(fileUploadHandler.@com.metaaps.webapps.test.client.FileUploadHandler::checkFileName(Ljava/lang/String;)(file.name)) {
    var type = fileUploadHandler.@com.metaaps.webapps.test.client.FileUploadHandler::specifyFileType()();
    reader.onload = function(e) {
     fileUploadHandler.@com.metaaps.webapps.test.client.FileUploadHandler::handleFileContent(Ljava/lang/String;Ljava/lang/String;)(file.name, e.target.result);
    }
    if(type == &quot;TEXT&quot;) {
     reader.readAsText(file);
    } else if(type == &quot;BINARY&quot;) {
     reader.readAsBinaryString(file);
    } else if(type == &quot;DATAURL&quot;) {
     reader.readAsDataURL(file);
    // not supported
//    } else if(type == &quot;ARRAYBUFFER&quot;) {
//     reader.readAsArrayBuffer(file);
    } else {
    }
   }
  }
 }-*/;

 public void setFileUploadHandler(FileUploadHandler fileUploadHandler) {
  this.fileUploadHandler = fileUploadHandler;
 }

 /*
  * returns true if drag and drop files is supported
  */
 static private final native boolean fileDragAndDropSupported() /*-{
  if((&quot;files&quot; in DataTransfer.prototype) &amp;amp;&amp;amp; $wnd.File &amp;amp;&amp;amp; $wnd.FileReader) {
   return true;
  }
  return false;
 }-*/;
 
 static public boolean isSupported() {
  return fileDragAndDropSupported();
 }

        // hire a great web designer to write some fancy css and provide nice visual feedback to this widget
 protected void highlight(boolean highlighted) {
  // add label for visual feedback
  clear();
  if(highlighted) {
   getElement().getStyle().setBorderColor(&quot;#345&quot;);
   add(new Label(&quot;Drop files to start upload&quot;));
  } else {
   getElement().getStyle().setBorderColor(&quot;transparent&quot;);
  }
 }

 // from jsArrays
 public static String[] toArray(JsArrayString values) {
     if (GWT.isScript()) {
       return reinterpretCast(values);
     } else {
       int length = values.length();
       String[] ret = new String[length];
       for (int i = 0, l = length; i &amp;lt; l; i++) {
         ret[i] = values.get(i);
       }
       return ret;
     }
 }
    
 private static native String[] reinterpretCast(JsArrayString value) /*-{ return value; }-*/;
    
}
&lt;/pre&gt;
&lt;br /&gt;
Overwrite the highlight method if you want to have some fancy effects on enter and leave. Add a DragOver handler as well if you want to provide feedback when a user is hovering above the panel.&lt;br /&gt;
&lt;br /&gt;
To get this working you will need the file upload handler interface:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;package com.metaaps.webapps.test.client;

public interface FileUploadHandler {

 static public enum TYPE {TEXT, BINARY, DATAURL};
 
        // check the filename and extension and return true if you are happy with proceeding
        // returnning false will prevent the file from being read
 boolean checkFileName(String fileName);
 
        // tell the method to use to read this file
 TYPE specifyFileType();
 
        // do your stuff here, eg upload to a server
 void handleFileContent(String fileName, String fileContent);
 
}

&lt;/pre&gt;
&lt;br /&gt;
To test the whole thing working:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;  DropFilesPanel dropPanel = new DropFilesPanel();
  dropPanel.setHeight(&quot;100px&quot;);
  dropPanel.setWidth(&quot;100px&quot;);
  dropPanel.setFileUploadHandler(new FileUploadHandler() {
   
   @Override
   public void handleFileContent(String fileName, String fileContent) {
    Window.alert(fileName + &quot; of size &quot; + fileContent.length());
   }

   @Override
   public boolean checkFileName(String fileName) {
    return true;
   }

   @Override
   public TYPE specifyFileType() {
    return TYPE.BINARY;
   }
   
  });
  RootPanel.get().add(dropPanel);

&lt;/pre&gt;
&lt;br /&gt;
And that&#39;s it ;-) I couldn&#39;t make it shorter...&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/5577645462287981460/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2013/01/minimal-implementation-of-file-drag-and.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/5577645462287981460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/5577645462287981460'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2013/01/minimal-implementation-of-file-drag-and.html' title='A minimalistic implementation of file drag and drop widget for uploading (or more...)'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-7573808020494482143</id><published>2012-11-21T14:06:00.004-08:00</published><updated>2013-01-07T01:34:54.390-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GWT"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><title type='text'>How to write a fading animation in GWT</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
In my own and humble opinion, GWT animation is a great example of the power of a well designed framework. It took me about 10 minutes, starting from this great &lt;a href=&quot;http://petrstepanov.wordpress.com/2011/12/15/gwt-fade-animation-example/&quot;&gt;post&lt;/a&gt;, to build a simple fade in/out animation for a map widget I have.&lt;br /&gt;
&lt;br /&gt;
Here&#39;s the code I wrote:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;import java.math.BigDecimal;

import com.google.gwt.animation.client.Animation;
import com.google.gwt.user.client.Element;

public class FadeAnimation extends Animation {

 private Element element;
 private double opacityIncrement;
 private double targetOpacity;
 private double baseOpacity;

 public FadeAnimation(Element element) {
  this.element = element;
 }
 
 @Override
 protected void onUpdate(double progress) {
  element.getStyle().setOpacity(baseOpacity + progress * opacityIncrement);
 }
 
 @Override
 protected void onComplete() {
  super.onComplete();
  element.getStyle().setOpacity(targetOpacity);
 }
 
 public void fade(int duration, double targetOpacity) {
  if(targetOpacity &amp;gt; 1.0) {
   targetOpacity = 1.0;
  }
  if(targetOpacity &amp;lt; 0.0) {
   targetOpacity = 0.0;
  }
  this.targetOpacity = targetOpacity;
  String opacityStr = element.getStyle().getOpacity();
  try {
   baseOpacity = new BigDecimal(opacityStr).doubleValue();
   opacityIncrement = targetOpacity - baseOpacity;
   run(duration);
  } catch(NumberFormatException e) {
   // set opacity directly
   onComplete();
  }
 }

}

&lt;/pre&gt;
It&#39;s pretty basic to use, here&#39;s an example to fade in or out depending on the mouse entering or leaving a panel.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;final FadeAnimation fadeAnimation = new FadeAnimation(panel.getElement());
panel.addDomHandler(new MouseOverHandler() {
   
 @Override
 public void onMouseOver(MouseOverEvent event) {
  fadeAnimation.fade(1500, 1.0);
 }
}, MouseOverEvent.getType());
  
panel.addDomHandler(new MouseOutHandler() {
   
 @Override
 public void onMouseOut(MouseOutEvent event) {
  fadeAnimation.fade(1500, 0.3);
 }
}, MouseOutEvent.getType());
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/7573808020494482143/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2012/11/fade-animation.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/7573808020494482143'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/7573808020494482143'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2012/11/fade-animation.html' title='How to write a fading animation in GWT'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-635035092924249880</id><published>2012-10-31T04:47:00.001-07:00</published><updated>2012-10-31T04:49:43.483-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GWT"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="performance measurement"/><category scheme="http://www.blogger.com/atom/ns#" term="RPC"/><title type='text'>How to measure server side performance on RPC calls</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;br /&gt;
I needed a quick (and possibly dirty) way to evaluate my rpc call processing time, ie the time it takes to decode, process and generate the output of the request.&lt;br /&gt;
&lt;br /&gt;
Here&#39;s a quick solution, have your RPC service implementation extend the following servlet (instead of directly RemoteServiceServlet):&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:java&quot;&gt;public class MeasuringRemoteService extends RemoteServiceServlet {

 @Override
 public String processCall(String payload) throws SerializationException {
  String[] tokens = payload.split(&quot;\\|&quot;);
  long currentTime = System.currentTimeMillis();
  String output = super.processCall(payload);
  System.out.println(&quot;Call &quot; + tokens[5] + &quot;::&quot; + tokens[6] + &quot; run in &quot; + (System.currentTimeMillis() - currentTime) + &quot;ms&quot;);
  return output;
 }

}

&lt;/pre&gt;
&lt;br /&gt;
This will print the name of the service, the method being called and the time spent in ms. Of course you can do some more fancy things such as store the results in a structured format (database, csv file) for further analysis.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/635035092924249880/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2012/10/how-to-measure-server-side-performance.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/635035092924249880'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/635035092924249880'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2012/10/how-to-measure-server-side-performance.html' title='How to measure server side performance on RPC calls'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-4775762554326842078</id><published>2012-10-25T08:00:00.002-07:00</published><updated>2012-10-25T08:16:11.974-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GWT"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="RPC"/><category scheme="http://www.blogger.com/atom/ns#" term="Serialization"/><category scheme="http://www.blogger.com/atom/ns#" term="servlets"/><title type='text'>How to use the GWT RPC Serialization for plain servlets</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I have a need to use plain Servlets, mainly because I want to be able to do some import/export of files into my application.&lt;br /&gt;
&lt;br /&gt;
Unfortunately it is not possible to do so with the GWT RPC mechanism which is pretty locked up as I found out today. I Googled a bit before going my own way and it appears to be a recurring need. I found two relevant blogs:&lt;br /&gt;
&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;This one, http://mayeur.com/wordpressfr/?p=70, uses the processGet method which can be overriden. I need a POST, so I left that one out.&lt;/li&gt;
&lt;li&gt;And this one, http://softteco.blogspot.com.es/2010/02/serializing-objects-in-gwt-and.html, which is what I tried.&lt;/li&gt;
&lt;/ol&gt;
The issue as one reader commented, is that the deserialization won&#39;t work because it is missing access to a serialization policy that includes the types being serialized.&lt;br /&gt;
Getting a hand on the serialization policies is actually not a simple as one would have thought. There is one per service and all of them are kept in a static HashMap field of RemoteServiceServlet. To retrieve the serialization policy you need the key, which is basically the name of the serialization file stored on the server. This key bears the name of &quot;strongName&quot;, which I must admit I have no explanation for such a name ;-)&lt;br /&gt;
Now bear with me a bit more, strongName is apparently an MD5 hash of the file content. This means that the name will change each time the service is modified. In the standard RPC mechanism, the strongName is embedded by the client call in the request. Unfortunately there is no method for accessing this value on the client side. So we are back to square one...&lt;br /&gt;
&lt;br /&gt;
Back to the main issue, we need to get a hand on a relevant Serialization policy (ie one that includes the types being serialized by our Servlet).&lt;br /&gt;
After a couple of hours of going in circles, the way I did this is as follows:&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;find the relevant RPC service. If you have no suitable service, create a dummy one.&lt;/li&gt;
&lt;li&gt;override the doGetSerializationPolicy and store the serialization policy into a field that will be accessible from another servlet. You will have to copy paste the static loadSerializationPolicy method from the RemoteServiceServlet as well.&lt;/li&gt;
&lt;li&gt;Now in your servlet code you can use the following code to deserialize your data
&lt;pre class=&quot;brush:java&quot;&gt;ServerSerializationStreamReader streamReader = new ServerSerializationStreamReader(Thread.currentThread().getContextClassLoader(), new SerializationPolicyProvider() {
     
 @Override
 public SerializationPolicy getSerializationPolicy(String moduleBaseURL, String serializationPolicyStrongName) {
  return YOUR_RemoteServiceServlet.getSerializationPolicy();
 }
});
// Filling stream reader with data
streamReader.prepareToRead(YOUR_serialized_string);
// now you can start reading your objects

&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&amp;nbsp;On the client side you will have to create a serialization as follows (as explained in the second blog):
&lt;pre class=&quot;brush:java&quot;&gt; public String serialize(Serializable serializable) throws SerializationException {
  // Creating stream writer
  SerializationStreamWriter writer = ((SerializationStreamFactory) YOUR_ClientRemoteService).createStreamWriter();
  // Serializing object
  writer.writeObject(serializable);
  // Getting serialized object content
  return writer.toString();
 }
&lt;/pre&gt;
&lt;/li&gt;
&amp;nbsp; &lt;/ol&gt;

And that&#39;s it, with those small add ons you can serialize/deserialize any serializable types you have in your GWT application.
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/4775762554326842078/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2012/10/tricking-rpc-to-use-gwt-serialization.html#comment-form' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/4775762554326842078'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/4775762554326842078'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2012/10/tricking-rpc-to-use-gwt-serialization.html' title='How to use the GWT RPC Serialization for plain servlets'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-3436094174929013554</id><published>2012-07-14T01:59:00.001-07:00</published><updated>2012-07-14T01:59:44.802-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Eclipse Google Plugin"/><category scheme="http://www.blogger.com/atom/ns#" term="GWT"/><category scheme="http://www.blogger.com/atom/ns#" term="UiBinder"/><title type='text'>MVP and UiBinder, small tricks for Eclipse users</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I recently discovered a few tricks to speed up code development in Eclipse. As always once you know them, you wonder how you could have lived without them! Here are a couple of them.&lt;br /&gt;
&lt;br /&gt;
1) auto generate MVP files. Generating the full MVP files for an activity can be quite a bit of (repetitive work), ie Place, Activity, Views, etc... Until recently my Google GWT menus were limited to the &quot;right click in the package explorer &amp;gt; new &amp;gt; uibinder, module, etc...&quot;. It&#39;s with great pleasure that I discovered this hidden gem, right click any tree item of the package explorer &amp;gt; Google Web Toolkit &amp;gt; MVP View. This will open a dialog with all fields required to configure your MVP files, such as Places and Activity. You can even link to your client factory!&lt;br /&gt;
&lt;br /&gt;
2) auto generate your inclusion tag in uibinder. Let&#39;s say you want to add a widget that is outside of the default included GWT package (user widget), eg a celltable or some of your own widgets. Before (what a fool I was), I would manually enter the xml tag of the widget package I needed. No need, just type &quot;&amp;lt;&quot; and start away with your widget name. Auto completion kicks in, choose you widget, and voila! The tag is automagically added!&lt;br /&gt;
&lt;br /&gt;
The trick I have not found so far and that would really save me a lot of time, is automatic generation of @UiField in the java counterpart of the uibinder xml file. It would work somehow like the eclipse JDT Source menu, eg generate setter and getters. It would also include the possibility to generate UiHandlers as well. That would be VERY neat.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/3436094174929013554/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2012/07/mvp-and-uibinder-small-tricks-for.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/3436094174929013554'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/3436094174929013554'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2012/07/mvp-and-uibinder-small-tricks-for.html' title='MVP and UiBinder, small tricks for Eclipse users'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-8121043681001186858</id><published>2012-07-12T01:52:00.001-07:00</published><updated>2012-07-14T01:40:26.039-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Google Maps"/><category scheme="http://www.blogger.com/atom/ns#" term="GWT"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><title type='text'>Google Maps and GWT performance live up to my expectations</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I am working on a customer web application through my company in Madrid.&lt;br /&gt;
&lt;br /&gt;
The purpose of the application is to enable customers of the client company to search for past and future Satellite Imagery, create orders and follow up orders. The client company is also interested in using the application to manage their customer orders. In other words, it&#39;s an eCommerce web site for Satellite Earth Imagery.&lt;br /&gt;
&lt;br /&gt;
Point is, when you search for archive imagery, that is to say imagery that has already been acquired and is stored on the company&#39;s servers, ie the archives, the amount of images returned can be very large.&lt;br /&gt;
It is not actually images that are sent back, but rather product descriptions - the actual images can be several GB in size. A product description&amp;nbsp;includes metadata information, eg acquisition times, sensors and sensors characteristics and the contour of the image as a polygon. Some product also come with a Url to available image browses (thumbnails), which I need to display in a maps popup window.&lt;br /&gt;
The product description data matching a user request is sent back to the web application in xml format. Depending on the request made the xml can be very large (MB) and include many products, therefore many polygons.&lt;br /&gt;
&lt;br /&gt;
The web application is developed with GWT and relies on Google Maps v3 to display the map features. Below you can see an overview of the main page.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbYrUjGCQ4Fk0q4sWViTT2KvenOK5LBzDnwVUDUy1PWSEhe7TJhcqZAY_2GnjolbHd2ngAQ4C_6uPjANI5Kx90C0uMVToNUr1BCjcj3kt9VwsnCFx65PEGKUTCQ_K9iLzINWA1okvFV-3T/s1600/webapp+map+problem.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;322&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbYrUjGCQ4Fk0q4sWViTT2KvenOK5LBzDnwVUDUy1PWSEhe7TJhcqZAY_2GnjolbHd2ngAQ4C_6uPjANI5Kx90C0uMVToNUr1BCjcj3kt9VwsnCFx65PEGKUTCQ_K9iLzINWA1okvFV-3T/s640/webapp+map+problem.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
It is built with pure GWT, no external library, and I even had to make my own JSNI port to my map layer on top of the Google Maps v3 API.&lt;br /&gt;
&lt;br /&gt;
I can&#39;t say it has been an easy ride, but the functionality is mostly there now. I will try to write some blog posts on the few &quot;tricks&quot; I learned along the way.&lt;br /&gt;
&lt;br /&gt;
I was pleasantly surprised to see that the processing speed when large data volumes are sent back from a request. My XML parsing is far from optimal I believe, which leads me to believe that the produced GWT code is really efficient. &amp;nbsp;Also Google Maps v3 appears to handle very well large amounts of polygons as you can see on the picture, about 2700 polygons were added to the map, zooming and panning work well on Chrome and Firefox. Also the DataGrid is very fluid. Don&#39;t pay too much attention to the data in the picture, many fields were actually missing from the input data. Sorting is fast and paging too. I also have coupled the map polygons with the product in the list so that when one is selected the other is too (with automatic scroll in the list), all this works fast and well using custom events and the GWT event bus.&lt;br /&gt;
&lt;br /&gt;
Conclusions: thanks Google for two really neat products :)&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/8121043681001186858/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2012/07/google-maps-and-gwt-performance-live-up.html#comment-form' title='2 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/8121043681001186858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/8121043681001186858'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2012/07/google-maps-and-gwt-performance-live-up.html' title='Google Maps and GWT performance live up to my expectations'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbYrUjGCQ4Fk0q4sWViTT2KvenOK5LBzDnwVUDUy1PWSEhe7TJhcqZAY_2GnjolbHd2ngAQ4C_6uPjANI5Kx90C0uMVToNUr1BCjcj3kt9VwsnCFx65PEGKUTCQ_K9iLzINWA1okvFV-3T/s72-c/webapp+map+problem.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-8892106301286902785</id><published>2012-03-26T06:15:00.001-07:00</published><updated>2012-03-26T06:16:17.111-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="errors"/><category scheme="http://www.blogger.com/atom/ns#" term="GWT"/><title type='text'>GWT &quot;ghost&quot; errors</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I had this freaky bang your head against the wall compilation error with my GWT Eclipse project.&lt;br /&gt;
Some issues in a library project I use with JSNI and reusing interfaces, which is not allowed unfortunately. However I removed the issue by not including the offending module in the project. But the compilation error persists and it references code that just does not exists anymore (hence the ghost thing in my title)!&lt;br /&gt;
I did what a man (or woman) with experience will do: switch on and off the TV.&lt;br /&gt;
But, alas, even after restarting Eclipse (I did not reboot the computer), the issue was still there.&lt;br /&gt;
Turns out GWT keeps some cached code in a directory called gwt-unitCache, right below the war file, so normally at the root of your project&#39;s directory.&lt;br /&gt;
I deleted those files, recompiled and voila!&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/8892106301286902785/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2012/03/gwt-ghost-errors.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/8892106301286902785'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/8892106301286902785'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2012/03/gwt-ghost-errors.html' title='GWT &quot;ghost&quot; errors'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-6540036272396641419</id><published>2012-03-08T04:09:00.003-08:00</published><updated>2012-03-26T06:15:59.795-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="custom overlayview"/><category scheme="http://www.blogger.com/atom/ns#" term="dom"/><category scheme="http://www.blogger.com/atom/ns#" term="Google Maps"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><title type='text'>Display map coordinates</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Here is another small trick. I need to display the mouse position as a (lat, long) value. I went to the samples and found the latlng-to-coord-control example.&lt;br /&gt;
&lt;br /&gt;
Works fine as long as your mousemove map events are not intercepted by a marker or an overlay.&lt;br /&gt;
&lt;br /&gt;
So I had to modify a bit, here&#39;s my solution:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:javascript&quot;&gt;// dummy overlay from http://code.google.com/p/gmaps-api-issues/issues/detail?id=2879
DummyOverlay.prototype = new google.maps.OverlayView;
DummyOverlay.prototype.onAdd = function(){}
DummyOverlay.prototype.onRemove = function(){}
DummyOverlay.prototype.draw = function(){ };
function DummyOverlay(map) {this.setMap(map);}

function projectionHack(map)
{
        if(map.dummyCanvas == null)
        {
                map.dummyCanvas = new DummyOverlay(map);
                map.getMapCanvasProjection = function() {return this.dummyCanvas.getProjection()}
        }
}

function latLngOverlay(map) {
    var div = document.createElement(&#39;DIV&#39;);
    div.className = &quot;ei-latLngOverlay&quot;;
    this.div_ = div;
    map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(this.div_);
    function findPos(obj) {
        var curleft = 0;
        var curtop = 0;
        if (obj.offsetParent) {
            do {
                curleft += obj.offsetLeft;
                curtop += obj.offsetTop;
            } while (obj = obj.offsetParent);
        }
        return {x: curleft, y:curtop};
    }

    var mapDiv = map.getDiv();
    projectionHack(map);
    google.maps.event.addDomListener(mapDiv, &quot;mousemove&quot;, function(event) {
        var offset = findPos(mapDiv);
        var latLng = map.getMapCanvasProjection().fromContainerPixelToLatLng(new google.maps.Point(event.clientX - offset.x, event.clientY - offset.y));
        div.innerHTML = &quot;Position: &quot; + latLng.toUrlValue(4);
      });
}

latLngOverlay.prototype.show = function() {
  this.div_.style.display = &#39;block&#39;;
}

latLngOverlay.prototype.hide = function() {
    this.div_.style.display = &#39;none&#39;;
}

&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
The DummyOverlayView is needed to get the map projections for the div and be able to make the projection on the fly. You can see the discussions at&amp;nbsp;http://code.google.com/p/gmaps-api-issues/issues/detail?id=2879&lt;br /&gt;
&lt;br /&gt;
I checked it out with the following webpage&amp;nbsp;&lt;a href=&quot;http://www.thegpscoordinates.com/spain/madrid/&quot;&gt;http://www.thegpscoordinates.com/spain/madrid/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/6540036272396641419/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2012/03/here-is-another-small-trick.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/6540036272396641419'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/6540036272396641419'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2012/03/here-is-another-small-trick.html' title='Display map coordinates'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-3639015853082958224</id><published>2012-01-30T11:16:00.000-08:00</published><updated>2012-03-08T03:34:33.575-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="custom overlayview"/><category scheme="http://www.blogger.com/atom/ns#" term="dom"/><category scheme="http://www.blogger.com/atom/ns#" term="Google Maps"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><title type='text'>Adding a glass panel to capture events on my Google Maps map</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
OK, this one got me sweating so I thought I put it online. Also because I found many fellow coders left stranded with a similar problem.&lt;br /&gt;
&lt;br /&gt;
I developed my own library to add and edit shapes to the google maps v3. When you hover above the shapes a nice little tooltip gives you instructions as to what you can do with the shape. Problem is when creating new shapes, the tooltip captures the map events. As a consequence I cannot add any points to my shape if they are above an existing shape... rather annoying. So I thought I could add a glass panel on top to capture all map events before they get to the underlying overlays. Simple no?&lt;br /&gt;
&lt;br /&gt;
Well, without further ado, here&#39;s the code, the explanation follows:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:javascript&quot;&gt;function glassOverlay(map) {
    this.div_ = null;
    this.map = map;
    this.eventsListener = [];
    this.setMap(map);
  }

glassOverlay.prototype = new google.maps.OverlayView();

glassOverlay.prototype.onAdd = function() {
    if(this.div_ == null) {
          var div = document.createElement(&#39;DIV&#39;);
          div.style.border = &quot;transparent&quot;;
          div.style.background = &quot;transparent&quot;;
          div.style.position = &quot;absolute&quot;;
          div.style.top = &quot;0px&quot;;
          div.style.left = &quot;0px&quot;;
          // default positioning
          div.style.width = &quot;300px&quot;;
          div.style.height = &quot;300px&quot;;
          this.div_ = div;

          // We add an overlay to a map via one of the map&#39;s panes.
          // We&#39;ll add this overlay to the overlayImage pane.
          var panes = this.getPanes();
          panes.overlayMouseTarget.appendChild(div);

          // initialise the handlers
          var type;
          for(type in this.eventsListener) {
                  var callback = this.eventsListener[type];
                  if(typeof callback == &quot;function&quot;) {
                                this._addEventListener(type, callback);
                  }
          }
    }
    var self = this;
    google.maps.event.addListener(this.map, &quot;dragend&quot;, function() {self.draw()});
}

glassOverlay.prototype.draw = function() {
    var bounds = this.getMap().getBounds();
    var projection = this.getProjection();
    var topRight = projection.fromLatLngToDivPixel(bounds.getNorthEast());
    var bottomLeft = projection.fromLatLngToDivPixel(bounds.getSouthWest());
    // resize the div to take up the whole map area
    this.div_.style.width = Math.round(topRight.x - bottomLeft.x) + &quot;px&quot;;
    this.div_.style.height = Math.round(bottomLeft.y - topRight.y) + &quot;px&quot;;
    this.div_.style.left = bottomLeft.x;
    this.div_.style.top = topRight.y;
}

function findPos(obj) {
    var curleft = 0;
    var curtop = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
    }
    return {x: curleft, y:curtop};
}

glassOverlay.prototype.addEventListener = function(type, callback) {
    // if overlay has been initialised
    if(this.div_ != null) {
            this._addEventListener(type, callback);
    } else {
            // else store th callback for the add function
            this.eventsListener[type] = callback;
    }
}

glassOverlay.prototype._addEventListener = function(type, callback) {
    var me = this;
    google.maps.event.addDomListener(this.div_, type, function(event) {
            google.maps.event.trigger(me, type, event);
    });
    function cancelEvent(e) {
        e.cancelBubble = true;
        if (e.stopPropagation) e.stopPropagation();
    }
    var projection = this.getProjection();
    google.maps.event.addListener(me, type, function(event) {
        var offset = findPos(me.div_);
        callback({
                latLng: projection.fromContainerPixelToLatLng(new google.maps.Point(event.clientX - offset.x, event.clientY - offset.y))
        });
        cancelEvent(event);
    });
}

glassOverlay.prototype.onRemove = function() {
 this.div_.parentNode.removeChild(this.div_);
 this.div_ = null;
}

&lt;/pre&gt;
&lt;br /&gt;
First you need an OverlayView and add it to the OverlayMouseTarget panel, which is one of the top most panels. This is done at the onAdd level, one of the three methods, with onRemove and draw, you need to implement for a custom OverlayView. The OnAdd method adds a div element to the window. You&#39;d want to set the div to cover the full screen, however this is not possible statically as the map can be paned and zoomed. The div position needs updating on each of these map event. The draw method is called when the zoom level has changed and &quot;sometimes&quot; when the map has paned (this is what cost me the most time). To make sure the draw method is called any time we pan, we add a dragend event listener to the map.&lt;br /&gt;
&lt;br /&gt;
The draw method needs to set the div position and dimensions so that it always cover the full zone of the map. For this we use the current bounds of the map and convert the bounds to points with the overlay&#39;s projection. This gives us the right width, height and top and left position within the map container.&lt;br /&gt;
&lt;br /&gt;
Next we will want to handle events with the overlay. For this we add a dom listener via the map api. The dom listener will receive the standard DOM Mouse events, unfortunately not the nice google maps events with lat, lng coordinates of the point where the click event&amp;nbsp;occurred. So we have to work the mechanics. For this we use the standard clientX and clientY mouse event coordinates and realign them using the div&#39;s position in the screen. Retrieving the equivalent lat lng coordinates in the map is straightforward with the use of the&amp;nbsp;projection.fromContainerPixelToLatLng method. The newly formatted event is passed to the event listener and voila!&lt;br /&gt;
&lt;br /&gt;
The findpos function comes form this &lt;a href=&quot;http://www.quirksmode.org/js/findpos.html&quot;&gt;post&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
OK that was a bit quick, if there are any parts that you would like further explanations on, please let me know!&lt;br /&gt;
&lt;br /&gt;
EDIT: sometimes solutions are way more simple than anticipated. I replaced this whole heavy mechanics, that didn&#39;t work very well at low zooms by the way, by a transparent Rectangle overlay spanning the whole globe!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/3639015853082958224/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2012/01/ok-this-one-got-me-sweating-so-i.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/3639015853082958224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/3639015853082958224'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2012/01/ok-this-one-got-me-sweating-so-i.html' title='Adding a glass panel to capture events on my Google Maps map'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-3825055664202054133</id><published>2011-09-08T06:52:00.000-07:00</published><updated>2011-09-08T06:52:57.401-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Open Source Software GIS Geography Free List OSGEO"/><title type='text'>Open Source GIS software</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;I am subscribed to the osgeo anouncements. They do send an email every 3 months so it&#39;s really not much work to go through as well each of them is of great interest. The latest is on a new DVD release that contains a great deal of excellent GIS OS SW. I am going to quote&amp;nbsp;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace; white-space: pre-wrap;&quot;&gt;Frank Warmerdam on this:&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre wrap=&quot;&quot;&gt;Highlights
    * 47 Quality GeoSpatial Open Source applications installed
      and pre-configured
    * Quality free world maps
    * One page overviews and quick starts for all applications
    * Overviews of key OGC standards
    * Translations for Greek, German, Polish, Spanish and Japanese


Contents

   Browser Clients
    * OpenLayers 2.10 - Browser GIS Client
    * Geomajas - 1.8 Browser GIS Client
    * Mapbender 2.7.2 - Geoportal Framework
    * MapFish 2.2 - Web Mapping Framework
    * GeoMoose 2.4 - Web GIS Portal

   Crisis Management
    * Sahana Eden 0.5.5 - Disaster management
    * Ushahidi 2.1 - Mapping and Timeline for events

   Databases
    * PostGIS 1.5 - Spatial Database
    * SpatiaLite 2.3.1 / 2.4 beta - Lightweight Database
    * Rasdaman 8.2 - Multi-Dimensional Raster Database
    * pgRouting 1.05 - Routing for PostGIS

   Desktop GIS
    * Quantum GIS (QGIS) 1.7.0
    * GRASS GIS 6.4.1
    * gvSIG Desktop 1.11
    * User-friendly Desktop Internet GIS (uDig) 1.2.2
    * Kosmo Desktop 2.0.1
    * OpenJUMP GIS 1.4.0.1
    * SAGA 2.0.7
    * OSSIM 1.8.6 - Image Processing
    * Geopublisher 1.7 - Catalogue
    * AtlasStyler 1.7 - Style Editor
    * osgEarth 2.0 - 3D Terrain Rendering

   Navigation and Maps
    * GpsDrive 2.11 - GPS Navigation
    * Marble 1.0.2 - Spinning Globe
    * OpenCPN 2.5.0 - Marine GPS Chartplotter
    * OpenStreetMap Tools - JOSM, Merkaartor, Gosmore, Osmarender
    * Prune 12 - View, Edit and Convert GPS Tracks
    * Viking 9.9.94 - GPS Data Analysis and Viewer
    * zyGrib 5.0 - Weather Forecast Maps

   Spatial Tools
    * GeoKettle 2.0-RC1 - ETL (Extract, Transform and Load) Tool
    * GDAL/OGR 1.8.0 - GeoSpatial Data Translation Tools
    * GMT 4.5.2 - Cartographic Rendering
    * Mapnik 0.7.1 - Cartographic Rendering
    * MapTiler 1.0beta2 - Create Map Tiles
    * OTB 3.10 - Image Processing
    * R Spatial Task View 2.12.1 - Statistical Programming

   Web Services
    * GeoServer 2.1.1
    * MapServer 6.0.1
    * deegree 3.0
    * GeoNetwork 2.6.4 - Metadata Catalog and Catalog Services for Web
    * MapProxy 1.1.1 - Proxy WMS &amp;amp;amp; tile services
    * QGIS Server 1.7.0 - Web Map Service
    * 52°North WSS 2.2.0 - Web Security Service
    * 52°North WPS - 2.0 RC6 - Web Processing Service
    * 52°North SOS - 3.2.0 Sensor Observation Service
    * TinyOWS 1.0 - WFS-T Service
    * ZOO Project 1.0.0 - Web Processing Service

   Data
    * Natural Earth 1.3.1 - Geographic Data Sets
    * OSGeo&#39;s North Carolina, USA Educational dataset
    * OpenStreetMap - Sample extract from OpenStreetMap

   Geospatial Libraries
    * GeoTools - Java GIS Toolkit
    * MetaCRS - Coordinate Reference System Transformations
    * libLAS - LiDAR Data Access
&lt;/pre&gt;&lt;pre wrap=&quot;&quot;&gt;&lt;/pre&gt;&lt;pre wrap=&quot;&quot;&gt;I thought I&#39;d copy-post it. It&#39;s a great reference list to start from if you are new to this side of the world.&lt;/pre&gt;&lt;pre wrap=&quot;&quot;&gt;&lt;/pre&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/3825055664202054133/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2011/09/open-source-gis-software.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/3825055664202054133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/3825055664202054133'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2011/09/open-source-gis-software.html' title='Open Source GIS software'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-1429714745805144691</id><published>2011-02-08T11:05:00.000-08:00</published><updated>2011-02-08T11:24:56.187-08:00</updated><title type='text'>Sorry, No GWT</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;I can&#39;t say I haven&#39;t tried though. After multiple attempts I gave up using GWT, but learned a couple of things along the way.&lt;br /&gt;
I gave up, mostly because the Map v3 API is not available yet. There are a couple of projects out there but they are on a standstill (alongside rumours of an official port under the &lt;a href=&quot;http://code.google.com/p/gwt-google-apis/&quot;&gt;google api project&lt;/a&gt;).&lt;br /&gt;
Still, the experience is worth a little post. Just let me know where I got it wrong.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;I am a relative newbie to GWT. I adopted it quickly though. Mostly because it scales well compared to javascript, no matter which framework you use (I use the excellent jQuery BTW).&lt;br /&gt;
To compare GWT and JS developments, I would use the following diagram:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYFo1epSjJ_A0t0Bt6K9mZdzMRZcomaLEALhqoIv29KjbAfi-ReQaDp-YhaXWEhXr_cTHsPY4PI3J_fDbWN1wBY-m4bFd0X5c20RR6kGEBX1UTcxoFD4gicwaCuNrMvICZ29q_VoSIqsbd/s1600/GWT-JS.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;232&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYFo1epSjJ_A0t0Bt6K9mZdzMRZcomaLEALhqoIv29KjbAfi-ReQaDp-YhaXWEhXr_cTHsPY4PI3J_fDbWN1wBY-m4bFd0X5c20RR6kGEBX1UTcxoFD4gicwaCuNrMvICZ29q_VoSIqsbd/s320/GWT-JS.gif&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
This is no scientific work, just my impressions and my personal experience. Notice how I conveniently forgot to put any tick marks on my axis ;-)? I can&#39;t tell you when the two curves meet, and therefore when you should start using GWT, but they meet. I guess it is down to you, your ability with both languages, the IDE you use, how organised you are, etc...&lt;br /&gt;
I am actually equally at ease (or not) with both languages. My explanation for such curves is mostly down to the language characteristics. The use of the Java language in GWT and the many integrated features you get in an Java IDE, eg refactoring, type checking, etc... certainly account for a lot. Conversely, the flexibility of javascript is fantastic, and most efficient when it comes to quickly build a bit of functionality. To make a bold comparison, I would say it&#39;s like building a house or building a skyscraper. You certainly wouldn&#39;t use the same techniques.&lt;br /&gt;
&lt;br /&gt;
Anyway, for the ones that haven&#39;t followed, the idea is to create an animated Map widget with GWT.&lt;br /&gt;
I started looking into how you would do that, starting with &lt;i&gt;&quot;how to expose widget methods to a js script&quot;&lt;/i&gt;.&lt;br /&gt;
The &lt;a href=&quot;http://code.google.com/p/gwt-google-apis/wiki/VisualizationCustomVisualization&quot;&gt;Google API Chart Tools&lt;/a&gt; provides a good starting point. I read the page documentation, did a bit of nosing in the library code and learned the basics of &lt;a href=&quot;http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasicsJSNI.html&quot;&gt;JSNI&lt;/a&gt;. In essence, it all drills down to:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;in your module load method, register your javascript objects&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;pre class=&quot;brush:java&quot;&gt;YourWidget.registerWidget(&quot;NameOfWidget&quot;, new WidgetFactory() {
      public YourWidget create() {
          return new YourWidget();
      }
});

&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;YourWidget must add the following (best is probably to create an abstract version that you will extend with your widgets functionality):&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Define the factory:&lt;br /&gt;
&lt;pre class=&quot;brush:java&quot;&gt;public interface WidgetFactory {
      YourWidget create();
}
&lt;/pre&gt;&lt;br /&gt;
Register the widget at module load time, exposes the constructor and the methods to be used by your js script:&lt;br /&gt;
&lt;pre class=&quot;brush:java&quot;&gt;public static final native void registerWidget(String name, WidgetFactory factory) /*-{
&amp;nbsp;&amp;nbsp;&amp;nbsp; // setup the constructor
&amp;nbsp;&amp;nbsp;&amp;nbsp; $wnd[name] = function(container) {
&amp;nbsp;&amp;nbsp;&amp;nbsp; this.gwt_widget = @your.widget.fullname::createWidget(Lyour/widget/fullname$WidgetFactory;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/user/client/Element;)(factory, this, container);
}
&amp;nbsp;&amp;nbsp;&amp;nbsp; // setup the exported methods
&amp;nbsp;&amp;nbsp;&amp;nbsp; $wnd[name].prototype.yourWidgetMethod = function(param1, param2) {
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; return this.gwt_widget.your.widgets.fullname@::yourWidgetMethod(Lparam1/full/type,Lparam2/full/type)(param1, param2);
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&amp;nbsp;&amp;nbsp;&amp;nbsp; // add more methods as required
}-*/;

&lt;/pre&gt;&lt;br /&gt;
Implement the factory:&lt;br /&gt;
&lt;pre class=&quot;brush:java&quot;&gt;@SuppressWarnings(&quot;unused&quot;)
private static YourWidget createWidget(WidgetFactory factory, JavaScriptObject jsWidget, Element container) {
&amp;nbsp;&amp;nbsp;&amp;nbsp; YourWidget widget = factory.create();

&amp;nbsp;&amp;nbsp;&amp;nbsp; RootPanel.get(container.getId()).add(widget);

&amp;nbsp;&amp;nbsp;&amp;nbsp; return widget;
}

&lt;/pre&gt;I won&#39;t go into too much details, because, in fact, there is a whole &lt;a href=&quot;http://code.google.com/p/gwt-exporter/&quot;&gt;project&lt;/a&gt; to help you do that, as I found out a bit too late...&lt;br /&gt;
&lt;br /&gt;
That was just square 1 and I am still in the steep learning curve phase.&lt;br /&gt;
&lt;br /&gt;
If you have followed the previous steps or used the GWT Exporter project, the widget now exposes its functionality to a js script. You can go into your html file and start playing with it. For instance, use the following code in your html file:&lt;br /&gt;
&lt;pre class=&quot;brush:javascript&quot;&gt;var yourWidget = new NameOfWidget(container);
   yourWidget.yourWidgetMethod1(param1, param2);
   // etc...
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
The next problem (square 2) was how to integrate the Google Maps in my widget. I want the user to pass his own Google Maps so that he keeps full configurability. The problem is that only Google Maps v2 is truly supported at the time of writing. And v2 as you might know is deprecated now. There are in fact a couple of projects enabling the use of Google maps v3 with GWT. I can think of this &lt;a href=&quot;http://code.google.com/p/gwt-google-maps-v3/&quot;&gt;one&lt;/a&gt; for instance. However, a quick look at the features supported, update times and pending issues convinced me not to go with them. Granted I could help and participate in the project, but that&#39;s a whole new story.&lt;br /&gt;
&lt;br /&gt;
That&#39;s basically where I got stuck, not being able to use v3 is a show stopper. I guess this will always be a problem with GWT, catching up on js developments. I had already worked a few hours and produced a fair amount of code. It&#39;s quite reluctantly that I decided to switch to good old javascript, testing along the way my GWT vs JS theory. Check my next Post.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/1429714745805144691/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2011/02/sorry-no-gwt.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/1429714745805144691'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/1429714745805144691'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2011/02/sorry-no-gwt.html' title='Sorry, No GWT'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYFo1epSjJ_A0t0Bt6K9mZdzMRZcomaLEALhqoIv29KjbAfi-ReQaDp-YhaXWEhXr_cTHsPY4PI3J_fDbWN1wBY-m4bFd0X5c20RR6kGEBX1UTcxoFD4gicwaCuNrMvICZ29q_VoSIqsbd/s72-c/GWT-JS.gif" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-2567878678653987032</id><published>2011-01-29T10:24:00.000-08:00</published><updated>2011-01-29T10:37:17.399-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Fusion Tables"/><category scheme="http://www.blogger.com/atom/ns#" term="Google Maps"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><title type='text'>Being Agile</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;My disappointment set aside (why is it Google always steals away my ideas? generally before I even invented them! ;-)), I decided to scour the Fusion Tables web site to evaluate the application and find out if there was any room for business.&lt;br /&gt;
I am not a seasoned market/product manager but one thing I found out over the years is that forums (or fora should I say) are a great way of finding out what people want. So there I went on the Fusion Tables forum and features request web pages.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;The features request page can be found &lt;a href=&quot;http://code.google.com/p/fusion-tables/issues/list?q=Type%3DFeature_Request&quot;&gt;here&lt;/a&gt;. You can vote on a feature already requested and leave a comment, eg OK but I would like it more like that (please). OR you can submit a new one using the online &lt;a href=&quot;http://code.google.com/p/fusion-tables/issues/entry?template=Feature%20Request&quot;&gt;form&lt;/a&gt;. Features can be ordered by number of votes they received.&lt;br /&gt;
At the time of writing,the most popular ones were ability to configure the marker rendering, more complex filtering options, etc...&lt;br /&gt;
One drew my attention though, the ability to display time animations. For instance we are talking about a moving marker, representing let&#39;s say the path followed by some great explorer (just an example). I actually developed such a functionality in one my projects (check my other &lt;a href=&quot;http://eotoolbox.blogspot.com/&quot;&gt;blog&lt;/a&gt; on it).&lt;br /&gt;
So I decided to start with a widget. One that can be added to a Google Map. The widget will consist of an play/pause/stop... UI with a time display, automatically pulling data from a said table, and displaying an animated layer on top of the map.&lt;br /&gt;
The widget can also propose a number of animation options such as automatic extrapolation of trajectories.&lt;br /&gt;
I need an elegant way to integrate with the map and the user data but it&#39;s a good start.&lt;br /&gt;
&lt;br /&gt;
My brain&#39;s ticking away now. I&#39;ll let you know what I come up with.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/2567878678653987032/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2011/01/being-agile.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/2567878678653987032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/2567878678653987032'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2011/01/being-agile.html' title='Being Agile'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-6652600563194326473</id><published>2011-01-28T02:17:00.000-08:00</published><updated>2011-01-28T02:27:18.568-08:00</updated><title type='text'>Awww what a blow</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;This morning, taking the elance Google Maps test hehehe, I discovered &lt;a href=&quot;http://tables.googlelabs.com/&quot;&gt;Fusion Table&lt;/a&gt;. For those who don&#39;t know, go to the web page or jump to the full version of my notes, below. Typical right? just when I was about to produce something useful...&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;You could say it&#39;s about time I found out. Fusion Table have been around for quite a while now (at least 2 years apparently).&lt;br /&gt;
Through my first readings and tinkering, I&#39;d say Fusion Table is a giant table, made available to all Google account owners to store and retrieved their (structured) data (through tables, in a RDBMS way). Data can be retrieved and visualised using the whole range of Google data visualisation tools. That includes:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;Maps&lt;/li&gt;
&lt;li&gt; Charts&lt;/li&gt;
&lt;li&gt;StoryLine&lt;/li&gt;
&lt;/ul&gt;You can actually embed a map in websites, as shown below. Check this &lt;a href=&quot;http://www.google.com/support/fusiontables/bin/answer.py?answer=185229&quot;&gt;tutorial&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;iframe height=&quot;300px&quot; scrolling=&quot;no&quot; src=&quot;http://www.google.com/fusiontables/embedviz?viz=MAP&amp;amp;q=select+col0%2C+col1%2C+col2%2C+col3+from+317391+&amp;amp;h=false&amp;amp;lat=11.178401873711785&amp;amp;lng=-176.484375&amp;amp;z=1&amp;amp;t=1&amp;amp;l=col2&quot; width=&quot;500px&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;
&lt;br /&gt;
Pretty cool no? BTW, it&#39;s a public table on the wikileak cables.&lt;br /&gt;
&lt;br /&gt;
There is plenty more visualisation widgets, depending on the content of your data. For instance you can plot a storyline if your table contains a date entry.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Google is the heaven of hackers.&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
So what is it I am going to do now??? Well, right now I am going to look for any essential lack of features and/or existing restrictions. I will find something useful to do.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/6652600563194326473/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2011/01/awww-what-blow.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/6652600563194326473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/6652600563194326473'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2011/01/awww-what-blow.html' title='Awww what a blow'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-198572703290404229.post-4694751551262189280</id><published>2011-01-25T13:04:00.000-08:00</published><updated>2011-01-25T13:04:29.646-08:00</updated><title type='text'>The idea</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;Well simply put I want to build a &quot;Drupal of Maps&quot;. I have been browsing on Elance&amp;nbsp;lately for Map/GIS related work and there are quite a few projects out there that could be built with a &quot;Drupal of Maps&quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;So, how do you get on with building a &quot;Drupal of Maps&quot; (DoM) and what technology do you use?&lt;br /&gt;
&lt;br /&gt;
I&#39;ll start with the basic requirements if you don&#39;t mind. Here&#39;s what I&#39;m thinking about:&lt;br /&gt;
&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;&lt;li&gt;Actors are the Administrator(s) and the User(s). The administrator builds the website, the user views the result.&lt;/li&gt;
&lt;li&gt;The result is either an embeddable widget or a full blown website/webpage. Both are comprised of at least a Map.&lt;/li&gt;
&lt;li&gt;The DoM is either installed locally or hosted by a third party&lt;/li&gt;
&lt;li&gt;The Administrator configures his website/webpage via a WYSIWYG editor, ie like in Drupal.&lt;/li&gt;
&lt;li&gt;The Administrator can configure the layout to a certain extent, as well as choose themes or even create new ones.&lt;/li&gt;
&lt;li&gt;The Administrator can define/create/add/edit/delete his own (Geographical) entities through a dedicated UI. An entity has one and only one Geometry field describing the geographical characteristics. An entity data can be restricted or public. The owner of the data can decide at each entry level the access restrictions.&lt;/li&gt;
&lt;li&gt;The Administrator can batch dump entity data in the system.&lt;/li&gt;
&lt;li&gt;The Administrator can add DoM registered widgets to his website/webpage.&lt;/li&gt;
&lt;li&gt;DoM has an API to enable integration of third party widgets.&lt;/li&gt;
&lt;li&gt;The Administrator can add entities to its website/webpage. Entities can be taken from the Administrator&#39;s own data set or from the publicly available ones.&lt;/li&gt;
&lt;li&gt;An (entity + filtering rule) is represented in the website/webpage by a Layer. The display of a layer can be customised, eg color or type.&lt;/li&gt;
&lt;li&gt;Website/webpage access can be restricted using authentication mechanisms&lt;/li&gt;
&lt;li&gt;The User, if authorised, can view/access the website/webpage. It can interact with it via the Map and the different widgets available.&lt;/li&gt;
&lt;li&gt;The User if authorised can leave comments or even contribute to the data by adding new entries or editing existing ones.&lt;/li&gt;
&lt;li&gt;The data should be versioned.&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;Right that&#39;s already a good start. Bear in mind it will evolve during the design.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Next Post I will start talk high level SW and the techno stack I am thinking of employing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://map-notes.blogspot.com/feeds/4694751551262189280/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://map-notes.blogspot.com/2011/01/idea.html#comment-form' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/4694751551262189280'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/198572703290404229/posts/default/4694751551262189280'/><link rel='alternate' type='text/html' href='http://map-notes.blogspot.com/2011/01/idea.html' title='The idea'/><author><name>Mouimoui</name><uri>http://www.blogger.com/profile/10058492310767557819</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>