Index: /applications/editors/josm/plugins/scripting/LICENSE
===================================================================
--- /applications/editors/josm/plugins/scripting/LICENSE	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/LICENSE	(revision 25019)
@@ -0,0 +1,345 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+	51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Index: /applications/editors/josm/plugins/scripting/README
===================================================================
--- /applications/editors/josm/plugins/scripting/README	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/README	(revision 25019)
@@ -0,0 +1,15 @@
+----------------------------------------------------------------------
+                        scripting plugin
+----------------------------------------------------------------------                        
+
+The scripting plugin executes scripts in JOSM.
+
+Scripts can be defined in any scripting language, for which a JSR-223
+compatible scripting engine is available.
+                                                  
+AUTHOR
+======
+Karl Guggisberg <karl.guggisberg@guggis.ch>
+
+ 
+                         
Index: /applications/editors/josm/plugins/scripting/build.xml
===================================================================
--- /applications/editors/josm/plugins/scripting/build.xml	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/build.xml	(revision 25019)
@@ -0,0 +1,350 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+** This is the build file for the contour plugin
+**
+** Maintaining versions
+** ====================
+** see README.template
+**
+** Usage
+** =====
+** To build it run
+**
+**    > ant  dist
+**
+** To install the generated plugin locally (in your default plugin directory) run
+**
+**    > ant  install
+**
+** To build against the core in ../../core, create a correct manifest and deploy to
+** SVN, 
+**    set the properties commit.message and plugin.main.version
+** and run
+**    > ant  publish
+**
+**
+-->
+<project name="scripting" default="dist" basedir=".">
+
+	<property name="commit.message" value="Initial version" />
+	<property name="plugin.main.version" value="3751" />
+
+	<!--
+      ************************************************
+      ** should not be necessary to change the following properties
+     -->
+	<property name="josm" location="../../core/dist/josm-custom.jar" />
+	<property name="plugin.build.dir" value="build" />
+	<property name="plugin.src.dir" value="src" />
+	<!-- this is the directory where the plugin jar is copied to -->
+	<property name="plugin.dist.dir" value="../../dist" />
+	<property name="plugin.jar" value="${plugin.dist.dir}/${ant.project.name}.jar" />
+
+	<path id="compile.path">
+		<pathelement location="${josm}"/>
+		<pathelement location="lib/groovy-all-1.7.7-SNAPSHOT.jar"/>
+	</path>
+
+	<!--
+    **********************************************************
+    ** init - initializes the build
+    **********************************************************
+    -->
+	<target name="init">
+		<mkdir dir="${plugin.build.dir}" />
+	</target>
+
+	<!--
+    **********************************************************
+    ** compile - complies the source tree
+    **********************************************************
+    -->
+	<target name="compile" depends="init">
+		<echo message="compiling sources for  ${plugin.jar} ... " />
+		<javac srcdir="src" classpathref="compile.path" debug="true" destdir="${plugin.build.dir}">
+			<compilerarg value="-Xlint:deprecation" />
+			<compilerarg value="-Xlint:unchecked" />
+		</javac>
+	</target>
+
+	<!--
+    **********************************************************
+    ** dist - creates the plugin jar
+    **********************************************************
+    -->
+	<target name="dist" depends="compile,revision">
+		<echo message="creating ${plugin.jar} for version ${version.entry.commit.revision} ... " />
+		<copy todir="${plugin.build.dir}/images">
+			<fileset dir="images">
+				<include name="*.png" />
+			</fileset>
+		</copy>
+		<copy todir="${plugin.build.dir}/scripts">
+			<fileset dir="scripts">
+				<include name="*.groovy" />
+			</fileset>
+		</copy>
+
+		<copy todir="${plugin.build.dir}">
+			<fileset dir=".">
+				<include name="README" />
+				<include name="LICENSE" />
+			</fileset>
+		</copy>
+		<copy todir="${plugin.build.dir}">
+			<fileset dir="${plugin.src.dir}">
+				<include name="**/*.dtd" />
+			</fileset>
+		</copy>
+		<copy todir="${plugin.build.dir}/META-INF">
+			<fileset dir="resources">
+				<include name="mime.types" />
+			</fileset>
+		</copy>
+		<jar destfile="${plugin.jar}" basedir="${plugin.build.dir}">
+			<manifest>
+				<attribute name="Author" value="Karl Guggisberg" />
+				<attribute name="Plugin-Class" value="org.openstreetmap.josm.plugins.scripting.ScriptingPlugin" />
+				<attribute name="Plugin-Date" value="${version.entry.commit.date}" />
+				<attribute name="Plugin-Description" value="Allows to run scripts in JOSM." />
+				<!-- <attribute name="Plugin-Icon" value="" /> -->
+				<attribute name="Plugin-Link" value="http://wiki.openstreetmap.org/index.php/JOSM/Plugins/Scripting" />
+				<attribute name="Plugin-Mainversion" value="${plugin.main.version}" />
+				<attribute name="Plugin-Version" value="${version.entry.commit.revision}" />
+			</manifest>
+		</jar>
+	</target>
+
+	<!--
+    **********************************************************
+    ** revision - extracts the current revision number for the
+    **    file build.number and stores it in the XML property
+    **    version.*
+    **********************************************************
+    -->
+	<target name="revision">
+		<!-- extract the SVN revision information  -->
+		<exec append="false" output="REVISION" executable="svn" failifexecutionfails="false">
+			<env key="LANG" value="C" />
+			<arg value="info" />
+			<arg value="--xml" />
+			<arg value="." />
+		</exec>
+		<xmlproperty file="REVISION" prefix="version" keepRoot="false" collapseAttributes="true" />
+		<delete file="REVISION" />
+	</target>
+
+	<!--
+    **********************************************************
+    ** clean - clean up the build environment
+    **********************************************************
+    -->
+	<target name="clean">
+		<delete dir="${plugin.build.dir}" />
+		<delete file="${plugin.jar}" />
+	</target>
+
+	<!--
+    **********************************************************
+    ** install - install the plugin in your local JOSM installation
+    **********************************************************
+    -->
+	<target name="install" depends="dist">
+		<property environment="env" />
+		<condition property="josm.plugins.dir" value="${env.APPDATA}/JOSM/plugins" else="${user.home}/.josm/plugins">
+			<and>
+				<os family="windows" />
+			</and>
+		</condition>
+		<copy file="${plugin.jar}" todir="${josm.plugins.dir}" />
+	</target>
+
+	<!--
+	 ************************** Publishing the plugin *********************************** 
+	-->
+	<!--
+	** extracts the JOSM release for the JOSM version in ../core and saves it in the 
+	** property ${coreversion.info.entry.revision}
+	**
+	-->
+	<target name="core-info">
+		<exec append="false" output="core.info.xml" executable="svn" failifexecutionfails="false">
+			<env key="LANG" value="C" />
+			<arg value="info" />
+			<arg value="--xml" />
+			<arg value="../../core" />
+		</exec>
+		<xmlproperty file="core.info.xml" prefix="coreversion" keepRoot="true" collapseAttributes="true" />
+		<echo>Building against core revision ${coreversion.info.entry.revision}.</echo>
+		<echo>Plugin-Mainversion is set to ${plugin.main.version}.</echo>
+		<delete file="core.info.xml" />
+	</target>
+
+	<!--
+	** commits the source tree for this plugin
+	-->
+	<target name="commit-current">
+		<echo>Commiting the plugin source with message '${commit.message}' ...</echo>
+		<exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+			<env key="LANG" value="C" />
+			<arg value="commit" />
+			<arg value="-m '${commit.message}'" />
+			<arg value="." />
+		</exec>
+	</target>
+
+	<!--
+	** updates (svn up) the source tree for this plugin
+	-->
+	<target name="update-current">
+		<echo>Updating plugin source ...</echo>
+		<exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+			<env key="LANG" value="C" />
+			<arg value="up" />
+			<arg value="." />
+		</exec>
+		<echo>Updating ${plugin.jar} ...</echo>
+		<exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+			<env key="LANG" value="C" />
+			<arg value="up" />
+			<arg value="../dist/${plugin.jar}" />
+		</exec>
+	</target>
+
+	<!--
+	** commits the plugin.jar 
+	-->
+	<target name="commit-dist">
+		<echo>
+***** Properties of published ${plugin.jar} *****
+Commit message    : '${commit.message}'					
+Plugin-Mainversion: ${plugin.main.version}
+JOSM build version: ${coreversion.info.entry.revision}
+Plugin-Version    : ${version.entry.commit.revision}
+***** / Properties of published ${plugin.jar} *****					
+					
+Now commiting ${plugin.jar} ...
+</echo>
+		<exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+			<env key="LANG" value="C" />
+			<arg value="-m '${commit.message}'" />
+			<arg value="commit" />
+			<arg value="${plugin.jar}" />
+		</exec>
+	</target>
+
+	<!-- ** make sure svn is present as a command line tool ** -->
+	<target name="ensure-svn-present">
+		<exec append="true" output="svn.log" executable="svn" failifexecutionfails="false" failonerror="false" resultproperty="svn.exit.code">
+			<env key="LANG" value="C" />
+			<arg value="--version" />
+		</exec>
+		<fail message="Fatal: command 'svn --version' failed. Please make sure svn is installed on your system.">
+			<!-- return code not set at all? Most likely svn isn't installed -->
+			<condition>
+				<not>
+					<isset property="svn.exit.code" />
+				</not>
+			</condition>
+		</fail>
+		<fail message="Fatal: command 'svn --version' failed. Please make sure a working copy of svn is installed on your system.">
+			<!-- error code from SVN? Most likely svn is not what we are looking on this system -->
+			<condition>
+				<isfailure code="${svn.exit.code}" />
+			</condition>
+		</fail>
+	</target>
+
+	<target name="publish" depends="ensure-svn-present,core-info,commit-current,update-current,clean,dist,commit-dist">
+	</target>
+
+	<!-- ************************************************************************************ -->
+	<!-- * Targets for compiling and running tests                                            -->
+	<!-- ************************************************************************************ -->
+	<property name="eclipse.plugin.dir" value="C:\software\eclipse-3.6.1\plugins" />
+	<property name="test.build.dir" value="test/build" />
+
+	<path id="groovy.path">
+		<pathelement location="${eclipse.plugin.dir}/org.codehaus.groovy_1.7.5.xx-20100926-2000-e36-RC1\lib\groovy-all-1.7.5.jar" />
+	</path>
+
+	<path id="junit.path">
+		<pathelement location="${eclipse.plugin.dir}/org.junit_4.8.1.v4_8_1_v20100427-1100\junit.jar" />
+	</path>
+
+	<!-- groovy dependency: groovy fails unless hamcrest is on the path -->
+	<path id="hamcrest.path">
+		<pathelement location="test/lib/hamcrest-all-1.3.0RC2.jar" />
+	</path>
+
+	<path id="test.class.path">
+		<pathelement location="${josm}" />
+		<pathelement location="${plugin.build.dir}" />
+		<path refid="groovy.path" />
+		<path refid="junit.path" />
+	</path>
+
+	<path id="groovyc.path">
+		<path refid="junit.path" />
+		<path refid="groovy.path" />
+		<path refid="hamcrest.path" />
+		<pathelement location="${josm}" />
+		<pathelement location="${test.build.dir}" />
+		<pathelement location="${plugin.build.dir}" />
+		<!-- if we didn't explicitly put hamcrest on the class path, groovyc would
+			     abort and report it is missing a hamcrest class -->
+		<pathelement location="test/lib/hamcrest-all-1.2.jar" />
+	</path>
+
+	<target name="test-clean">
+		<delete dir="${test.build.dir}" />
+		<mkdir dir="${test.build.dir}" />
+	</target>
+
+	<target name="test-compile" depends="compile,test-clean" description="Compiles the test files">
+
+		<available classname="org.codehaus.groovy.ant.Groovy" classpathref="groovyc.path" property="groovy.present" />
+		<fail message="Groovy not found. Make sure groovy is on the classpath. Check 'groovy.path' in this build file." unless="groovy.present" />
+
+		<taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc" classpathref="groovy.path" />
+
+		<echo message="compiling test infrastructur for ${plugin.jar} ... " />
+		<javac srcdir="test/src" classpathref="test.class.path" debug="true" destdir="${test.build.dir}" includes="org/openstreetmap/josm/plugins/contourmerge/fixtures/**/*">
+			<compilerarg value="-Xlint:deprecation" />
+			<compilerarg value="-Xlint:unchecked" />
+		</javac>
+
+		<echo message="compiling groovy test cases for ${plugin.jar} ... " />
+		<groovyc srcdir="test/src" destdir="${test.build.dir}" classpathref="groovyc.path">
+		</groovyc>
+
+		<echo message="compiling java test cases for ${plugin.jar} ... " />
+		<javac srcdir="test/src" classpathref="test.class.path" debug="true" destdir="${test.build.dir}">
+			<compilerarg value="-Xlint:deprecation" />
+			<compilerarg value="-Xlint:unchecked" />
+		</javac>
+	</target>
+
+	<target name="test-run" depends="test-compile" description="Runs the junit tests">
+		<delete dir="test/output" />
+		<mkdir dir="test/output" />
+
+		<junit printsummary="true" failureproperty="junit.failure">
+			<classpath>
+				<path refid="groovyc.path" />
+				<pathelement location="test/config" />
+				<!-- required for test config file -->
+				<pathelement location="." />
+				<!-- required to load images from subdir 'images/' -->
+			</classpath>
+
+			<test todir="test/output" name='org.openstreetmap.josm.plugins.contourmerge.AllUnitTests'>
+				<formatter type="xml" />
+			</test>
+		</junit>
+	</target>
+
+	<target name="dev-install" depends="dist">
+		<copy file="${plugin.jar}" todir="C:/data/projekte/osm/josm-dev/plugins" />
+	</target>
+</project>
Index: /applications/editors/josm/plugins/scripting/scripts/AddHouseNumbers.groovy
===================================================================
--- /applications/editors/josm/plugins/scripting/scripts/AddHouseNumbers.groovy	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/scripts/AddHouseNumbers.groovy	(revision 25019)
@@ -0,0 +1,145 @@
+/*
+ * This scripts sets a sequence of house numbers on the currently selected nodes.
+ * 
+ * The user can enter a start number and and an increment.
+ */
+
+import java.awt.BorderLayout;
+
+import groovy.swing.SwingBuilder;
+import javax.swing.JOptionPane;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.ChangeCommand;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.gui.HelpAwareOptionPane;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.widgets.HtmlPanel;
+import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.WindowGeometry;
+import org.openstreetmap.josm.data.osm.DataSet
+import org.openstreetmap.josm.data.osm.Node;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import javax.swing.JLabel;
+
+import javax.swing.BorderFactory;
+import javax.swing.JTextField;
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import java.awt.event.ActionListener;
+import java.awt.Dimension;
+
+class AddHouseNumberDialog extends JDialog {
+	
+	private JTextField tfStart;
+	private JTextField tfIncrement;
+	
+	public AddHouseNumberDialog(){
+		super(Main.parent, true /* modal */)
+		build();
+	}
+	
+	def buildInfoPanel() {
+		def info = new HtmlPanel(
+		"""
+		<html>
+		Enter the <strong>first house number</strong> to be applied to the currently selected nodes
+		and the amount by which the house number is <strong>incremented</strong>.
+		</html>
+		"""
+		)
+	}
+	
+	def buildInputPanel() {
+		SwingBuilder swing = new SwingBuilder()
+		return swing.panel(){
+			gridBagLayout()
+			label(text: "Start:", 
+				horizontalAlignment: JLabel.LEFT,
+				constraints: gbc(gridx:0,gridy:0,weightx:0.0, weighty:0.0, fill: GridBagConstraints.NONE, anchor: GridBagConstraints.WEST)
+			)
+			tfStart = textField(constraints: gbc(gridx:1,gridy:0,weightx:1.0, weighty:0.0, fill: GridBagConstraints.HORIZONTAL, insets:[2,2,2,2]))
+			label(text: "Increment:", horizontalAlignment: JLabel.LEFT, constraints: gbc(gridx:0,gridy:1,weightx:0.0, weighty:0.0, anchor: GridBagConstraints.WEST, insets:[2,2,2,2]))
+			tfIncrement = textField(constraints: gbc(gridx:1,gridy:1,weightx:1.0, weighty:0.0, fill: GridBagConstraints.HORIZONTAL, anchor: GridBagConstraints.WEST, insets:[2,2,2,2]))
+			panel(constraints: gbc(gridx:0,gridy:2,weightx:1.0, weighty:1.0, gridwidth:2, fill: GridBagConstraints.BOTH, insets:[2,2,2,2]))
+		} 
+	}
+	
+	def buildControlButtonPanel() {
+		SwingBuilder swing = new SwingBuilder()
+		return swing.panel(layout: new FlowLayout(FlowLayout.CENTER)) {
+			button(text: "Cancel", icon: ImageProvider.get("cancel"), actionPerformed: {setVisible(false)})
+			button(text: "Apply", icon: ImageProvider.get("ok"), actionPerformed: {
+				apply()
+				setVisible(false)
+			})
+		}
+	}
+	
+	def apply() {
+		def start
+		try {
+			start = tfStart.text.trim().toInteger()
+		} catch(NumberFormatException e){
+			e.printStackTrace()
+			return
+		}
+		def incr
+		try  {
+			incr = tfIncrement.text.trim().toInteger()
+		} catch(NumberFormatException e){
+			e.printStackTrace()
+			return
+		} 
+		def nodes = getCurrentlySelectedNodes()
+		def cmds = []
+		nodes.each {Node n ->
+			Node nn = new Node(n)
+			nn.put("addr:housenumber", start.toString())
+			start += incr
+			cmds << new ChangeCommand(n, nn)			
+		}
+		if (cmds.isEmpty()) return
+		Main.main.undoRedo.add(new SequenceCommand("Setting house numbers", cmds))
+	}
+	
+	def build() {
+		setTitle("Set house numbers")
+		def cp = getContentPane()
+		cp.setLayout(new BorderLayout())
+		cp.add(buildInfoPanel(), BorderLayout.NORTH)
+		cp.add(buildInputPanel(), BorderLayout.CENTER)
+		cp.add(buildControlButtonPanel(), BorderLayout.SOUTH)
+	}	
+	
+	def getCurrentDataSet() {
+		def layer = Main?.map?.mapView?.getActiveLayer()
+		if (layer == null) return null
+		if (! (layer instanceof OsmDataLayer)) return null
+		return layer.data
+	}
+	
+	def getCurrentlySelectedNodes() {
+		def DataSet ds = getCurrentDataSet()
+		if (ds == null) return []
+		return ds.getSelectedNodes().asList()
+	}
+
+	@Override
+	public void setVisible(boolean b) {
+		if (b){
+			WindowGeometry.centerInWindow(getParent(), new Dimension(400,200)).applySafe(this)
+		}
+		super.setVisible(b);
+	}
+}
+
+def dialog = new AddHouseNumberDialog()
+dialog.setVisible(true)
Index: /applications/editors/josm/plugins/scripting/scripts/HelloWorld.groovy
===================================================================
--- /applications/editors/josm/plugins/scripting/scripts/HelloWorld.groovy	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/scripts/HelloWorld.groovy	(revision 25019)
@@ -0,0 +1,4 @@
+import javax.swing.JOptionPane;
+import org.openstreetmap.josm.Main;
+
+JOptionPane.showMessageDialog(Main.parent, "Hello World!")
Index: /applications/editors/josm/plugins/scripting/scripts/helloWorld.properties
===================================================================
--- /applications/editors/josm/plugins/scripting/scripts/helloWorld.properties	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/scripts/helloWorld.properties	(revision 25019)
@@ -0,0 +1,4 @@
+displayName=Hello World Script
+description=Displays a hello world message. 
+author=Karl Guggisberg
+scriptingEngine=groovy
Index: /applications/editors/josm/plugins/scripting/src/org/openstreetmap/josm/plugins/scripting/HelpAwareOptionPane.java
===================================================================
--- /applications/editors/josm/plugins/scripting/src/org/openstreetmap/josm/plugins/scripting/HelpAwareOptionPane.java	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/src/org/openstreetmap/josm/plugins/scripting/HelpAwareOptionPane.java	(revision 25019)
@@ -0,0 +1,281 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.scripting;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+import java.awt.Dialog.ModalityType;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+
+import org.openstreetmap.josm.gui.help.HelpBrowser;
+import org.openstreetmap.josm.gui.help.HelpUtil;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.WindowGeometry;
+
+// FIXME: copied from the JOSM source tree. After migration to Java6 somebody added
+// ModalityType.DOCUMENT_MODAL when the option pane dialog is launched, but this leads
+// to problems when an option pane dialog is launched from a modal JDialog. 
+// 
+// This cloned source class just replaces ModalityType.DOCUMENT_MODAL with 
+// ModalityType.APPLICATION_MODAL. If this gets fixed later in the JOSM core, this
+// class be removed. 
+//
+
+public class HelpAwareOptionPane {
+
+    public static class ButtonSpec {
+        public String text;
+        public Icon icon;
+        public String tooltipText;
+        public String helpTopic;
+
+        /**
+         *
+         * @param text  the button text
+         * @param icon  the icon to display. Can be null
+         * @param tooltipText  the tooltip text. Can be null.
+         * @param helpTopic the help topic. Can be null.
+         */
+        public ButtonSpec(String text, Icon icon, String tooltipText, String helpTopic) {
+            this.text = text;
+            this.icon = icon;
+            this.tooltipText = tooltipText;
+            this.helpTopic = helpTopic;
+        }
+    }
+
+    static private class DefaultAction extends AbstractAction {
+        private JDialog dialog;
+        private JOptionPane pane;
+        private int value;
+
+        public DefaultAction(JDialog dialog, JOptionPane pane, int value) {
+            this.dialog = dialog;
+            this.pane = pane;
+            this.value = value;
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            pane.setValue(value);
+            dialog.setVisible(false);
+        }
+    }
+
+    /**
+     * Creates the list buttons to be displayed in the option pane dialog.
+     *
+     * @param options the option. If null, just creates an OK button and a help button
+     * @param helpTopic the help topic. The context sensitive help of all buttons is equal
+     * to the context sensitive help of the whole dialog
+     * @return the list of buttons
+     */
+    static private List<JButton> createOptionButtons(ButtonSpec[] options, String helpTopic) {
+        List<JButton> buttons = new ArrayList<JButton>();
+        if (options == null) {
+            JButton b = new JButton(tr("OK"));
+            b.setIcon(ImageProvider.get("ok"));
+            b.setToolTipText(tr("Click to close the dialog"));
+            b.setFocusable(true);
+            buttons.add(b);
+        } else {
+            for (ButtonSpec spec: options) {
+                JButton b = new JButton(spec.text);
+                b.setIcon(spec.icon);
+                b.setToolTipText(spec.tooltipText == null? "" : spec.tooltipText);
+                if (helpTopic != null) {
+                    HelpUtil.setHelpContext(b, helpTopic);
+                }
+                b.setFocusable(true);
+                buttons.add(b);
+            }
+        }
+        return buttons;
+    }
+
+    /**
+     * Creates the help button
+     *
+     * @param helpTopic the help topic
+     * @return the help button
+     */
+    static private JButton createHelpButton(final String helpTopic) {
+        JButton b = new JButton(tr("Help"));
+        b.setIcon(ImageProvider.get("help"));
+        b.setToolTipText(tr("Show help information"));
+        HelpUtil.setHelpContext(b, helpTopic);
+        Action a = new AbstractAction() {
+            public void actionPerformed(ActionEvent e) {
+                HelpBrowser.setUrlForHelpTopic(helpTopic);
+            }
+        };
+        b.addActionListener(a);
+        b.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), "enter");
+        b.getActionMap().put("enter", a);
+        return b;
+    }
+
+    /**
+     * Displays an option dialog which is aware of a help context. If <code>helpTopic</code> isn't null,
+     * the dialog includes a "Help" button and launches the help browser if the user presses F1. If the
+     * user clicks on the "Help" button the option dialog remains open and JOSM launches the help
+     * browser.
+     *
+     * <code>helpTopic</code> is the trailing part of a JOSM online help URL, i.e. the part after the leading
+     * <code>http://josm.openstreetmap.de/wiki/Help</code>. It should start with a leading '/' and it
+     * may include an anchor after a '#'.
+     *
+     * <strong>Examples</strong>
+     * <ul>
+     *    <li>/Dialogs/RelationEditor</li>
+     *    <li>/Dialogs/RelationEditor#ConflictInData</li>
+     * </ul>
+     *
+     * In addition, the option buttons display JOSM icons, similar to ExtendedDialog.
+     *
+     * @param parentComponent the parent component
+     * @param msg the message
+     * @param title the title
+     * @param messageType the message type (see {@see JOptionPane})
+     * @param icon the icon to display. Can be null.
+     * @param options the list of options to display. Can be null.
+     * @param defaultOption the default option. Can be null.
+     * @param helpTopic the help topic. Can be null.
+     * @return the index of the selected option or {@link JOptionPane#CLOSED_OPTION}
+     */
+    static public int showOptionDialog(Component parentComponent, Object msg, String title, int messageType, Icon icon, final ButtonSpec[] options, final ButtonSpec defaultOption, final String helpTopic)  {
+        final List<JButton> buttons = createOptionButtons(options, helpTopic);
+        if (helpTopic != null) {
+            buttons.add(createHelpButton(helpTopic));
+        }
+
+        JButton defaultButton = null;
+        if (options != null && defaultOption != null) {
+            for (int i=0; i< options.length; i++) {
+                if (options[i] == defaultOption) {
+                    defaultButton = buttons.get(i);
+                    break;
+                }
+            }
+        }
+
+        if (msg instanceof String) {
+            msg = new JLabel((String)msg);
+        }
+
+        final JOptionPane pane = new JOptionPane(
+                msg,
+                messageType,
+                JOptionPane.DEFAULT_OPTION,
+                icon,
+                buttons.toArray(),
+                defaultButton
+        );
+
+        pane.getValue();
+        final JDialog dialog = new JDialog(
+                JOptionPane.getFrameForComponent(parentComponent),
+                title,
+                ModalityType.APPLICATION_MODAL
+        );
+        dialog.setContentPane(pane);
+        dialog.addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowClosing(WindowEvent e) {
+                pane.setValue(JOptionPane.CLOSED_OPTION);
+                super.windowClosed(e);
+            }
+
+            @Override
+            public void windowOpened(WindowEvent e) {
+                if (defaultOption != null && options != null && options.length > 0) {
+                    int i;
+                    for (i=0; i<options.length;i++) {
+                        if (options[i] == defaultOption) {
+                            break;
+                        }
+                    }
+                    if (i >= options.length) {
+                        buttons.get(0).requestFocusInWindow();
+                    }
+                    buttons.get(i).requestFocusInWindow();
+                } else {
+                    buttons.get(0).requestFocusInWindow();
+                }
+            }
+        });
+        dialog.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0), "close");
+        dialog.getRootPane().getActionMap().put("close", new AbstractAction() {
+            public void actionPerformed(ActionEvent e) {
+                pane.setValue(JOptionPane.CLOSED_OPTION);
+                dialog.setVisible(false);
+            }}
+        );
+
+        if (options != null) {
+            for (int i=0; i < options.length;i++) {
+                final DefaultAction action = new DefaultAction(dialog, pane, i);
+                buttons.get(i).addActionListener(action);
+                buttons.get(i).getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), "enter");
+                buttons.get(i).getActionMap().put("enter", action);
+            }
+        } else {
+            final DefaultAction action = new DefaultAction(dialog, pane, 0);
+            buttons.get(0).addActionListener(action);
+            buttons.get(0).getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), "enter");
+            buttons.get(0).getActionMap().put("enter", action);
+        }
+
+        dialog.pack();
+        WindowGeometry.centerOnScreen(dialog.getSize()).applySafe(dialog);
+        if (helpTopic != null) {
+            HelpUtil.setHelpContext(dialog.getRootPane(), helpTopic);
+        }
+        dialog.setVisible(true);
+        return (Integer)pane.getValue();
+    }
+
+    /**
+     *
+     * @param parentComponent
+     * @param msg
+     * @param title
+     * @param messageType
+     * @param helpTopic
+     * @return
+     * @see #showOptionDialog(Component, Object, String, int, Icon, ButtonSpec[], ButtonSpec, String)
+     */
+    static public int showOptionDialog(Component parentComponent, Object msg, String title, int messageType,final String helpTopic)  {
+        return showOptionDialog(parentComponent, msg, title, messageType, null,null,null, helpTopic);
+    }
+
+    /**
+     * Run it in Event Dispatch Thread.
+     * This version does not return anything, so it is more like showMessageDialog.
+     *
+     * It can be used, when you need to show a message dialog from a worker thread,
+     * e.g. from PleaseWaitRunnable
+     */
+    static public void showMessageDialogInEDT(final Component parentComponent, final Object msg, final String title, final int messageType, final String helpTopic)  {
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+                showOptionDialog(parentComponent, msg, title, messageType, null, null, null, helpTopic);
+            }
+        });
+    }
+}
Index: /applications/editors/josm/plugins/scripting/src/org/openstreetmap/josm/plugins/scripting/RunScriptAction.java
===================================================================
--- /applications/editors/josm/plugins/scripting/src/org/openstreetmap/josm/plugins/scripting/RunScriptAction.java	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/src/org/openstreetmap/josm/plugins/scripting/RunScriptAction.java	(revision 25019)
@@ -0,0 +1,29 @@
+package org.openstreetmap.josm.plugins.scripting;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.Shortcut;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+public class RunScriptAction extends JosmAction{
+	public RunScriptAction() {
+		super(
+			tr("Run..."),        // title
+			"run", 			     // icon name
+			tr("Run a script"),  // tooltip 
+			null,                // no shortcut 
+			false                // don't register
+		);		
+		putValue(MNEMONIC_KEY, KeyEvent.VK_R);
+	}
+
+	@Override
+	public void actionPerformed(ActionEvent evt) {
+		RunScriptDialog dialog = new RunScriptDialog(Main.parent);
+		dialog.setVisible(true);		
+	}		
+}
Index: /applications/editors/josm/plugins/scripting/src/org/openstreetmap/josm/plugins/scripting/RunScriptDialog.java
===================================================================
--- /applications/editors/josm/plugins/scripting/src/org/openstreetmap/josm/plugins/scripting/RunScriptDialog.java	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/src/org/openstreetmap/josm/plugins/scripting/RunScriptDialog.java	(revision 25019)
@@ -0,0 +1,375 @@
+package org.openstreetmap.josm.plugins.scripting;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.activation.MimetypesFileTypeMap;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.SideButton;
+import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
+import org.openstreetmap.josm.gui.help.HelpUtil;
+import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
+import org.openstreetmap.josm.gui.widgets.HtmlPanel;
+import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.WindowGeometry;
+
+/**
+ * <p><strong>RunScriptDialog</strong> provides a modal dialog for selecting and
+ * running a script.</p> 
+ */
+public class RunScriptDialog extends JDialog {
+	static private final Logger logger = Logger.getLogger(RunScriptDialog.class.getName());
+	
+	/**
+	 * <p>The preferences key for the script file history.</p> 
+	 */
+	static private final String PREF_KEY_FILE_HISTORY = "scripting.RunScriptDialog.file-history";
+	
+	/**
+	 * <p>The preferences key for the last script file name entered in the script file
+	 * selection field.</p> 
+	 */	
+	static private final String PREF_KEY_LAST_FILE = "scripting.RunScriptDialog.last-file";
+
+	/** the input field for the script file name */
+	private HistoryComboBox cbScriptFile;
+	
+	/**
+	 * Constructor
+	 * 
+	 * @param owner the dialog owner 
+	 */
+	public RunScriptDialog(Component parent) {
+		super(JOptionPane.getFrameForComponent(parent), true);
+		build();
+	}
+	
+	protected JPanel buildInfoPanel() {
+		JPanel pnl = new JPanel(new BorderLayout());
+		HtmlPanel info = new HtmlPanel();
+		info.setText(
+				"<html>"
+			+  	tr("Select a script file and click on <strong>Run</strong>.")
+		    +	"</html>"
+		);
+		pnl.add(info, BorderLayout.CENTER);
+		return pnl;
+	}
+	
+	protected JPanel buildControlButtonPanel() {
+		JPanel pnl = new JPanel(new FlowLayout(FlowLayout.CENTER));
+		pnl.add(new SideButton(new RunAction()));
+		pnl.add(new SideButton(new CancelAction()));
+		pnl.add(new SideButton(new ContextSensitiveHelpAction(HelpUtil.ht("/Plugin/Macro#Run"))));
+		return pnl;
+	}
+	
+	protected JPanel buildMacroFileInputPanel() {
+		JPanel pnl = new JPanel(new GridBagLayout());
+		GridBagConstraints gc = new GridBagConstraints();
+		gc.gridx = 0; 
+		gc.weightx = 0.0;
+		gc.weighty = 0.0;
+		gc.insets = new Insets(3,3,3,3);
+		gc.fill = GridBagConstraints.BOTH;
+		
+		pnl.add(new JLabel(tr("File:")), gc);
+		
+		cbScriptFile = new HistoryComboBox();		
+		SelectAllOnFocusGainedDecorator.decorate((JTextField)cbScriptFile.getEditor().getEditorComponent());
+		cbScriptFile.setToolTipText(tr("Enter the name of a script file"));
+		gc.gridx = 1; 
+		gc.weightx = 1.0;
+		gc.insets = new Insets(3,3,3,0 /* no spacing to the right */); 
+		gc.fill = GridBagConstraints.BOTH;
+		pnl.add(cbScriptFile, gc);
+		
+		gc.gridx = 2; 
+		gc.weightx = 0.0;
+		gc.fill = GridBagConstraints.BOTH;
+		gc.insets = new Insets(3,0 /* no spacing to the left */,3,3);
+		pnl.add(new JButton(new SelectMacroFileAction()), gc);
+				
+		// just a filler 
+		JPanel filler = new JPanel();
+		gc.gridx = 0;
+		gc.gridy = 1;
+		gc.gridwidth =3;
+		gc.weightx = 1.0;
+		gc.weighty = 1.0;
+		gc.fill = GridBagConstraints.BOTH;
+		pnl.add(filler, gc);
+		
+		return pnl;
+	}
+	
+	protected JPanel buildContentPanel() {
+		JPanel pnl = new JPanel(new BorderLayout());
+		pnl.add(buildInfoPanel(), BorderLayout.NORTH);
+		pnl.add(buildMacroFileInputPanel(), BorderLayout.CENTER);
+		pnl.add(buildControlButtonPanel(), BorderLayout.SOUTH);
+		return pnl;
+	}
+	
+	protected void build() {
+		getContentPane().setLayout(new BorderLayout());
+		getContentPane().add(buildContentPanel(), BorderLayout.CENTER);
+		
+		setTitle(tr("Run a script"));
+		setSize(600, 150);
+	}
+	
+	@Override
+	public void setVisible(boolean visible) {
+		if (visible) {
+			/*
+			 * Restore the file history and the last entered script file name
+			 * from preferences
+			 */
+	        List<String> fileHistory = new LinkedList<String>(
+	        		Main.pref.getCollection(PREF_KEY_FILE_HISTORY, new LinkedList<String>())
+	        );
+	        Collections.reverse(fileHistory);
+	        cbScriptFile.setPossibleItems(fileHistory);
+	        String lastFile = Main.pref.get(PREF_KEY_LAST_FILE);
+	        if (lastFile != null && !lastFile.trim().isEmpty()){
+	        	cbScriptFile.setText(lastFile.trim());
+	        }
+	        WindowGeometry.centerInWindow(getParent(),new Dimension(600,150)).applySafe(this);
+		} else {
+			/*
+			 * Persist the file history script file name
+			 * in the preferences
+			 */
+			String currentFile = cbScriptFile.getText();
+			Main.pref.put(PREF_KEY_FILE_HISTORY, currentFile.trim());
+			Main.pref.putCollection(PREF_KEY_LAST_FILE, cbScriptFile.getHistory());			
+		}
+		super.setVisible(visible);
+	}
+
+	private class CancelAction extends AbstractAction {
+		public CancelAction() {
+			putValue(NAME, tr("Cancel"));
+			putValue(SHORT_DESCRIPTION, tr("Cancel"));
+			putValue(SMALL_ICON, ImageProvider.get("cancel"));
+		}
+		
+		@Override
+		public void actionPerformed(ActionEvent evt) {
+			setVisible(false);
+		}				
+	}
+	
+	private class RunAction extends AbstractAction {
+		public RunAction() {
+			putValue(NAME, tr("Run"));
+			putValue(SHORT_DESCRIPTION, tr("Run the script"));
+			putValue(SMALL_ICON, ImageProvider.get("run"));
+		}
+		
+		protected void warnMacroFileDoesntExist(File f){			
+			HelpAwareOptionPane.showOptionDialog(
+					null,
+					tr("The script file ''{0}'' doesn''t exist.", f.toString()),
+					tr("File not found"),
+					JOptionPane.ERROR_MESSAGE,
+					null // no help topic
+			);			
+		}
+		
+		protected void warnEmptyFile(){			
+			HelpAwareOptionPane.showOptionDialog(
+					cbScriptFile,
+					tr("Please enter a file name first."),
+					tr("Empty file name"),
+					JOptionPane.ERROR_MESSAGE,
+					null // no help topic
+			);			
+		}
+		
+		protected void warnMacroFileIsntReadable(File f){
+			HelpAwareOptionPane.showOptionDialog(
+					RunScriptDialog.this,
+					tr("The script file ''{0}'' isn't readable.", f.toString()),
+					tr("File not readable"),
+					JOptionPane.ERROR_MESSAGE,
+					null // no help topic
+			);			
+		}
+		
+		protected void warnFailedToOpenMacroFile(File f, Exception e){
+			HelpAwareOptionPane.showOptionDialog(
+					RunScriptDialog.this,
+					tr("Failed to read the script from the file ''{0}''.", f.toString()),
+					tr("IO error"),
+					JOptionPane.ERROR_MESSAGE,
+					null // no help topic
+			);			
+			System.out.println(tr("Failed to read a macro from the file ''{0}''.", f.toString()));
+			e.printStackTrace();			
+		}
+		
+		protected void warnExecutingScriptFailed(ScriptException e){
+			HelpAwareOptionPane.showOptionDialog(
+					RunScriptDialog.this,
+					tr("Script execution has failed."),
+					tr("Script Error"),
+					JOptionPane.ERROR_MESSAGE,
+					null // no help topic
+			);			
+			System.out.println(tr("Macro execution has failed."));
+			e.printStackTrace();
+		}
+		
+		protected void warnNoScriptingEnginesInstalled() {
+			HelpAwareOptionPane.showOptionDialog(
+					RunScriptDialog.this,
+					"<html>"
+					+ tr(
+						"<p>The script can''t be executed, becasue there are currently no scripting engines installed.</p>"
+						+ "<p>Refer to the online help for information about how to install a scripting engine with JOSM.</p>"						
+					)					
+					+ "</html>"
+					,
+					tr("No scripting engine"),
+					JOptionPane.ERROR_MESSAGE,
+					null // no help topic
+			);
+		}
+		
+		protected ScriptEngine getScriptEngine(File file) {
+			ScriptEngineManager mgr = new ScriptEngineManager(getClass().getClassLoader());
+			Matcher matcher = Pattern.compile("\\.([^\\.]+)$").matcher(file.toString());
+			
+			// can we derive a suitable script engine from the file name?			
+			MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();
+			// FIXME: provide a resources file for script mime types; provide an editor
+			// for these mappings in the preferences
+			mimeTypesMap.addMimeTypes("application/x-groovy groovy");
+			String mt = mimeTypesMap.getContentType(file);
+			if (mt != null){
+				ScriptEngine engine = mgr.getEngineByMimeType(mt);
+				if (engine != null) return engine;	
+			}
+			
+			// no script engine at all? Abort.
+			List<ScriptEngineFactory> factories = mgr.getEngineFactories();
+			if (factories.isEmpty()) {
+				warnNoScriptingEnginesInstalled();
+				return null;
+			}
+			// let the user select a script engine
+			return ScriptEngineSelectionDialog.select(RunScriptDialog.this); 
+		}
+		
+		@Override
+		public void actionPerformed(ActionEvent evt) {
+			String fileName = cbScriptFile.getText().trim();
+			if (fileName.isEmpty()){
+				warnEmptyFile();
+				return;
+			}
+			final File f = new File(fileName);
+			if (! f.exists() || !f.isFile()) {
+				warnMacroFileDoesntExist(f);
+				return;
+			} else if (!f.canRead()) {
+				warnMacroFileIsntReadable(f);
+				return;
+			}
+			
+			cbScriptFile.addCurrentItemToHistory();
+			
+			try {
+				new FileReader(f);
+			} catch(IOException e){
+				warnFailedToOpenMacroFile(f, e);
+				return;
+			} 			
+			final ScriptEngine engine = getScriptEngine(f);
+			if (engine == null) return;
+			SwingUtilities.invokeLater(
+			    new Runnable() {
+			    	public void run() {			
+			    		FileReader reader = null;
+						try {
+							reader = new FileReader(f);
+							engine.eval(reader);
+						} catch(ScriptException e){
+							warnExecutingScriptFailed(e);
+						} catch(IOException e){
+							warnFailedToOpenMacroFile(f, e);
+						} finally {
+							if (reader != null){
+								try {reader.close();} catch(IOException e) {}
+							}
+						}
+			    	}
+			    }
+		    );
+			setVisible(false);		
+		}	
+	}
+	
+	private class SelectMacroFileAction extends AbstractAction {
+		public SelectMacroFileAction() {
+			putValue(NAME, tr("..."));
+			putValue(SHORT_DESCRIPTION, tr("Launch file selection dialog"));
+		}
+		
+		@Override
+		public void actionPerformed(ActionEvent evt) {
+			String fileName = cbScriptFile.getText().trim();
+			File currentFile = null;
+			if (! fileName.isEmpty()) {
+				currentFile = new File(fileName);
+			}
+			JFileChooser chooser = new JFileChooser();
+			chooser.setDialogTitle(tr("Select a script"));
+			chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+			chooser.setMultiSelectionEnabled(false);
+			if (currentFile != null){
+				chooser.setCurrentDirectory(currentFile);
+				chooser.setSelectedFile(currentFile);
+			}
+			int ret = chooser.showOpenDialog(RunScriptDialog.this);			
+			if (ret != JFileChooser.APPROVE_OPTION) return;
+			
+			currentFile = chooser.getSelectedFile();
+			cbScriptFile.setText(currentFile.toString());			
+		}	
+	}
+}
Index: /applications/editors/josm/plugins/scripting/src/org/openstreetmap/josm/plugins/scripting/ScriptEngineSelectionDialog.java
===================================================================
--- /applications/editors/josm/plugins/scripting/src/org/openstreetmap/josm/plugins/scripting/ScriptEngineSelectionDialog.java	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/src/org/openstreetmap/josm/plugins/scripting/ScriptEngineSelectionDialog.java	(revision 25019)
@@ -0,0 +1,323 @@
+package org.openstreetmap.josm.plugins.scripting;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+import javax.script.ScriptEngineManager;
+import javax.swing.AbstractAction;
+import javax.swing.AbstractListModel;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.KeyStroke;
+import javax.swing.ListCellRenderer;
+import javax.swing.ListSelectionModel;
+import javax.swing.UIManager;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.SideButton;
+import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
+import org.openstreetmap.josm.gui.help.HelpUtil;
+import org.openstreetmap.josm.gui.widgets.HtmlPanel;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.WindowGeometry;
+
+/**
+ * <strong>ScriptEngineSelectionDialog</strong> allows to select one of the available
+ * JSR-223 compatible script engines.
+ *
+ */
+public class ScriptEngineSelectionDialog extends JDialog {
+
+	/**
+	 * <p>Launches a modal dialog for selecting a script engine.</p>
+	 * 
+	 * @param parent the parent component for the dialog. Assumes {@code Main.parent} if
+	 * null
+	 *  
+	 * @return the selected script engine, or null, if the user didn't select an engine
+	 */
+	static public ScriptEngine select(Component parent){
+		if (parent == null) parent = Main.parent;
+		ScriptEngineSelectionDialog dialog = new ScriptEngineSelectionDialog(parent);
+		dialog.setVisible(true);
+		return dialog.selectedEngine;
+	}
+
+	/**
+	 * <p>Launches a modal dialog for selecting a script engine. The dialog is opend
+	 * with {@code Main.parent} as owner.</p>
+	 *  
+	 * @return the selected script engine, or null, if the user didn't select an engine
+	 */
+	static public ScriptEngine select(){
+		return select(Main.parent);
+	}
+	
+	private JList lstEngines;
+	private JButton btnOK;
+	private ScriptEngine selectedEngine;
+	private ScriptEngineListModel model;
+	private OKAction actOK;
+	
+	/**
+	 * <p>Creates a new dialog.</p>
+	 * 
+	 * @param parent the parent. Uses {@link JOptionPane#getFrameForComponent(Component)} to 
+	 * determine the owner frame.
+	 */
+	public ScriptEngineSelectionDialog(Component parent) {
+		super(JOptionPane.getFrameForComponent(parent), true /* modal */);
+		build();
+	}
+	
+	protected JPanel buildInfoPanel() {
+		JPanel pnl = new JPanel(new BorderLayout());
+		HtmlPanel info = new HtmlPanel();
+		info.setText(
+				"<html>"
+				+ tr("Please select a scripting engine to execute the selected script.")
+				+ "</html>"
+		);
+		pnl.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
+		pnl.add(info, BorderLayout.CENTER);
+		return pnl;
+	}
+	
+	protected JPanel buildControlButtonPanel() {
+		JPanel pnl = new JPanel(new FlowLayout(FlowLayout.CENTER));
+		SideButton btn;
+		pnl.add(btnOK = new SideButton(actOK = new OKAction()));
+		btnOK.setFocusable(true);
+		CancelAction actCancel;
+		pnl.add(btn = new SideButton(actCancel = new CancelAction()));
+		btn.setFocusable(true);
+		pnl.add(btn = new SideButton(new ContextSensitiveHelpAction(HelpUtil.ht("/Plugins/Scripting#SelectScriptingEngine"))));
+		btn.setFocusable(true);
+		
+		// Ctrl-Enter triggers OK
+		getRootPane().registerKeyboardAction(
+				actOK,  
+				KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_DOWN_MASK), 
+				JComponent.WHEN_IN_FOCUSED_WINDOW
+		);
+		
+		// ESC triggers Cancel 
+		getRootPane().registerKeyboardAction(
+				actCancel,  
+				KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), 
+				JComponent.WHEN_IN_FOCUSED_WINDOW
+		);
+		return pnl;
+	}
+	
+	protected JPanel buildScriptEngineListPanel() {
+		JPanel pnl = new JPanel(new BorderLayout());
+		lstEngines = new JList(model = new ScriptEngineListModel());
+		lstEngines.setCellRenderer(new ScriptEngineCellRenderer());
+		pnl.add(lstEngines, BorderLayout.CENTER);
+		lstEngines.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+		lstEngines.setSelectedIndex(0);
+		
+		lstEngines.addMouseListener(
+				new MouseAdapter() {					
+					@Override
+					public void mouseClicked(MouseEvent e) {
+						if (e.getClickCount() >= 2) {
+							actOK.execute();
+						}
+					}
+				}
+		);
+		
+		return pnl;			
+	}
+	
+	protected void build() {
+		Container c = getContentPane();
+		c.setLayout(new BorderLayout());
+		c.add(buildInfoPanel(), BorderLayout.NORTH);
+		c.add(buildScriptEngineListPanel(), BorderLayout.CENTER);
+		c.add(buildControlButtonPanel(), BorderLayout.SOUTH);
+		
+		lstEngines.getSelectionModel().addListSelectionListener((OKAction)btnOK.getAction());
+		
+		// Respond to 'Enter' in the list
+		lstEngines.registerKeyboardAction(
+				actOK, 
+				KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), 
+				JComponent.WHEN_FOCUSED
+		);
+	}
+	
+	private class OKAction extends AbstractAction implements ListSelectionListener {
+		public OKAction() {
+			putValue(NAME, tr("OK"));
+			putValue(SHORT_DESCRIPTION, tr("Accept the selected scripting engine"));
+			putValue(SMALL_ICON, ImageProvider.get("ok"));
+		}
+		
+		public void execute() {
+			int selIndex = lstEngines.getSelectedIndex();
+			selectedEngine = selIndex < 0 ? null: model.getScriptEngine(selIndex) ;
+			setVisible(false);
+		}
+
+		@Override
+		public void actionPerformed(ActionEvent evt) {
+			execute();
+		}
+
+		@Override
+		public void valueChanged(ListSelectionEvent e) {
+			setEnabled(lstEngines.getSelectedIndex() >=0);
+		}
+	}
+
+	private class CancelAction extends AbstractAction {
+		public CancelAction() {
+			putValue(NAME, tr("Cancel"));
+			putValue(SHORT_DESCRIPTION, tr("cancel"));
+			putValue(SMALL_ICON, ImageProvider.get("cancel"));			
+		}
+
+		@Override
+		public void actionPerformed(ActionEvent evt) {
+			selectedEngine = null;
+			setVisible(false);
+		}
+	}
+	
+	@Override
+	public void setVisible(boolean visible) {
+		if (visible) {
+			btnOK.requestFocusInWindow();
+			WindowGeometry
+				.centerInWindow(getParent(), new Dimension(250, 300))
+				.applySafe(this);
+		}
+		super.setVisible(visible);
+	}
+
+	/**
+	 * <p>Provides a list model for the list of available script engines.</p>
+	 */
+	private static class ScriptEngineListModel extends AbstractListModel {
+		
+		private List<ScriptEngineFactory> factories;
+		
+		public ScriptEngineListModel(){
+			ScriptEngineManager mgr = new ScriptEngineManager(getClass().getClassLoader());
+			factories = new ArrayList<ScriptEngineFactory>(mgr.getEngineFactories());
+			Collections.sort(factories,
+					new Comparator<ScriptEngineFactory>() {
+						@Override
+						public int compare(ScriptEngineFactory f1, ScriptEngineFactory f2) {
+							return f1.getEngineName().compareTo(f2.getEngineName());
+						}
+					}
+			);	
+		}
+				
+		/**
+		 * <p>Replies a script engine created by the i-th script engine factory.</p>
+		 * 
+		 * @param i the index
+		 * @return the engine
+		 */
+		public ScriptEngine getScriptEngine(int i){
+			ScriptEngine engine = factories.get(i).getScriptEngine();
+			return engine;
+		}
+
+		@Override
+		public Object getElementAt(int i) {
+			return factories.get(i);
+		}
+
+		@Override
+		public int getSize() {
+			return factories.size();
+		}		
+	}
+	
+	/**
+	 * <p>Implements a list cell renderer for the list of scripting engines.</p>
+	 *
+	 */
+	private static class ScriptEngineCellRenderer implements ListCellRenderer {
+
+		private final JLabel lbl = new JLabel();
+		
+		protected String getDisplayName(ScriptEngineFactory factory){
+			return tr("{1} (with engine {0})", factory.getEngineName(), factory.getLanguageName());
+		}
+		
+		protected String getTooltipText(ScriptEngineFactory factory){
+			StringBuilder sb = new StringBuilder();
+			sb.append("<html>");
+			sb.append("<strong>").append(tr("Name:")).append("</strong> ").append(factory.getEngineName()).append("<br>");
+			sb.append("<strong>").append(tr("Version:")).append("</strong> ").append(factory.getEngineVersion()).append("<br>");
+			sb.append("<strong>").append(tr("Language:")).append("</strong> ").append(factory.getLanguageName()).append("<br>");
+			sb.append("<strong>").append(tr("Language version:")).append("</strong> ").append(factory.getLanguageVersion()).append("<br>");
+			sb.append("<strong>").append(tr("MIME-Types:")).append("</strong> ");
+			List<String> types = factory.getMimeTypes();
+			for(int i=0; i<types.size(); i++){
+				if (i > 0 )sb.append(", ");
+				sb.append(types.get(i));
+			}
+			sb.append("<br>");
+			sb.append("</html>");
+			
+			return sb.toString();
+		}
+		
+		protected void renderColors(boolean selected){
+			if (!selected){
+				lbl.setForeground(UIManager.getColor("List.foreground"));
+				lbl.setBackground(UIManager.getColor("List.background"));
+			} else {
+				lbl.setForeground(UIManager.getColor("List.selectionForeground"));
+				lbl.setBackground(UIManager.getColor("List.selectionBackground"));
+			}
+		}
+		
+		public ScriptEngineCellRenderer() {		
+			lbl.setOpaque(true);
+			lbl.setBorder(BorderFactory.createEmptyBorder(1, 3, 1, 3));
+			lbl.setIcon(ImageProvider.get("script-engine"));
+		}
+		
+		@Override
+		public Component getListCellRendererComponent(JList list, Object obj,int index, boolean isSelected, boolean cellHasFocus) {
+			ScriptEngineFactory factory = (ScriptEngineFactory)obj;
+			renderColors(isSelected);
+			lbl.setText(getDisplayName(factory));
+			lbl.setToolTipText(getTooltipText(factory));
+			return lbl;
+		}		
+	}
+}
Index: /applications/editors/josm/plugins/scripting/src/org/openstreetmap/josm/plugins/scripting/ScriptingPlugin.java
===================================================================
--- /applications/editors/josm/plugins/scripting/src/org/openstreetmap/josm/plugins/scripting/ScriptingPlugin.java	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/src/org/openstreetmap/josm/plugins/scripting/ScriptingPlugin.java	(revision 25019)
@@ -0,0 +1,32 @@
+package org.openstreetmap.josm.plugins.scripting;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import javax.swing.JMenu;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.plugins.Plugin;
+import org.openstreetmap.josm.plugins.PluginInformation;
+
+public class ScriptingPlugin extends Plugin {
+	
+	private static ScriptingPlugin instance;
+	
+	public static ScriptingPlugin getInstance() {
+		return instance;
+	
+	}
+	
+	public ScriptingPlugin(PluginInformation info) {
+		super(info);
+		instance = this;
+		installScriptsMenu();
+	}
+	
+	protected void installScriptsMenu(){
+		JMenu mnuMacro;
+		Main.main.menu.add(mnuMacro = new JMenu(tr("Scripts")));
+		mnuMacro.setMnemonic('S');
+		mnuMacro.add(new RunScriptAction());		
+	}
+}
Index: /applications/editors/josm/plugins/scripting/test/common/org/openstreetmap/josm/plugins/scripting/fixtures/JOSMFixture.java
===================================================================
--- /applications/editors/josm/plugins/scripting/test/common/org/openstreetmap/josm/plugins/scripting/fixtures/JOSMFixture.java	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/test/common/org/openstreetmap/josm/plugins/scripting/fixtures/JOSMFixture.java	(revision 25019)
@@ -0,0 +1,76 @@
+package org.openstreetmap.josm.plugins.scripting.fixtures;
+
+
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.text.MessageFormat;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.projection.Mercator;
+import org.openstreetmap.josm.io.OsmApi;
+import org.openstreetmap.josm.tools.I18n;
+
+public class JOSMFixture {
+    static private final Logger logger = Logger.getLogger(JOSMFixture.class.getName());
+
+    static public JOSMFixture createUnitTestFixture() {
+        return new JOSMFixture("/test-env.properties");
+    }
+
+    private Properties testProperties;
+    private String testPropertiesResourceName;
+
+    public JOSMFixture(String testPropertiesResourceName) {
+        this.testPropertiesResourceName = testPropertiesResourceName;
+    }
+
+    public void init() {
+        testProperties = new Properties();
+     
+        // load properties
+        //
+        try {
+            testProperties.load(JOSMFixture.class.getResourceAsStream(testPropertiesResourceName));
+        } catch(Exception e){
+            logger.log(Level.SEVERE, MessageFormat.format("failed to load property file ''{0}''", testPropertiesResourceName));
+            fail(MessageFormat.format("failed to load property file ''{0}''. \nMake sure the path ''$project_root/test/config'' is on the classpath.", testPropertiesResourceName));
+        }
+
+        // check josm.home
+        //
+        String josmHome = testProperties.getProperty("josm.home");
+        if (josmHome == null) {
+            fail(MessageFormat.format("property ''{0}'' not set in test environment", "josm.home"));
+        } else {
+            File f = new File(josmHome);
+            if (! f.exists() || ! f.canRead()) {
+                fail(MessageFormat.format("property ''{0}'' points to ''{1}'' which is either not existing or not readable.\nEdit ''{2}'' and update the value ''josm.home''. ", "josm.home", josmHome,testPropertiesResourceName ));
+            }
+        }
+        System.setProperty("josm.home", josmHome);
+        Main.pref = new Preferences();
+        I18n.init();
+        // initialize the plaform hook, and
+        Main.determinePlatformHook();
+        // call the really early hook before we anything else
+        Main.platform.preStartupHook();
+
+        Main.pref.init(false);
+
+        // init projection
+        Main.proj = new Mercator();
+
+        // make sure we don't upload to or test against production
+        //
+        String url = OsmApi.getOsmApi().getBaseUrl().toLowerCase().trim();
+        if (url.startsWith("http://www.openstreetmap.org")
+                || url.startsWith("http://api.openstreetmap.org")) {
+            fail(MessageFormat.format("configured server url ''{0}'' seems to be a productive url, aborting.", url));
+        }
+    }
+}
Index: /applications/editors/josm/plugins/scripting/test/conf/test-unit-env.properties
===================================================================
--- /applications/editors/josm/plugins/scripting/test/conf/test-unit-env.properties	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/test/conf/test-unit-env.properties	(revision 25019)
@@ -0,0 +1,11 @@
+#
+# This file includes properties which are used by all contouralign unit tests 
+#
+
+#### 
+# josm.home - the home directory of the JOSM installation to be used in unit tests
+#
+# This is the home directory for JOSM preferences: ${josm.home}\preferences
+# This is the home directory for JOSM plugins: ${josm.home}\plugins\*.jar
+#
+josm.home=C:\\data\\eclipse-ws\\eclipse-3.6.1\\JOSM plugins\\plugins\\scripting\\test\\josm.home
Index: /applications/editors/josm/plugins/scripting/test/functional/org/openstreetmap/josm/plugins/scripting/RunScriptDialogTest.java
===================================================================
--- /applications/editors/josm/plugins/scripting/test/functional/org/openstreetmap/josm/plugins/scripting/RunScriptDialogTest.java	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/test/functional/org/openstreetmap/josm/plugins/scripting/RunScriptDialogTest.java	(revision 25019)
@@ -0,0 +1,38 @@
+package org.openstreetmap.josm.plugins.scripting;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+
+import org.openstreetmap.josm.plugins.contourmerge.fixtures.JOSMFixture;
+import org.openstreetmap.josm.plugins.scripting.RunScriptDialog;
+
+
+public class RunScriptDialogTest extends JFrame {
+	
+	private JOSMFixture fixture;
+	
+	public RunScriptDialogTest() {
+		getContentPane().setLayout(new FlowLayout());
+		setSize(100,100);
+		JButton btn = new JButton("Launch");
+		getContentPane().add(btn);
+		btn.addActionListener(new ActionListener() {			
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				RunScriptDialog dialog = new RunScriptDialog(RunScriptDialogTest.this);
+				dialog.setVisible(true);
+			}
+		});
+		
+		fixture = JOSMFixture.createUnitTestFixture();
+		fixture.init();				
+	}
+		
+	static public void main(String args[]) {
+		RunScriptDialogTest app = new RunScriptDialogTest();
+		app.setVisible(true);
+	}
+}
Index: /applications/editors/josm/plugins/scripting/test/functional/org/openstreetmap/josm/plugins/scripting/ScriptEngineSelectionDialogTest.java
===================================================================
--- /applications/editors/josm/plugins/scripting/test/functional/org/openstreetmap/josm/plugins/scripting/ScriptEngineSelectionDialogTest.java	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/test/functional/org/openstreetmap/josm/plugins/scripting/ScriptEngineSelectionDialogTest.java	(revision 25019)
@@ -0,0 +1,38 @@
+package org.openstreetmap.josm.plugins.scripting;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+
+import org.openstreetmap.josm.plugins.contourmerge.fixtures.JOSMFixture;
+import org.openstreetmap.josm.plugins.scripting.RunScriptDialog;
+
+
+public class ScriptEngineSelectionDialogTest extends JFrame {
+	
+	private JOSMFixture fixture;
+	
+	public ScriptEngineSelectionDialogTest() {
+		getContentPane().setLayout(new FlowLayout());
+		setSize(100,100);
+		JButton btn = new JButton("Launch");
+		getContentPane().add(btn);
+		btn.addActionListener(new ActionListener() {			
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				ScriptEngineSelectionDialog dialog = new ScriptEngineSelectionDialog(ScriptEngineSelectionDialogTest.this);
+				dialog.setVisible(true);
+			}
+		});
+		
+		fixture = JOSMFixture.createUnitTestFixture();
+		fixture.init();				
+	}
+		
+	static public void main(String args[]) {
+		ScriptEngineSelectionDialogTest app = new ScriptEngineSelectionDialogTest();
+		app.setVisible(true);
+	}
+}
Index: /applications/editors/josm/plugins/scripting/test/josm.home/preferences
===================================================================
--- /applications/editors/josm/plugins/scripting/test/josm.home/preferences	(revision 25019)
+++ /applications/editors/josm/plugins/scripting/test/josm.home/preferences	(revision 25019)
@@ -0,0 +1,1 @@
+osm-server.url=http://localhost:8080/api
