Index: /applications/editors/josm/plugins/poly/build.xml
===================================================================
--- /applications/editors/josm/plugins/poly/build.xml	(revision 28570)
+++ /applications/editors/josm/plugins/poly/build.xml	(revision 28570)
@@ -0,0 +1,236 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<!--
+** This is a template build file for the PBF plugin.
+**
+** Maintaining versions
+** ====================
+** see README.template
+**
+** Usage
+** =====
+** To build it run
+**
+**    > ant  dist
+**
+** To install the generated plugin locally (in you default plugin directory) run
+**
+**    > ant  install
+**
+** The generated plugin jar is not automatically available in JOSMs plugin configuration
+** dialog. You have to check it in first.
+**
+** Use the ant target 'publish' to check in the plugin and make it available to other
+** JOSM users:
+**    set the properties commit.message and plugin.main.version
+** and run
+**    > ant  publish
+**
+**
+-->
+<project name="poly" default="dist" basedir=".">
+    <!-- enter the SVN commit message -->
+    <property name="commit.message" value="Commit message"/>
+    <!-- enter the *lowest* JOSM version this plugin is currently compatible with -->
+    <property name="plugin.main.version" value="4523"/>
+    <!-- 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="ant.build.javac.source" value="1.6"/>
+    <property name="ant.build.javac.target" value="1.6"/>
+    <property name="plugin.dist.dir" value="../../dist"/>
+    <property name="plugin.jar" value="${plugin.dist.dir}/${ant.project.name}.jar"/>
+    <!--
+    **********************************************************
+    ** 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 classpath="${josm}" debug="true" destdir="${plugin.build.dir}" includeAntRuntime="false">
+            <compilerarg value="-Xlint:deprecation"/>
+            <compilerarg value="-Xlint:unchecked"/>
+        	<src path="src" />
+        </javac>
+    </target>
+    <!--
+    **********************************************************
+    ** dist - creates the plugin jar
+    **********************************************************
+    -->
+    <target name="dist" depends="compile,revision">
+        <echo message="creating ${ant.project.name}.jar ... "/>
+        <copy todir="${plugin.build.dir}/resources">
+            <fileset dir="resources"/>
+        </copy>
+        <copy todir="${plugin.build.dir}/images">
+            <fileset dir="images"/>
+        </copy>
+        <copy todir="${plugin.build.dir}/data">
+            <fileset dir="data"/>
+        </copy>
+        <copy todir="${plugin.build.dir}">
+            <fileset dir=".">
+                <include name="README"/>
+                <include name="gpl-3.0.txt"/>
+            </fileset>
+        </copy>
+        <jar destfile="${plugin.jar}" basedir="${plugin.build.dir}">
+            <!--
+            ************************************************
+            ** configure these properties. Most of them will be copied to the plugins
+            ** manifest file. Property values will also show up in the list available
+            ** plugins: http://josm.openstreetmap.de/wiki/Plugins.
+            **
+            ************************************************
+            -->
+            <manifest>
+                <attribute name="Author" value="Zverik"/>
+                <attribute name="Plugin-Class" value="poly.PolyPlugin"/>
+                <attribute name="Plugin-Date" value="${version.entry.commit.date}"/>
+                <attribute name="Plugin-Description" value="Read and write osmosis' poly files"/>
+                <attribute name="Plugin-Early" value="false"/>
+                <!--<attribute name="Plugin-Icon" value="images/pbf_24.png"/>-->
+                <attribute name="Plugin-Link" value="http://wiki.openstreetmap.org/wiki/Osmosis/Polygon_Filter_File_Format"/>
+                <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">
+        <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>
+</project>
Index: /applications/editors/josm/plugins/poly/src/poly/DownloadPolyTask.java
===================================================================
--- /applications/editors/josm/plugins/poly/src/poly/DownloadPolyTask.java	(revision 28570)
+++ /applications/editors/josm/plugins/poly/src/poly/DownloadPolyTask.java	(revision 28570)
@@ -0,0 +1,55 @@
+package poly;
+
+import java.util.concurrent.Future;
+import org.openstreetmap.josm.Main;
+import static org.openstreetmap.josm.tools.I18n.tr;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.OsmServerReader;
+import org.openstreetmap.josm.io.OsmTransferException;
+
+/**
+ * Download task for remote control to download poly files.
+ * 
+ * @author zverik
+ */
+public class DownloadPolyTask extends DownloadOsmTask {
+
+    @Override
+    public Future<?> download( boolean newLayer, Bounds downloadArea, ProgressMonitor progressMonitor ) {
+        return null;
+    }
+
+    @Override
+    public Future<?> loadUrl( boolean new_layer, String url, ProgressMonitor progressMonitor ) {
+        downloadTask = new DownloadTask(new_layer, new ServerPolyReader(url), progressMonitor);
+        return Main.worker.submit(downloadTask);
+    }
+
+    @Override
+    public boolean acceptsUrl( String url ) {
+        return url != null && url.matches("http://.*/.*\\.poly");
+    }
+    
+    public class ServerPolyReader extends OsmServerReader {
+        private String url;
+
+        public ServerPolyReader( String url ) {
+            this.url = url;
+        }
+
+        @Override
+        public DataSet parseOsm( ProgressMonitor progressMonitor ) throws OsmTransferException {
+            try {
+                progressMonitor.beginTask(tr("Contacting Server...", 10));
+                return new PolyImporter().parseDataSet(url);
+            } catch( Exception e ) {
+                throw new OsmTransferException(e);
+            } finally {
+                progressMonitor.finishTask();
+            }
+        }
+    }
+}
Index: /applications/editors/josm/plugins/poly/src/poly/PolyExporter.java
===================================================================
--- /applications/editors/josm/plugins/poly/src/poly/PolyExporter.java	(revision 28570)
+++ /applications/editors/josm/plugins/poly/src/poly/PolyExporter.java	(revision 28570)
@@ -0,0 +1,100 @@
+package poly;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TreeMap;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.io.OsmExporter;
+
+/**
+ * Writes poly files.
+ * 
+ * @author zverik
+ */
+public class PolyExporter extends OsmExporter {
+
+    public PolyExporter() {
+        super(PolyType.FILE_FILTER);
+    }
+
+    @Override
+    public void exportData( File file, Layer layer ) throws IOException {
+        if( layer instanceof OsmDataLayer ) {
+            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF8"));
+            try {
+                DataSet ds = ((OsmDataLayer)layer).data;
+                Map<Way, Boolean> ways = new TreeMap<Way, Boolean>(new AreaComparator());
+                String polygonName = layer.getName();
+                for( Way w : ds.getWays() ) {
+                    if( w.isClosed() ) {
+                        boolean outer = true;
+                        for( OsmPrimitive p : w.getReferrers() ) {
+                            if( p instanceof Relation && ((Relation)p).isMultipolygon() ) {
+                                for( RelationMember m : ((Relation)p).getMembers() ) {
+                                    if( m.refersTo(w) && "inner".equals(m.getRole()) ) {
+                                        outer = false;
+                                        break;
+                                    }
+                                }
+                            }
+                            if( !outer ) break;
+                        }
+                        ways.put(w, outer);
+                        if( w.hasKey("name") )
+                            polygonName = w.get("name");
+                    }
+                }
+
+                int counter = 1;
+                writer.write(polygonName);
+                writer.newLine();
+                for( Way w : ways.keySet() ) {
+                    if( !ways.get(w) )
+                        writer.write('!');
+                    writer.write(w.hasKey("ref") ? w.get("ref") : String.valueOf(counter++));
+                    writer.newLine();
+                    for( Node n : w.getNodes() ) {
+                        writer.write(String.format(Locale.ENGLISH, "   %E   %E", n.getCoor().lon(), n.getCoor().lat()));
+                        writer.newLine();
+                    }
+                    writer.write("END");
+                    writer.newLine();
+                }
+                writer.write("END");
+                writer.newLine();
+            } finally {
+                writer.close();
+            }
+        }
+    }
+
+    private class AreaComparator implements Comparator<Way> {
+        @Override
+        public int compare( Way w1, Way w2 ) {
+            if( w1.hasKey("ref") && !w2.hasKey("ref") )
+                return -1;
+            else if( !w1.hasKey("ref") && w2.hasKey("ref") )
+                return 1;
+            else if( w1.hasKey("ref") && w2.hasKey("ref") && !w1.get("ref").equals(w2.get("ref")) )
+                return w1.get("ref").compareTo(w2.get("ref"));
+            else
+                return w1.compareTo(w2);
+        }
+    }
+}
Index: /applications/editors/josm/plugins/poly/src/poly/PolyImporter.java
===================================================================
--- /applications/editors/josm/plugins/poly/src/poly/PolyImporter.java	(revision 28570)
+++ /applications/editors/josm/plugins/poly/src/poly/PolyImporter.java	(revision 28570)
@@ -0,0 +1,198 @@
+package poly;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import org.openstreetmap.josm.data.coor.LatLon;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.IllegalDataException;
+import org.openstreetmap.josm.io.MirroredInputStream;
+import org.openstreetmap.josm.io.OsmImporter;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+import org.xml.sax.SAXException;
+
+/**
+ * Imports poly files.
+ *
+ * @author zverik
+ */
+public class PolyImporter extends OsmImporter {
+    public PolyImporter() {
+        super(PolyType.FILE_FILTER);
+    }
+
+    protected DataSet parseDataSet( final String source ) throws IOException, SAXException, IllegalDataException {
+        return parseDataSet(new MirroredInputStream(source), NullProgressMonitor.INSTANCE);
+    }
+
+    @Override
+    protected DataSet parseDataSet( InputStream in, ProgressMonitor progressMonitor ) throws IllegalDataException {
+        if( progressMonitor == null )
+            progressMonitor = NullProgressMonitor.INSTANCE;
+        CheckParameterUtil.ensureParameterNotNull(in, "in");
+        BufferedReader reader = null;
+
+        try {
+            progressMonitor.beginTask(tr("Reading polygon filter file..."), 2);
+            progressMonitor.indeterminateSubTask(tr("Reading polygon filter file..."));
+            reader = new BufferedReader(new InputStreamReader(in));
+            List<Area> areas = loadPolygon(reader);
+            progressMonitor.worked(1);
+            
+            progressMonitor.indeterminateSubTask(tr("Preparing data set..."));
+            DataSet ds = constructDataSet(areas);
+            progressMonitor.worked(1);
+            return ds;
+        } catch( IOException e ) {
+            throw new IllegalDataException(tr("Error reading poly file: {0}", e.getMessage()), e);
+        } finally {
+            try {
+                if( reader != null )
+                    reader.close();
+            } catch( IOException e ) { }
+            progressMonitor.finishTask();
+        }
+    }
+    
+    private List<Area> loadPolygon( BufferedReader reader ) throws IllegalDataException, IOException {
+        String name = reader.readLine();
+        if( name == null || name.trim().length() == 0 )
+            throw new IllegalDataException(tr("The file must begin with a polygon name"));
+        List<Area> areas = new ArrayList<Area>();
+        Area area = null;
+        boolean parsingSection = false;
+        while(true) {
+            String line;
+            do {
+                line = reader.readLine();
+                if( line == null )
+                    throw new IllegalDataException("File ended prematurely without END record");
+                line = line.trim();
+            } while( line.length() == 0 );
+
+            if( line.equals("END") ) {
+                if( !parsingSection )
+                    break;
+                else {
+                    // an area has been read
+                    if( area.getNodeCount() < 2 )
+                        throw new IllegalDataException(tr("There are less than 2 points in an area"));
+                    areas.add(area);
+                    if( areas.size() == 1 )
+                        areas.get(0).setPolygonName(name);
+                    parsingSection = false;
+                }
+            }
+
+            if( !parsingSection ) {
+                area = new Area(line);
+                parsingSection = true;
+            } else {
+                // reading area, parse coordinates
+                String[] tokens = line.split("\\s+");
+                double[] coords = new double[2];
+                int tokenCount = 0;
+                for( String token : tokens ) {
+                    if( token.length() > 0 ) {
+                        if( tokenCount > 2 )
+                            throw new IllegalDataException(tr("A polygon coordinate line must contain exactly 2 numbers"));
+                        try {
+                            coords[tokenCount++] = Double.parseDouble(token);
+                        } catch( NumberFormatException e ) {
+                            throw new IllegalDataException(tr("Unable to parse {0} as a number", token));
+                        }
+                    }
+                }
+                if( tokenCount < 2 )
+                    throw new IllegalDataException(tr("A polygon coordinate line must contain exactly 2 numbers"));
+                LatLon coord = new LatLon(coords[1], coords[0]);
+                if( !coord.isValid() )
+                    throw new IllegalDataException(tr("Invalid coordinates were found"));
+                area.addNode(coord);
+            }
+        }
+        return areas;
+    }
+
+    private DataSet constructDataSet( List<Area> areas ) {
+        DataSet ds = new DataSet();
+        boolean foundInner = false;
+        for( Area area : areas ) {
+            if( !area.isOuter() )
+                foundInner = true;
+            area.constructWay(ds);
+        }
+
+        if( foundInner ) {
+            Relation mp = new Relation();
+            mp.put("type", "multipolygon");
+            for( Area area : areas ) {
+                mp.addMember(new RelationMember(area.isOuter() ? "outer" : "inner", area.getWay()));
+            }
+            ds.addPrimitive(mp);
+        }
+
+        return ds;
+    }
+
+    private class Area {
+        private String name;
+        private String polygonName;
+        private List<LatLon> nodes;
+        private boolean outer;
+        private Way way;
+
+        public Area( String name ) {
+            this.name = name;
+            outer = name.charAt(0) != '!';
+            if( !outer )
+                this.name = this.name.substring(1);
+            nodes = new ArrayList<LatLon>();
+            way = null;
+            polygonName = null;
+        }
+
+        public void setPolygonName( String polygonName ) {
+            this.polygonName = polygonName;
+        }
+
+        public void addNode( LatLon node ) {
+            if( nodes.isEmpty() || !(nodes.get(nodes.size()-1).equals(node) || nodes.get(0).equals(node)) )
+                nodes.add(node);
+        }
+
+        public boolean isOuter() {
+            return outer;
+        }
+
+        public int getNodeCount() {
+            return nodes.size();
+        }
+
+        public Way getWay() {
+            return way;
+        }
+
+        public void constructWay( DataSet ds ) {
+            way = new Way();
+            for( LatLon coord : nodes )
+                way.addNode(new Node(coord));
+            way.addNode(way.getNode(0));
+            way.put("ref", name);
+            if( polygonName != null )
+                way.put("name", polygonName);
+            ds.addPrimitive(way);
+        }
+    }
+}
Index: /applications/editors/josm/plugins/poly/src/poly/PolyPlugin.java
===================================================================
--- /applications/editors/josm/plugins/poly/src/poly/PolyPlugin.java	(revision 28570)
+++ /applications/editors/josm/plugins/poly/src/poly/PolyPlugin.java	(revision 28570)
@@ -0,0 +1,21 @@
+package poly;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.ExtensionFileFilter;
+import org.openstreetmap.josm.plugins.Plugin;
+import org.openstreetmap.josm.plugins.PluginInformation;
+
+/**
+ * Poly reader/writer plugin.
+ * 
+ * @author zverik
+ */
+public class PolyPlugin extends Plugin {
+
+    public PolyPlugin(PluginInformation info) {
+        super(info);
+        ExtensionFileFilter.importers.add(new PolyImporter());
+        ExtensionFileFilter.exporters.add(new PolyExporter());
+        Main.main.menu.openLocation.addDownloadTaskClass(DownloadPolyTask.class);
+    }
+}
Index: /applications/editors/josm/plugins/poly/src/poly/PolyType.java
===================================================================
--- /applications/editors/josm/plugins/poly/src/poly/PolyType.java	(revision 28570)
+++ /applications/editors/josm/plugins/poly/src/poly/PolyType.java	(revision 28570)
@@ -0,0 +1,14 @@
+package poly;
+
+import org.openstreetmap.josm.actions.ExtensionFileFilter;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+/**
+ * Extension and file filter for poly type.
+ *
+ * @author zverik
+ */
+public interface PolyType {
+    public static final String EXTENSION = "poly";
+    public static final ExtensionFileFilter FILE_FILTER = new ExtensionFileFilter(EXTENSION, EXTENSION, tr("Osmosis polygon files") + " (*." + EXTENSION + ")");
+}
Index: /applications/editors/josm/plugins/poly/src/poly/ServerPolyReader.java
===================================================================
--- /applications/editors/josm/plugins/poly/src/poly/ServerPolyReader.java	(revision 28570)
+++ /applications/editors/josm/plugins/poly/src/poly/ServerPolyReader.java	(revision 28570)
@@ -0,0 +1,9 @@
+package poly;
+
+/**
+ *
+ * @author zverik
+ */
+public class ServerPolyReader {
+    
+}
