Index: utils/josm/plugins/ywms/.classpath
===================================================================
--- utils/josm/plugins/ywms/.classpath	(revision 2264)
+++ utils/josm/plugins/ywms/.classpath	(revision 2264)
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/josm"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JDK 5"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
Index: utils/josm/plugins/ywms/.project
===================================================================
--- utils/josm/plugins/ywms/.project	(revision 2264)
+++ utils/josm/plugins/ywms/.project	(revision 2264)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>ywms</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
Index: utils/josm/plugins/ywms/README
===================================================================
--- utils/josm/plugins/ywms/README	(revision 2264)
+++ utils/josm/plugins/ywms/README	(revision 2264)
@@ -0,0 +1,25 @@
+A plugin for JOSM that acts as a WMS server for Yahoo satellite imagery. Used with wmsplugin.
+
+From the announcement on talk:
+
+With this new plugin, you can now work with Yahoo satellite images inside
+JOSM, the same way the applet or the flash editor does. It is a port to java
+of the perl script that Frederik Ramm made a couple of months ago, so it
+uses the same approach: spawn a browser window that asks Yahoo the images
+using its API. However, this plugin works in windows too.
+
+To use Yahoo imagery, follow this steps:
+
+1.- Download and install YWMS from [1].
+2.- Download and install/update WMS plugin from [2]. IMPORTANT!!: upgrade if
+you already have this plugin.
+3.- Activate both plugins in JOSM and restart.
+4.- In preference settings, Yahoo tab, set the path to firefox executable,
+the name of a new profile for firefox and click  "create". This opens a new
+browser window. Click "Make changes" and accept the question. Close the
+browser.
+5.- Go to your favorite area, and click the menu option "WMS -> Yahoo" .
+6.- Enjoy
+
+Any modern Gecko browser ([3]) should work, not only firefox. However, I
+have only tested firefox (>1.5.)
Index: utils/josm/plugins/ywms/build.xml
===================================================================
--- utils/josm/plugins/ywms/build.xml	(revision 2264)
+++ utils/josm/plugins/ywms/build.xml	(revision 2264)
@@ -0,0 +1,46 @@
+<project name="ywms" default="build" basedir=".">
+
+	<!-- point to your JOSM directory -->
+	<property name="josm" location="../josm/dist/josm-custom.jar" />
+
+
+	
+	<target name="init">
+		<mkdir dir="build"/>
+	</target>
+
+	<target name="compile" depends="init">
+		<javac srcdir="src" classpath="${josm}" destdir="build" debug="true">
+			<include name="**/*.java" />
+		</javac>
+	</target>
+
+	<target name="build" depends="compile">
+		<copy todir="build/resources">
+			<fileset dir="resources"/>
+		</copy>
+		<copy todir="build/images">
+			<fileset dir="images"/>
+		</copy>
+		<jar destfile="ywms.jar" basedir="build">
+			<manifest>
+				<attribute name="Plugin-Class" value="org.openstreetmap.josm.plugins.ywms.YWMSPlugin"/>
+				<attribute name="Plugin-Description" value="A WMS server for Yahoo imagery based on Firefox"/>
+				<attribute name="Author" value="Francisco R. Santos &lt;frsantos@gmail.com>"/>
+			</manifest>
+		</jar>
+	</target>
+
+	<target name="clean">
+		<delete dir="build" />
+	</target>
+
+	<target name="install" depends="build">
+		<copy file="ywms.jar" todir="${user.home}/.josm/plugins"/>
+	</target>
+
+	<target name="test" depends="install">
+		<java jar="${josm}" fork="true"/>
+	</target>
+
+</project>
Index: utils/josm/plugins/ywms/resources/config.html
===================================================================
--- utils/josm/plugins/ywms/resources/config.html	(revision 2264)
+++ utils/josm/plugins/ywms/resources/config.html	(revision 2264)
@@ -0,0 +1,80 @@
+<html>
+  <head>
+    <script type="text/javascript">
+    function configure()
+    {
+    	// Require privileges to change configuration
+	    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect UniversalPreferencesWrite UniversalPreferencesRead");
+    	var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
+		var ok = true;
+
+		// when this properties are created with "string" instead of "boolean", it throws an error
+		// Jus delete the profile and create again.
+    	try
+    	{
+	    	// Enable dump to console
+	    	prefs.setBoolPref("browser.dom.window.dump.enabled", true);
+			// navigator.preference("browser.dom.window.dump.enabled", true);
+		}
+		catch(err)
+		{
+			ok = false;
+			alert( "Error setting 'browser.dom.window.dump.enabled'=true :" + err );
+		}
+
+    	try
+    	{
+			// Disable resume from crash
+	    	prefs.setBoolPref("browser.sessionstore.resume_from_crash",false);
+			// navigator.preference("browser.sessionstore.resume_from_crash", "false");
+		}
+		catch(err)
+		{
+			ok = false;
+			alert( "Error setting 'browser.sessionstore.resume_from_crash'=false :" + err );
+		}
+		
+		if( ok )
+		{
+			document.getElementById("closeMsg").style.visibility = "inherit";
+			document.getElementById("errorMsg").style.visibility = "hidden";
+		}		// Seems that both configuration changes need differente ways of modification. Some mozilla bug??		
+		
+		else
+		{
+			document.getElementById("closeMsg").style.visibility = "hidden";
+			document.getElementById("errorMsg").style.visibility = "inherit";
+		}
+	}
+    </script>
+  
+  </head>
+
+<body>
+  <h2>YWMS Plugin configuration</h2>
+  
+  The configuration of the profile needs some extra modificationsof the
+  browser profile:
+  <ol>
+  <li><h4>The Javascript method <i>dump</i> must be active.</h4>
+  	  This method allows Javascrip code to write data to the output stream of the browser, 
+  	  and can be activated with the config option <i>browser.dom.window.dump.enabled</i>.</li><br>
+  <li><h4>Session recovery must be inactive</h4>
+      Session crash recovery will try to reopen the pages you were viewing before a browser crash, 
+      but for this JOSM plugin, this feature is not useful. This feature can be deactivated 
+      with the config option <i>browser.sessionstore.resume_from_crash</i>
+  </li>
+  </ol>
+  
+  These configuration propoerties can be modified automatically just clicking in the button below, 
+  that will ask for permissions to do so. Just accept to allow the modifications.
+  <br>
+  <br>
+  <button type="button" name="configure" value="Configure" onClick="configure()">Make changes</button>
+  <br>
+  <br>
+  <div id="closeMsg" style="visibility:hidden;"><blink>Close this browser window to start using JOSM with the YWMS plugin</blink></div>
+  <div id="errorMsg" style="visibility:hidden;"><blink>Configuration properties not properly modified.</blink></div>
+  
+</body>
+</html>
Index: utils/josm/plugins/ywms/resources/user.js
===================================================================
--- utils/josm/plugins/ywms/resources/user.js	(revision 2264)
+++ utils/josm/plugins/ywms/resources/user.js	(revision 2264)
@@ -0,0 +1,4 @@
+// Enable dump to console
+user_pref("browser.dom.window.dump.enabled", "true"); 
+// Disable resume from crash
+user_pref("browser.sessionstore.resume_from_crash", "true");
Index: utils/josm/plugins/ywms/resources/ymap.html
===================================================================
--- utils/josm/plugins/ywms/resources/ymap.html	(revision 2264)
+++ utils/josm/plugins/ywms/resources/ymap.html	(revision 2264)
@@ -0,0 +1,78 @@
+<html>
+  <head>
+    <script type="text/javascript">
+		var bbox = "";
+        var width  = 800;
+        var height = 800;
+
+		// Parse query string and set variables
+		var url = location.href;
+        var queryStringPos = url.indexOf("?");
+		if( queryStringPos != -1 )
+        {
+            url = url.substring(queryStringPos + 1);
+	    	var variables = url.split ("&");
+            for (i = 0; i < variables.length; i++) 
+            {
+            	if( !variables[i] )
+            		continue;
+                var keyValue = variables[i].split("=");
+                eval ('var '+keyValue[0].toLowerCase()+'="'+keyValue[1]+'"');
+            }
+        }
+        else
+        {
+            dump("YWMS ERROR: no queryString\n");
+        }
+        
+        // Limit size to current window's, to avoid memory problems
+        width = Math.min(width, screen.width);
+        height = Math.min(height, screen.height);
+        
+		// Don't know how to hide the window, so resize for the user to see it loading the aerial photo
+        window.moveTo(0,0);
+        window.resizeTo(width,height);
+    </script>
+    <script type="text/javascript" src="http://api.maps.yahoo.com/ajaxymap?v=3.0&appid=YahooDemo"></script>
+  </head>
+  
+  <body style="margin: 0px">
+    <div id="map"></div>
+    <script type="text/javascript">
+      if( !bbox || !width || !height)
+      {
+          alert("YWMS ERROR: invalid parameters\n");
+      }
+      else
+      {
+          // Resize map container to parameter dimension
+          var mapDiv = document.getElementById("map");
+          mapDiv.style.width  = width;
+          mapDiv.style.height = height;
+
+          // Get the bounding box
+          var coords = bbox.split(",");
+          var tllon  = coords[0], tllat = coords[1];
+          var brlon  = coords[2], brlat = coords[3];
+
+          var points = new Array();
+          points[0] = new YGeoPoint(tllat, tllon);
+          points[1] = new YGeoPoint(brlat, brlon);
+
+          // other map types work as well but only satellite allowed for use with OSM!
+          var map = new YMap(document.getElementById("map"), YAHOO_MAP_SAT);
+          var zac = map.getBestZoomAndCenter(points);
+          var level = zac.zoomLevel;
+
+          // funny Yahoo bug seems to return 0 if your section is too small
+          if (level==0) level=1;
+
+          map.drawZoomAndCenter(zac.YGeoPoint,level);
+          var bounds = map.getBoundsLatLon();
+
+          // Dumps the actual bounding box
+          dump("bbox=" + bounds.LonMin + "," + bounds.LatMin + "," + bounds.LonMax + "," + bounds.LatMax + "\n");
+      }
+    </script>
+  </body>
+</html>
Index: utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/GeckoSupport.java
===================================================================
--- utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/GeckoSupport.java	(revision 2264)
+++ utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/GeckoSupport.java	(revision 2264)
@@ -0,0 +1,87 @@
+package org.openstreetmap.josm.plugins.ywms;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Map;
+
+import org.openstreetmap.josm.Main;
+
+/**
+ * Utility class for Gecko browsers operations
+ * 
+ * @author frsantos
+ */
+public class GeckoSupport 
+{
+
+	/**
+	 * Creates a profile in a gecko browser
+	 * @param browserPath The path to the executable 
+	 * @param profile The profile to create
+	 * @return The browser process that is creating the profile
+	 * @throws IOException 
+	 */
+	public static Process createProfile(String browserPath, String profile) throws IOException 
+	{
+		ArrayList<String> cmdParams = new ArrayList<String>();
+		cmdParams.add( browserPath );
+		cmdParams.add("-CreateProfile");
+		cmdParams.add( profile );
+	
+		System.out.println("YWMS::Create Firefox profile CMD:" + cmdParams);
+		ProcessBuilder builder = new ProcessBuilder( cmdParams );
+	
+		// Set Mozilla environment variable to avoid reusing same window if already open
+		builder.environment().put("MOZ_NO_REMOTE", "1");
+		
+		return builder.start();
+	}
+	
+	/**
+	 * Browses a URL using a profile.
+	 * 
+	 * @param browserPath The path to the browser executable
+	 * @param profile If not empty, the profile to browse with
+	 * @param url The URL to browse
+	 * @param dump If true, every page loaded will be dumped to a PPM image
+	 * @return The browser process
+	 * @throws IOException If error
+	 */
+	public static Process browse(String browserPath, String profile, String url, boolean dump) throws IOException 
+	{
+		ArrayList<String> cmdParams = new ArrayList<String>();
+		cmdParams.add( browserPath );
+		if( profile != null && profile.length() != 0 )
+		{
+			cmdParams.add("-P");
+			cmdParams.add( profile );
+		}
+		cmdParams.add( url );
+
+		System.out.println("YWMS::Browsing URL CMD:" + cmdParams);
+		ProcessBuilder builder = new ProcessBuilder( cmdParams );
+
+		Map<String, String> environment = builder.environment();
+		// Set Mozilla environment variables
+		// This one avoids reusing same window if already open
+		environment.put("MOZ_NO_REMOTE", "1");
+		// This one causes Firefox to dump a screenshot of the viewport once the page has been loaded
+		if( dump )
+			environment.put("MOZ_FORCE_PAINT_AFTER_ONLOAD", System.getProperty("java.io.tmpdir") + "/ywms");
+		
+		return builder.start();
+	}
+	
+	/**
+	 * Browses a URL using the configured profile.
+	 * 
+	 * @param url The URL to browse
+	 * @param dump If true, every page loaded will be dumped to a PPM image
+	 * @return The browser process
+	 * @throws IOException If error
+	 */
+	public static Process browse(String url, boolean dump) throws IOException
+	{
+		return browse(Main.pref.get("ywms.firefox", "firefox"), Main.pref.get("ywms.profile"), url, dump);
+	}
+}
Index: utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/HTTPServer.java
===================================================================
--- utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/HTTPServer.java	(revision 2264)
+++ utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/HTTPServer.java	(revision 2264)
@@ -0,0 +1,69 @@
+package org.openstreetmap.josm.plugins.ywms;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+
+/**
+ * Simple HTTP server that spawn a {@link RequestProcessor} for every connection.
+ * 
+ * @author frsantos
+  */
+public class HTTPServer extends Thread 
+{
+    /** Default port for the HTTP server */
+	public static final int DEFAULT_PORT = 8000;
+	
+	/** The server socket */
+	private ServerSocket server;
+
+	/**
+	 * Constructor
+	 * @param port The port this server will listen
+	 * @throws IOException when connection errors
+	 */
+	public HTTPServer(int port)
+		throws IOException 
+	{
+		super("YWMS HTTP Server");
+		this.setDaemon(true);
+		// Start the server socket with only 1 connection, because we can only start one firefox process
+		this.server = new ServerSocket(port, 1);
+	}
+
+	/**
+	 * The main loop, spawns a {@link RequestProcessor} for each connection
+	 */
+	public void run() 
+	{
+		System.out.println("YWMS::Accepting connections on port " + server.getLocalPort());
+		while (true) 
+		{
+			try 
+			{
+				Socket request = server.accept();
+				RequestProcessor.processRequest(request);
+			}
+			catch( SocketException se)
+			{
+				if( !server.isClosed() )
+					se.printStackTrace();
+			}
+			catch (IOException ioe) 
+			{
+				ioe.printStackTrace();
+			}
+		}
+	}
+	
+	/**
+     * Stops the HTTP server
+     *  
+     * @throws IOException
+	 */
+	public void stopServer() throws IOException
+	{
+		server.close();
+	}
+}
Index: utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/ImageLoader.java
===================================================================
--- utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/ImageLoader.java	(revision 2264)
+++ utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/ImageLoader.java	(revision 2264)
@@ -0,0 +1,290 @@
+package org.openstreetmap.josm.plugins.ywms;
+
+import java.awt.*;
+import java.awt.image.*;
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.imageio.ImageIO;
+
+
+/**
+ * Loads a stellite image from Yahoo accordin to a WMS request.
+ * <p>
+ * The image is captured from firefox using one of its features: when the
+ * environment variable MOZ_FORCE_PAINT_AFTER_ONLOAD is set, it causes firefox
+ * to dump, as PPM files, the contents of all the pages loaded. The value of the
+ * variable is used to locate where the files are dumped.
+ * <p>
+ * As the image served by Yahoo is bigger than the one requested, it is cropped
+ * and resized to the desired size.
+ * <p>
+ * Currently, there is no way of knowing whether a zone has imagery or not. If
+ * not, the Yahoo message "We're sorry, the data you have requested is not
+ * available. Please zoom out to see more map information or refresh your
+ * browser to try again".
+ * <p>
+ * <br>
+ * <b>Implementation note:</b> <lu>
+ * <li>Some information is passed from Javascript to Java, so Firefox must be
+ * configured with the method "dump" to work. To allow this method in firefox,
+ * create or modify the option "browser.dom.window.dump.enabled=true" in
+ * "about:config"
+ * <p>
+ * <li>Also, as firefox must be started and killed once and again, it is
+ * recommended to create a profile with the option
+ * "browser.sessionstore.resume_from_crash" to false and set other profile to
+ * default, so no nag screens are shown. </lu>
+ * 
+ * @author frsantos
+ * 
+ */
+public class ImageLoader 
+{
+	/** Firefox writes lines starting with this for each file loadded */
+	public static final String GECKO_DEBUG_LINE = "GECKO: PAINT FORCED AFTER ONLOAD:";
+
+	private URL yahooUrl;
+	double[] orig_bbox = null;
+	double[] final_bbox = null;
+	int width = -1;
+	int height = -1;
+	Image image;
+	List<String> firefoxFiles = new ArrayList<String>();
+
+	/** The regular expression used to locate the bounding boxes */
+	private static final Pattern BBOX_RE = Pattern.compile("bbox=([+-]?\\d+\\.\\d+),([+-]?\\d+\\.\\d+),([+-]?\\d+\\.\\d+),([+-]?\\d+\\.\\d+)", Pattern.CASE_INSENSITIVE); 
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param wmsUrl The WMS request
+	 * @param pluginDir The directory of the plugin
+	 * @throws ImageLoaderException When error loading the image
+	 */
+	public ImageLoader(String wmsUrl) throws ImageLoaderException
+	{
+		System.out.println("YWMS::Requested WMS URL: " + wmsUrl);
+		try {
+			URL request = new URL("file:///page" + wmsUrl);
+			String query = request.getQuery().toLowerCase();
+			yahooUrl = new File(YWMSPlugin.getStaticPluginDir(), "ymap.html").toURI().toURL();
+			yahooUrl = new URL( yahooUrl.toExternalForm() + "?" + query);
+			
+			// Parse query to find original bounding box and dimensions
+        	StringTokenizer st = new StringTokenizer(query, "&");
+        	while( st.hasMoreTokens() )
+        	{
+        		String param = st.nextToken();
+        		if( param.startsWith("width=") )
+        			width=Integer.parseInt(param.substring("width=".length()));
+        		else if( param.startsWith("height=") )
+        			height=Integer.parseInt(param.substring("height=".length()));
+        		else if( param.startsWith("bbox=") )
+        		{
+        			orig_bbox = getBbox(param);
+        		}
+        	}
+        	
+        	if( width == -1 || height == -1)
+        		throw new ImageLoaderException("Can't find dimensions");
+        	
+        	load();
+		} 
+		catch (MalformedURLException e) {
+			throw new ImageLoaderException(e);
+		}
+	}
+
+	/**
+	 * Does the hard work.
+	 * <p>
+	 * It spawns a Firefox process with an HTML page that loads Yahoo imagery
+	 * using Yahoo's AJAX API. Firefox must be configured to allow the "dump"
+	 * method for this to work.
+	 * <p>
+	 * The image is cropped and reescaled to meet requested dimensions.
+	 * @throws ImageLoaderException When error loading the page
+	 */
+	private void load() throws ImageLoaderException
+	{
+		Process browser = null;
+		try 
+		{
+			browser = GeckoSupport.browse(yahooUrl.toString(), true);
+			// TODO: set focus in main window
+			File imageFilePpm = null;
+
+			// Parse output
+			BufferedReader in = new BufferedReader( new InputStreamReader( browser.getInputStream() ) );
+			String line = in.readLine();
+	        while( line != null ) 
+	        {
+	        	System.out.println("YWMS::" + line);
+	            if( line.startsWith("bbox=") )
+	            {
+	            	final_bbox = getBbox(line);
+	                // System.out.println("YWMS::BBOX: (" + final_bbox[0] + "," + final_bbox[1] + "), (" + final_bbox[2] + "," + final_bbox[3] + ")");
+	            }
+	            else if( line.startsWith(GECKO_DEBUG_LINE))
+	            {
+	            	// Find out the screenshot file
+	            	StringTokenizer st = new StringTokenizer(line);
+	            	// Skip header
+	            	for( int i = 0; i < 5; i++) st.nextToken();
+	            	String url = st.nextToken();
+	            	String file = st.nextToken();
+	            	firefoxFiles.add(file);
+	            	
+	            	URL browserUrl;
+	            	try {
+	            		browserUrl = new URL(url);	
+		            	if( browserUrl.sameFile(yahooUrl))
+		            	{
+			            	String status = st.nextToken();
+			            	if( !"(OK)".equals(status) )
+			            		throw new ImageLoaderException("Firefox couldn't load image");
+			            	
+			            	imageFilePpm = new File(file);
+			            	break;
+		            	}
+					} 
+	            	catch (MalformedURLException mue) 
+	            	{
+						// Probably a mozilla "chrome://" URL. Do nothing
+					}
+	            }
+	            else if( line.startsWith("WYMS ERROR:") )
+	            {
+		        	throw new ImageLoaderException("Error in JavaScript page:" + line);
+	            }
+	            line = in.readLine();
+	        }
+
+	        if( final_bbox == null  && imageFilePpm == null && !firefoxFiles.isEmpty() )
+	        {
+	        	throw new ImageLoaderException("Is there any other firefox window open with same profile?");
+	        }
+	        if( final_bbox == null )
+	        {
+	        	throw new ImageLoaderException("Couldn't find bounding box. Is browser.dom.window.dump.enabled set in Firefox config?");
+	        }
+	        if( imageFilePpm == null )
+	        {
+	        	throw new ImageLoaderException("Couldn't find dumped image. Is it a modern Gecko browser (i.e., firefox 1.5)?");
+	        }
+	        
+            PPM ppmImage = new PPM(imageFilePpm.getAbsolutePath());
+            image = ppmImage.getImage();
+            cleanImages();
+
+	        resizeImage();
+		} catch (IOException e) 
+		{
+			throw new ImageLoaderException(e);
+		}
+		finally
+		{
+			if( browser != null )
+			    browser.destroy();
+		}
+	}
+
+	/**
+	 * Transforms the Image into a BufferedImage
+	 * @return The current image as a BufferedImage
+	 */
+	public BufferedImage getBufferedImage() 
+	{
+		if( image == null )
+			return null;
+		
+		BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        Graphics g = bufferedImage.createGraphics();
+        g.setColor(Color.white);
+        g.fillRect(0, 0, width, height);
+        g.drawImage(image, 0, 0, null);
+        g.dispose();
+
+        return bufferedImage;
+	}
+
+	/**
+	 * Resizes the image to meet the requested dimensions
+	 */
+	private void resizeImage() 
+	{
+		int calcwidth = (int)Math.round((final_bbox[2] - final_bbox[0]) * width / (orig_bbox[2] - orig_bbox[0]));
+		int calcheight = (int)Math.round((final_bbox[3] - final_bbox[1]) * height / (orig_bbox[3] - orig_bbox[1]));
+
+		int cropWidth = (calcwidth - width) / 2;
+		int cropHeight = (calcheight - height) / 2;
+	
+		Toolkit tk = Toolkit.getDefaultToolkit();
+        // save("/tmp/image_orig.jpg");
+        image = tk.createImage (new FilteredImageSource (image.getSource(), new CropImageFilter(0, 0, width, height)));
+        image = tk.createImage (new FilteredImageSource (image.getSource(), new ReplicateScaleFilter(calcwidth, calcheight)));
+        image = tk.createImage (new FilteredImageSource (image.getSource(), new CropImageFilter(cropWidth, cropHeight, width, height)));
+		// BufferedImage img = (BufferedImage)image.getScaledInstance(calcwidth, calcwidth, BufferedImage.SCALE_DEFAULT);
+		// image = img.getSubimage(cropl, cropt, width, height);
+	}
+
+	/**
+	 * Parses a line of the form bbox=xmin,ymin,xmax,ymax and extracts the bounding box
+	 * 
+	 * @param line The string to parse
+	 * @return The bound box as a double array[4]
+	 * @throws ImageLoaderException
+	 */
+	private double[] getBbox(String line) throws ImageLoaderException
+	{
+    	Matcher matcher = BBOX_RE.matcher(line);
+    	if( !matcher.matches() )
+    	{
+    		throw new ImageLoaderException("Can't find bounding box");
+    	}
+    	
+    	double[] bbox = new double[4];
+    	for( int i = 0; i < 4; i++)
+    	{
+    		bbox[i] = Double.parseDouble( matcher.group(i+1) );
+    	}
+    	
+    	return bbox;
+	}
+	
+	/**
+	 * Saves the current image as a PNG file
+	 * @param fileName The name of the new file 
+	 * @throws IOException When error saving the file
+	 */
+	public void save(String fileName) throws IOException
+	{
+        FileOutputStream fileStream = new FileOutputStream(fileName);
+        ImageIO.write(getBufferedImage(), "png", fileStream);
+        fileStream.close();
+	}
+	
+	/**
+	 * Delete all images created by firefox when they are not longer used
+	 */
+	public void cleanImages() 
+	{
+		for(String fileName : firefoxFiles)
+		{
+			try
+			{
+				File file = new File(fileName);
+				file.delete();
+			}
+			catch(Exception e) { }
+		}
+		
+	}
+}
Index: utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/ImageLoaderException.java
===================================================================
--- utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/ImageLoaderException.java	(revision 2264)
+++ utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/ImageLoaderException.java	(revision 2264)
@@ -0,0 +1,38 @@
+package org.openstreetmap.josm.plugins.ywms;
+
+/**
+ * Exception when loading images with a mozilla browser
+ * 
+ * @author frsantos
+ *
+ */
+public class ImageLoaderException extends Exception 
+{
+    /**
+     * Constructor
+     */
+	public ImageLoaderException() 
+	{
+		super();
+	}
+
+
+    /**
+     * Constructor 
+     * 
+     * @param msg The exception message
+     */
+	public ImageLoaderException(String msg) 
+	{
+		super(msg);
+	}
+
+    /**
+     * Constructor 
+     * @param t the nested exception
+     */
+	public ImageLoaderException(Throwable t) 
+	{
+		super(t);
+	}
+}
Index: utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/PPM.java
===================================================================
--- utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/PPM.java	(revision 2264)
+++ utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/PPM.java	(revision 2264)
@@ -0,0 +1,109 @@
+package org.openstreetmap.josm.plugins.ywms;
+
+import java.awt.Dimension;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.image.MemoryImageSource;
+import java.io.*;
+
+/**
+ * PPM Image loader.
+ * <p>
+ * This loader handles only one type of PPM files: binary(P6) with 255 colors.
+ */
+public class PPM
+{
+	/** The image dimension */
+	protected Dimension dim = new Dimension();
+	
+	/** The pixels of the image in ARGB format  */
+	protected int[] data;
+
+	/**
+	 * Creates a PPM image from a file
+	 * <p>
+	 * The stream must contain a binary PPM (type P6 in the header) of 255 colors
+	 * 
+	 * @param filename The name of the file to read the PPM from
+	 * @throws IOException when failing to read the file
+	 * @throws UnsupportedEncodingException if file is not a binary(P6) PPM of 255 colors 
+	 */
+	public PPM(String filename) throws IOException, UnsupportedEncodingException
+	{
+		FileInputStream fis = new FileInputStream(filename);
+		
+		// XXX: The source data to the StreamTokenizer can't buffered, since we
+		// only need a few lines of the beginning of the file, and all remain
+		// data must be processed later. Even a InputStreamReader does some
+		// internal buffering, so we must use a deprecated constructor, create
+		// our own Reader or create some methods to simulate a StreamTokenizer.
+		// Easy way chosen :-)
+		StreamTokenizer st = new StreamTokenizer(fis);
+		st.commentChar('#');
+
+		/* PPM file format:
+		 * 
+		 * #			  --> Comments allowed anywere before binary data
+		 * P3|P6          --> ASCII/Binary
+		 * WIDTH          --> image width, in ascii
+		 * HEIGHT         --> image height, in ascii
+		 * COLORS		  --> num colors, in ascii
+		 * [data]		  --> if P6, data in binary, 3 RGB bytes per pixel 
+		 */
+
+		st.nextToken();
+		if( !st.sval.equals("P6") )
+			throw new UnsupportedEncodingException("Not a P6 (binary) PPM");
+		
+		st.nextToken();
+		dim.width = (int) Math.round(st.nval);
+		st.nextToken();
+		dim.height = (int) Math.round(st.nval);
+		data = new int[dim.width * dim.height];
+
+		st.nextToken(); 
+		int maxVal = (int) Math.round(st.nval); 
+		if( maxVal != 255 )
+			throw new UnsupportedEncodingException("Not a 255 color PPM");
+				
+		// Binary data cann be buffered
+		InputStream in = new BufferedInputStream(fis);
+		int numPixels = dim.width * dim.height;
+		for (int i = 0; i < numPixels; i++)
+		{
+			int r = in.read();
+			int g = in.read();
+			int b = in.read();
+			if( r== -1 || g == -1 || b == -1)
+				throw new IOException("EOF:" + r + " " + g + " " + b);
+			
+			data[i] = rgb(r, g, b);
+		}
+		in.close();		
+	}
+
+
+	/**
+	 * Creates an AWT image using the raw data
+	 * @return The AWT image
+	 */
+	public Image getImage()
+	{
+		MemoryImageSource memoryImageSource = new MemoryImageSource(dim.width, dim.height, data, 0, dim.width);
+		return Toolkit.getDefaultToolkit().createImage(memoryImageSource);
+	}
+
+	/**
+	 * Makes an ARGB pixel from three color values
+	 * @param r The red value
+	 * @param g The green value
+	 * @param b The blue value
+	 * @return The ARGB value
+	 * 
+	 */
+	private static int rgb(int r, int g, int b)
+	{
+		return (255 << 24 | (r << 16) | (g << 8) | b);
+	}
+
+}
Index: utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/RequestProcessor.java
===================================================================
--- utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/RequestProcessor.java	(revision 2264)
+++ utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/RequestProcessor.java	(revision 2264)
@@ -0,0 +1,168 @@
+package org.openstreetmap.josm.plugins.ywms;
+
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.net.Socket;
+import java.util.Date;
+import java.util.StringTokenizer;
+
+import javax.imageio.ImageIO;
+    
+/**
+ * Processes each of the WMS cliente requests, and serves the PNG image of the
+ * area.
+ * <p>
+ * This class acts as a very simple HTTP server, that only understands WMS GET
+ * requests.
+ * 
+ * @author frsantos
+ */
+public class RequestProcessor extends Thread 
+{
+	private Socket request;
+  
+	/**
+	 * Constructor
+	 * 
+	 * @param request The WMS request
+	 * @param pluginDir The directory of the plugin
+	 */
+	public RequestProcessor(Socket request) 
+	{
+	    super("YWMS request processor");
+	    this.setDaemon(true);
+		this.request = request;
+	}
+  
+	/**
+	 * Spawns a new thread for the request
+	 * 
+	 * @param request The WMS request
+	 */
+	public static void processRequest(Socket request) 
+	{
+		RequestProcessor processor = new RequestProcessor(request);
+		processor.start();
+	}  
+  
+	/**
+	 * The work is done here.
+	 * <p>
+	 * It parses the request and extracts the URL requested, used to load the
+	 * image, and serves it back
+	 */
+	public void run() 
+	{
+		Writer out = null;
+		try 
+		{            
+	        OutputStream raw = new BufferedOutputStream( request.getOutputStream() );         
+	        out = new OutputStreamWriter(raw);
+	        Reader in = new InputStreamReader( new BufferedInputStream( request.getInputStream(  ) ), "ASCII" );
+	        
+	        StringBuffer requestLine = new StringBuffer();
+	        while (true) 
+	        {
+	            int c = in.read();
+	            if (c == '\r' || c == '\n') break;
+	            requestLine.append((char) c);
+	        }
+	        
+	        String get = requestLine.toString();
+	        StringTokenizer st = new StringTokenizer(get);
+	        String method = st.nextToken();
+	        String url = st.nextToken();
+
+	        if( !method.equals("GET") )
+	        {
+	        	sendNotImplemented(out);
+	        	return;
+	        }
+
+	        // Load the image
+	        ImageLoader imageLdr = new ImageLoader(url);
+            BufferedImage wmsImage = imageLdr.getBufferedImage();
+            
+            // send the image data
+            ByteArrayOutputStream imageStream = new ByteArrayOutputStream();
+            ImageIO.write(wmsImage, "jpeg", imageStream);
+            byte[] data = imageStream.toByteArray();
+            
+			sendHeader(out, "200 OK", "image/jpeg", false);
+            out.write("Content-length: " + data.length + "\r\n");
+            out.write("\r\n");
+            out.flush();
+            
+            raw.write(data);
+            raw.flush();
+		}
+		catch (IOException ioe) { }
+		catch(Exception e)
+		{
+			e.printStackTrace();
+			try 
+			{
+				sendError(out);
+			} 
+			catch (IOException e1) { }
+		}
+		finally 
+		{
+	        try 
+	        {
+	        	request.close();        
+	        }
+	        catch (IOException e) {} 
+		}
+	}
+
+	/**
+	 * Sends a 500 error: server error
+	 */
+	private void sendError(Writer out) throws IOException
+	{
+		sendHeader(out, "500 Internal Server Error", "text/html", true);
+		out.write("<HTML>\r\n");
+		out.write("<HEAD><TITLE>Internal Error</TITLE>\r\n");
+		out.write("</HEAD>\r\n");
+		out.write("<BODY>");
+		out.write("<H1>HTTP Error 500: Internal Server Error</h2>\r\n");
+		out.write("</BODY></HTML>\r\n");
+		out.flush();
+	}
+
+	/**
+	 * Sends a 501 error: not implemented
+	 */
+	private void sendNotImplemented(Writer out) throws IOException
+	{
+		sendHeader(out, "501 Not Implemented", "text/html", true);
+		out.write("<HTML>\r\n");
+		out.write("<HEAD><TITLE>Not Implemented</TITLE>\r\n");
+		out.write("</HEAD>\r\n");
+		out.write("<BODY>");
+		out.write("<H1>HTTP Error 501: Not Implemented</h2>\r\n");
+		out.write("</BODY></HTML>\r\n");
+		out.flush();
+	}
+	
+	/**
+	 * Send common HTTP headers to the client.
+	 * 
+	 * @param out The Writer
+	 * @param status The status string ("200 OK", "500", etc)
+	 * @param contentType The content type of the data sent
+	 * @param endHeaders If true, adds a new line, ending the headers.
+	 * @throws IOException When error
+	 */
+	private void sendHeader(Writer out, String status, String contentType, boolean endHeaders) throws IOException
+	{
+		out.write("HTTP/1.1 " + status + "\r\n");
+		Date now = new Date();
+		out.write("Date: " + now + "\r\n");
+        out.write("Server: YWMS Server 1.0\r\n");
+        out.write("Content-type: " + contentType + "\r\n");
+        if( endHeaders )
+        	out.write("\r\n");
+	}
+}
Index: utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/YWMSPlugin.java
===================================================================
--- utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/YWMSPlugin.java	(revision 2264)
+++ utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/YWMSPlugin.java	(revision 2264)
@@ -0,0 +1,165 @@
+package org.openstreetmap.josm.plugins.ywms;
+
+import java.io.IOException;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.plugins.Plugin;
+import org.openstreetmap.josm.plugins.PluginProxy;
+
+/**
+ * 
+ * YWMS server
+ * <p>
+ * Emulates a primitive WMS server (only GetMap requests) that serves Yahoo!
+ * satellite images.
+ * <p>
+ * This plugin is heavily based on Frederik Ramm <frederik@remote.org> YWMS
+ * server in perl (see
+ * http://lists.openstreetmap.org/pipermail/dev/2007-January/002814.html), so
+ * most of the calculations and documentation is taken from his code. However,
+ * this plugin does not need any X server to run, because of a Firefox feature
+ * that dumps all loaded pages to PPM files, activated through the environment
+ * variable MOZ_FORCE_PAINT_AFTER_ONLOAD, pointing to the directory and prefix
+ * of the generated image files.
+ * <p>
+ * For each incoming request:
+ * <ul>
+ * <li>starts a firefox instance to render the web page
+ * <li>converts the resulting image to jpeg and returns it
+ * </ul>
+ * <p>
+ * This method can theoretically be used to display maps from any web site where
+ * the API supports selecting a geographic region AND includes a call to find
+ * out the region actually displayed.
+ * <p>
+ * This is required because most such services have discrete zoom levels, while
+ * the WMS request issued by josm expects to receive EXACTLY the coordinates
+ * requested in an image of the requested pixel size.
+ * <p>
+ * The HTML/Javscript used by this server uses the Yahoo! API to display an
+ * image depicting the selected area in the best available zoom level and then
+ * inquires about the area actually displayed, which will always be larger than
+ * what was requested. This information is then written to stdout using the
+ * "dump" Javascript command. From there it is read by this server, and used to
+ * stretch and cut the resulting browser image to the size requested in the WMS
+ * request.
+ * <p>
+ * To illustrate: <lu>
+ * <li>josm says "I want the area (48.5,7.0)-(48.8,7.1) as a 1000x800 pixel
+ * image"
+ * <li>we ask Yahoo about the best zoom level to display this area on 1000x800
+ * and request the image
+ * <li>we ask Yahoo about the extents actually displayed and receive the
+ * answer: (48.45,6.95)-(48.85,7.15)
+ * <li>This is .4 degrees high (we requested .3 degrees high) and .2 degrees
+ * wide (we requested .1 wide).
+ * <li>We scale the image to 1333x1600 and cut a 1000x800 section from the
+ * middle, knowing that this will now be exactly .3 degrees by .1 degrees (minus
+ * projection errors of course!) <lu>
+ * <p>
+ * <br>
+ * <b>Implementation note:</b> <lu>
+ * <li>Some information is passed from Javascript to Java, so Firefox must be
+ * configured with the method "dump" to work. To allow this method in firefox,
+ * create or modify the option "browser.dom.window.dump.enabled=true" in
+ * "about:config"
+ * <p>
+ * <li>Also, as firefox must be started and killed once and again, it is
+ * recommended to create a profile with the option
+ * "browser.sessionstore.resume_from_crash" to false and set other profile to
+ * default, so no nag screens are shown. </lu>
+ * 
+ * @author Francisco R. Santos <frsantos@gmail.com>
+ * @author Frederik Ramm <frederik@remote.org>
+ * @version 0.2 03/10/2007
+ */
+public class YWMSPlugin extends Plugin 
+{
+	static HTTPServer server;
+    
+	/**
+	 * Creates the plugin, and starts the HTTP server
+	 */
+	public YWMSPlugin()
+	{
+		try
+		{
+			copy("/resources/ymap.html", "ymap.html");
+			copy("/resources/config.html", "config.html");
+			restartServer();
+		}
+		catch(IOException e)
+		{
+			e.printStackTrace();
+		}
+	}
+	
+    @Override
+	public PreferenceSetting getPreferenceSetting() 
+	{
+		return new YWMSPreferenceSetting();
+	}
+	
+	/**
+	 * Starts or restarts the HTTP server
+	 *
+	 */
+	public void restartServer()
+	{
+		try
+		{
+			if( server != null )
+				server.stopServer();
+			
+			int port;
+			String strPort = Main.pref.get("ywms.port");
+			try
+			{
+				port = Integer.parseInt( strPort );
+			}
+			catch(Exception e)
+			{
+				System.out.println("YWMS::Invalid port '" + strPort + "'. Using default " + HTTPServer.DEFAULT_PORT);
+				port = HTTPServer.DEFAULT_PORT;
+			}
+			server = new HTTPServer(port);
+			server.start();
+		}
+		catch(IOException ioe)
+		{
+			ioe.printStackTrace();
+		}
+	}
+	
+    /** 
+     * Returns the plugin's directory
+     * <p>
+     * Utility method for classes that can't acces the plugin object
+     * 
+     * @return The directory of the plugin
+     */
+    public static String getStaticPluginDir()
+    {
+        YWMSPlugin plugin = getPlugin();
+        return ( plugin != null ) ? plugin.getPluginDir() : null;
+    }
+
+    /**
+     * Utility method to retrieve the plugin for classes that can't access to the plugin object directly.
+     * 
+     * @return The YWMS plugin
+     */
+    public static YWMSPlugin getPlugin()
+    {
+        for (PluginProxy plugin : Main.plugins)
+        {
+            if( plugin.info.className.equals(YWMSPlugin.class.getName()) )
+            {
+                return (YWMSPlugin)plugin.plugin;
+            }
+        }
+        
+        return null;
+    }
+}
Index: utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/YWMSPreferenceSetting.java
===================================================================
--- utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/YWMSPreferenceSetting.java	(revision 2264)
+++ utils/josm/plugins/ywms/src/org/openstreetmap/josm/plugins/ywms/YWMSPreferenceSetting.java	(revision 2264)
@@ -0,0 +1,210 @@
+package org.openstreetmap.josm.plugins.ywms;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.*;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+
+import javax.swing.*;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.gui.preferences.PreferenceDialog;
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.I18n;
+
+/**
+ * Preference settings for the YWMS plugin
+ * 
+ * @author frsantos
+ */
+public class YWMSPreferenceSetting implements PreferenceSetting
+{
+    /** WMS server name */
+    public static final String WMS_NAME  = "Yahoo";
+    /** WMS URL server parameters */
+    public static final String WMS_URL_PARAMS = "/ymap?request=GetMap&format=image/jpeg";
+
+    private JTextField firefox = new JTextField(10);
+    private JTextField port    = new JTextField(10);
+    private JTextField profile = new JTextField(10);
+    
+    public void addGui( final PreferenceDialog gui ) 
+    {
+    	firefox.setToolTipText(tr("<html>Path to firefox executable.<br>" + 
+    							  "The Firefox profile used in this plugin <b>must</b> be configured with the javascript 'dump' method,<br>" + 
+    							  "that can be activated with the property 'browser.dom.window.dump.enabled=true' in the about:config page.</html>"));
+    	port.setToolTipText(tr("<html>The port that the server will use to listen WMS requests<br>" +
+    						   "The WMS plugin need to be configured to use this port"));
+    	profile.setToolTipText(tr("<html>Name of the profile.<br>" + 
+    							  "This profile is used to avoid nag firefox screens asking you to resume failed sessions.<br>" +
+    							  "Just set the selected profile as not default in the profile selection window and configure to not ask<br>" + 
+    							  "about failed sessions with 'browser.sessionstore.resume_from_crash=false' in the about:config page"
+    							 ));
+
+    	JPanel ywms = gui.createPreferenceTab("yahoo.gif", I18n.tr("Yahoo! WMS server"), I18n.tr("Settings for the Yahoo! imagery server."));
+    	ywms.add(new JLabel(tr("YWMS options")), GBC.eol().insets(0,5,0,0));
+
+    	ywms.add(new JLabel(tr("Firefox executable")), GBC.std().insets(10,5,5,0));
+        ywms.add(firefox, GBC.eol().insets(0,5,0,0).fill(GBC.HORIZONTAL));
+        
+        ywms.add(new JLabel(tr("Firefox profile")), GBC.std().insets(10,5,5,0));
+        ywms.add(profile, GBC.std().insets(0,5,0,0).fill(GBC.HORIZONTAL));
+		JButton create = new JButton(tr("Create"));
+		ywms.add(create, GBC.eol().insets(5,0,0,0).fill(GBC.EAST));
+		create.addActionListener(new ProfileCreatorActionListener());
+        
+        ywms.add(new JLabel(tr("Server port")), GBC.std().insets(10,5,5,0));
+        ywms.add(port, GBC.eol().insets(0,5,0,0).fill(GBC.HORIZONTAL));
+		ywms.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
+        WMSConfigurationActionListener configurationActionListener = new WMSConfigurationActionListener();
+        port.addActionListener(configurationActionListener);
+        port.addFocusListener(configurationActionListener);
+		
+        firefox.setText(Main.pref.get("ywms.firefox", "firefox"));
+        profile.setText(Main.pref.get("ywms.profile"));
+        port.setText(Main.pref.get("ywms.port", "8000"));
+    }
+    
+    public void ok() 
+    {
+        Main.pref.put("ywms.firefox", firefox.getText());
+        Main.pref.put("ywms.profile", profile.getText());
+
+        String oldPort = Main.pref.get("ywms.port");
+        Main.pref.put("ywms.port", port.getText());
+        if( !oldPort.equals(port.getText()) )
+        {
+            YWMSPlugin plugin = YWMSPlugin.getPlugin();
+            plugin.restartServer();
+        }
+    }
+
+    /**
+     * ActionListener for the configuration of WMS plugin  
+     * @author frsantos
+     */
+    private final class WMSConfigurationActionListener implements ActionListener, FocusListener
+    {
+        boolean alreadyHandled = false;
+        public void actionPerformed(ActionEvent e) 
+        {
+            if( !alreadyHandled )
+                configureWMSPluginPreferences();
+            alreadyHandled = true;
+        }
+
+        public void focusGained(FocusEvent e)
+        {
+            alreadyHandled = false;
+        }
+
+        public void focusLost(FocusEvent e)
+        {
+            if( !alreadyHandled )
+                configureWMSPluginPreferences();
+            alreadyHandled = true;
+        }
+    }
+    
+    /**
+     * ActionListener for the creation of a Mozilla profile  
+     * @author frsantos
+     */
+    private final class ProfileCreatorActionListener implements ActionListener
+    {
+        public void actionPerformed(ActionEvent e) 
+        {
+            String profileName = profile.getText();
+            if( profileName == null || profileName.length() == 0)
+            {
+                JOptionPane.showMessageDialog(Main.parent, tr("Please name the profile you want to create."));
+                return;
+            }
+            
+            try
+            {
+                PleaseWaitRunnable createProfileTask = new PleaseWaitRunnable(tr("Creating profile"))
+                {
+                    Process process = null;
+                    @Override 
+                    protected void realRun() throws IOException
+                    {
+                        process = GeckoSupport.createProfile(firefox.getText(), profile.getText());
+                        try {
+                            process.waitFor();
+                        } 
+                        catch (InterruptedException e) 
+                        {
+                            IOException ioe = new IOException();
+                            ioe.initCause(e);
+                            throw ioe;
+                        }
+                        
+                        String configFile = new File(YWMSPlugin.getStaticPluginDir(), "config.html").toURL().toString(); 
+                        GeckoSupport.browse(firefox.getText(), profile.getText(), configFile, false);
+                        configureWMSPluginPreferences();
+                    }
+                    
+                    @Override 
+                    protected void finish() {}
+                    
+                    @Override 
+                    protected void cancel() 
+                    {
+                        if( process != null )
+                            process.destroy();
+                    }
+                };                  
+                Main.worker.execute(createProfileTask);
+            }
+            catch(Exception e2)
+            {
+                
+            }
+        }
+    }
+    
+    /**
+     * Configures WMSPlugin preferences with a server "Yahoo" pointing to YWMS  
+     * @param gui 
+     */
+    private void configureWMSPluginPreferences()
+    {
+        try 
+        {
+            PreferenceSetting wmsSetting = null;
+            for( PreferenceSetting setting : PreferenceDialog.settings)
+            {
+                if( setting.getClass().getName() == "wmsplugin.WMSPreferenceEditor" )
+                {
+                    wmsSetting = setting;
+                    break;
+                }
+            }
+            
+            if( wmsSetting == null )
+                return;
+            
+            int portNumber = Integer.parseInt(port.getText());
+            String strUrl = (String)wmsSetting.getClass().getMethod("getServerUrl", String.class).invoke(wmsSetting, WMS_NAME);
+            if( strUrl == null )
+                strUrl = new URL("http", "localhost", portNumber, WMS_URL_PARAMS).toString();
+            else
+            {
+                URL oldUrl = new URL(strUrl);
+                strUrl = new URL("http", oldUrl.getHost(), portNumber, WMS_URL_PARAMS).toString();
+            }
+            wmsSetting.getClass().getMethod("setServerUrl", String.class, String.class).invoke(wmsSetting, WMS_NAME, strUrl);
+        } catch (NoSuchMethodException e) {
+        } catch (NumberFormatException nfe) {
+        }
+        catch (Exception e) 
+        {
+            e.printStackTrace();
+        }
+    }
+}
