vhardy      2003/03/11 08:02:53

  Modified:    sources/org/apache/batik/transcoder/wmf/tosvg
                        WMFPainter.java WMFRecordStore.java
                        WMFTranscoder.java
  Log:
  Updated WMFTranscoder from Luan O'Carroll. Code refactoring and bug fixing
  
  Revision  Changes    Path
  1.4       +88 -105   
xml-batik/sources/org/apache/batik/transcoder/wmf/tosvg/WMFPainter.java
  
  Index: WMFPainter.java
  ===================================================================
  RCS file: 
/home/cvs/xml-batik/sources/org/apache/batik/transcoder/wmf/tosvg/WMFPainter.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- WMFPainter.java   19 Sep 2002 07:36:50 -0000      1.3
  +++ WMFPainter.java   11 Mar 2003 16:02:52 -0000      1.4
  @@ -40,8 +40,7 @@
     * @version $Id$
     * @author <a href="mailto:[EMAIL PROTECTED]">Luan O'Carroll</a>
     */
  -public class WMFPainter
  -{
  +public class WMFPainter {
       private static final String WMF_FILE_EXTENSION = ".wmf";
   
       /**
  @@ -57,7 +56,7 @@
       /**
        * Basic constructor, initializes the storage.
        */
  -    public WMFPainter(RecordStore currentStore) {
  +    public WMFPainter(WMFRecordStore currentStore) {
           setRecordStore(currentStore);
       }
   
  @@ -377,20 +376,18 @@
   
                   case WMFConstants.META_RECTANGLE:
                       {
  -                      int x1, y1, x2, y2;
  -                      x1 = (int)( scaleX * ( vpX + mr.ElementAt( 0 ).intValue()));
  -                      x2 = (int)( scaleX * ( vpX + mr.ElementAt( 2 ).intValue()));
  -                      y1 = (int)( scaleY * ( vpY + mr.ElementAt( 1 ).intValue()));
  -                      y2 = (int)( scaleY * ( vpY + mr.ElementAt( 3 ).intValue()));
  -
  -                      if ( brushObject >= 0 ) {
  -                        setBrushColor( currentStore, g, brushObject );
  -                        g.fillRect( x1, y1, x2-x1, y2-y1 );
  -                      }
  -                      setPenColor( currentStore, g, penObject );
  +                        int x1, y1, x2, y2;
  +                        x1 = (int)( scaleX * ( vpX + mr.ElementAt( 0 ).intValue()));
  +                        x2 = (int)( scaleX * ( vpX + mr.ElementAt( 2 ).intValue()));
  +                        y1 = (int)( scaleY * ( vpY + mr.ElementAt( 1 ).intValue()));
  +                        y2 = (int)( scaleY * ( vpY + mr.ElementAt( 3 ).intValue()));
   
  -                      if ( penObject >= 0 )
  -                        g.drawRect( x1, y1, x2-x1, y2-y1 );
  +                        if ( brushObject >= 0 ) {
  +                            setBrushColor( currentStore, g, brushObject );
  +                            g.fillRect( x1, y1, x2-x1-1, y2-y1-1 );
  +                        }
  +                        setPenColor( currentStore, g, penObject );
  +                        g.drawRect( x1, y1, x2-x1-1, y2-y1-1 );
                       }
                       break;
   
  @@ -415,18 +412,17 @@
   
                   case WMFConstants.META_ELLIPSE:
                       {
  -                      int x1, y1, x2, y2;
  -                      x1 = (int)( scaleX * ( vpX + mr.ElementAt( 0 ).intValue()));
  -                      x2 = (int)( scaleX * ( vpX + mr.ElementAt( 2 ).intValue()));
  -                      y1 = (int)( scaleY * ( vpY + mr.ElementAt( 1 ).intValue()));
  -                      y2 = (int)( scaleY * ( vpY + mr.ElementAt( 3 ).intValue()));
  -
  -                      setBrushColor( currentStore, g, brushObject );
  -                      if ( brushObject >= 0 )
  -                        g.fillOval( x1, y1, x2-x1, y2-y1 );
  +                        int x1, y1, x2, y2;
  +                        x1 = (int)( scaleX * ( vpX + mr.ElementAt( 0 ).intValue()));
  +                        x2 = (int)( scaleX * ( vpX + mr.ElementAt( 2 ).intValue()));
  +                        y1 = (int)( scaleY * ( vpY + mr.ElementAt( 1 ).intValue()));
  +                        y2 = (int)( scaleY * ( vpY + mr.ElementAt( 3 ).intValue()));
   
  -                      setPenColor( currentStore, g, penObject );
  -                      if ( penObject >= 0 )
  +                        if ( brushObject >= 0 ) {
  +                            setBrushColor( currentStore, g, brushObject );
  +                            g.fillOval( x1, y1, x2-x1, y2-y1 );
  +                        }
  +                        setPenColor( currentStore, g, penObject );
                           g.drawOval( x1, y1, x2-x1-1, y2-y1-1 );
                       }
                       break;
  @@ -451,8 +447,7 @@
                               Graphics2D g2 = (Graphics2D)g;
                               int x, y;
                               x = (int)( scaleX * ( vpX + mr.ElementAt( 0 
).intValue()));
  -                            //y = (int)( fontHeight + scaleY * ( vpY + 
mr.ElementAt( 1 ).intValue()));
  -                            y = (int)( scaleY * ( vpY + mr.ElementAt( 1 
).intValue()));
  +                            y = (int)( fontHeight + scaleY * ( vpY + mr.ElementAt( 
1 ).intValue()));
                               if ( frgdColor != null )
                                   g.setColor( frgdColor );
                               else
  @@ -466,7 +461,7 @@
                               TextLayout layout = new TextLayout( sr.text, font, frc 
);
                               pen.y += layout.getAscent();
   
  -                            if ( fontAngle != 0 ) {
  +                            if (( fontAngle != 0 ) || sr.text.startsWith("Sono una 
scala verticale di prevalenza") ) {
                                   AffineTransform at = new AffineTransform();
                                   float width = (float)layout.getBounds().getWidth();
                                   float height = 
(float)layout.getBounds().getHeight();
  @@ -490,34 +485,26 @@
                   case WMFConstants.META_ARC:
                   case WMFConstants.META_PIE:
                       {
  -                      int x1, y1, x2, y2, x3, y3, x4, y4;
  -                      x1 = (int)( scaleX * ( vpX + mr.ElementAt( 0 ).intValue()));
  -                      x2 = (int)( scaleX * ( vpX + mr.ElementAt( 2 ).intValue()));
  -                      x3 = (int)( scaleX * ( mr.ElementAt( 4 ).intValue()));
  -                      x4 = (int)( scaleX * ( mr.ElementAt( 6 ).intValue()));
  -                      y1 = (int)( scaleY * ( vpY + mr.ElementAt( 1 ).intValue()));
  -                      y2 = (int)( scaleY * ( vpY + mr.ElementAt( 3 ).intValue()));
  -                      y3 = (int)( scaleY * ( mr.ElementAt( 5 ).intValue()));
  -                      y4 = (int)( scaleY * ( mr.ElementAt( 7 ).intValue()));
  -
  -                      int mx = x1+(x2-x1)/2;
  -                      int my = y1+(y2-y1)/2;
  -                      int startAngle = (int)Math.toDegrees( Math.atan2( 
-1.0*(y3-my), 1.0*(x3-mx)));
  -                      int endAngle = (int)Math.toDegrees( Math.atan2( -1.0*(y4-my), 
1.0*(x4-mx)));
  -                      if ( mr.functionId == 0x081A ) {
  +                        int x1, y1, x2, y2, x3, y3, x4, y4;
  +                        x1 = (int)( scaleX * ( vpX + mr.ElementAt( 0 ).intValue()));
  +                        x2 = (int)( scaleX * ( vpX + mr.ElementAt( 2 ).intValue()));
  +                        x3 = (int)( scaleX * ( mr.ElementAt( 4 ).intValue()));
  +                        x4 = (int)( scaleX * ( mr.ElementAt( 6 ).intValue()));
  +                        y1 = (int)( scaleY * ( vpY + mr.ElementAt( 1 ).intValue()));
  +                        y2 = (int)( scaleY * ( vpY + mr.ElementAt( 3 ).intValue()));
  +                        y3 = (int)( scaleY * ( mr.ElementAt( 5 ).intValue()));
  +                        y4 = (int)( scaleY * ( mr.ElementAt( 7 ).intValue()));
                           setBrushColor( currentStore, g, brushObject );
  -                        if ( brushObject >= 0 )
  -                          g.fillArc( x1, y1, x2-x1, y2-y1, startAngle, endAngle );
  -                      }
  -
  -                      setPenColor( currentStore, g, penObject );
  -                      if ( startAngle < 0 ) startAngle = 360+startAngle;
  -                      if ( endAngle < 0 ) endAngle = 360+endAngle;
  -                      int len = Math.abs( endAngle - startAngle );
  -                      if ( endAngle < startAngle )
  -                        len = 360 - startAngle + endAngle;
  -                      if ( penObject >= 0 )
  -                        g.drawArc( x1, y1, x2-x1, y2-y1, startAngle, len );
  +
  +                        int mx = x1+(x2-x1)/2;
  +                        int my = y1+(y2-y1)/2;
  +                        int startAngle = (int)Math.atan( (y3-my)/(x3-mx));
  +                        int endAngle = (int)Math.atan( (y4-my)/(x4-mx));
  +                        if ( mr.functionId == 0x0817 )
  +                            g.drawArc( x1, y1, x2-x1, y2-y1, startAngle, endAngle );
  +                        else
  +                            g.fillArc( x1, y1, x2-x1, y2-y1, startAngle, endAngle );
  +
                       }
                       break;
   
  @@ -635,30 +622,26 @@
           }
       }
   
  -    private void setPenColor( RecordStore currentStore, Graphics g, int penObject)
  -    {
  -      if ( penObject >= 0 ) {
  -        GdiObject gdiObj = currentStore.getObject( penObject );
  -        g.setColor( (Color)gdiObj.obj );
  -        //penObject = -1;
  -      }
  +    private void setPenColor( WMFRecordStore currentStore, Graphics g, int 
penObject) {
  +        if ( penObject >= 0 ) {
  +            GdiObject gdiObj = currentStore.getObject( penObject );
  +            g.setColor( (Color)gdiObj.obj );
  +            penObject = -1;
  +        }
       }
   
  -
  -    private void setBrushColor( RecordStore currentStore, Graphics g, int 
brushObject)
  -    {
  -      if ( brushObject >= 0 ) {
  -        GdiObject gdiObj = currentStore.getObject( brushObject );
  -        g.setColor( (Color)gdiObj.obj );
  -        //brushObject = -1;
  -      }
  +    private void setBrushColor( WMFRecordStore currentStore, Graphics g, int 
brushObject) {
  +        if ( brushObject >= 0 ) {
  +            GdiObject gdiObj = currentStore.getObject( brushObject );
  +            g.setColor( (Color)gdiObj.obj );
  +            brushObject = -1;
  +        }
       }
   
       /**
  -     * Sets the RecordStore this WMFPainter should use to render
  +     * Sets the WMFRecordStore this WMFPainter should use to render
        */
  -    public void setRecordStore(RecordStore currentStore)
  -    {
  +    public void setRecordStore(WMFRecordStore currentStore){
           if(currentStore == null){
               throw new IllegalArgumentException();
           }
  @@ -667,17 +650,17 @@
       }
   
       /**
  -     * Returns the RecordStore this WMFPainter renders
  +     * Returns the WMFRecordStore this WMFPainter renders
        */
  -    public RecordStore getRecordStore(){
  +    public WMFRecordStore getRecordStore(){
           return currentStore;
       }
   
  -    private void addObject( RecordStore currentStore, int type, Object obj ) {
  +    private void addObject( WMFRecordStore currentStore, int type, Object obj ) {
           currentStore.addObject( type, obj );
       }
   
  -    private void addObjectAt( RecordStore currentStore, int type, Object obj, int 
idx ) {
  +    private void addObjectAt( WMFRecordStore currentStore, int type, Object obj, 
int idx ) {
           currentStore.addObjectAt( type, obj, idx );
       }
   
  @@ -688,7 +671,7 @@
       public static final int NULL_BRUSH = 5;
       public static final int PALETTE = 6;
   
  -    private RecordStore currentStore;
  +    private WMFRecordStore currentStore;
       transient private boolean bReadingWMF = true;
       transient private BufferedInputStream bufStream = null;
   
  @@ -735,30 +718,30 @@
   
   class GdiObject /*implements Serializable*/
   {
  -  GdiObject( int _id, boolean _used )
  -  {
  -    id = _id;
  -    used = _used;
  -    type = 0;
  -  }
  -
  -  public void Clear()
  -  {
  -    used = false;
  -    type = 0;
  -  }
  -
  -  public void Setup( int _type, Object _obj )
  -  {
  -    obj = _obj;
  -    type = _type;
  -    used = true;
  -  }
  -
  -  int id;
  -  boolean used;
  -  Object obj;
  -  int type = 0;
  +        GdiObject( int _id, boolean _used )
  +        {
  +        id = _id;
  +        used = _used;
  +        type = 0;
  +        }
  +
  +        public void Clear()
  +        {
  +        used = false;
  +        type = 0;
  +        }
  +
  +        public void Setup( int _type, Object _obj )
  +        {
  +        obj = _obj;
  +        type = _type;
  +        used = true;
  +        }
  +
  +        int id;
  +        boolean used;
  +        Object obj;
  +        int type = 0;
   }
   
   
  
  
  
  1.3       +171 -14   
xml-batik/sources/org/apache/batik/transcoder/wmf/tosvg/WMFRecordStore.java
  
  Index: WMFRecordStore.java
  ===================================================================
  RCS file: 
/home/cvs/xml-batik/sources/org/apache/batik/transcoder/wmf/tosvg/WMFRecordStore.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- WMFRecordStore.java       4 Mar 2002 12:29:04 -0000       1.2
  +++ WMFRecordStore.java       11 Mar 2003 16:02:52 -0000      1.3
  @@ -11,6 +11,7 @@
   import java.io.DataInputStream;
   import java.io.IOException;
   import java.net.URL;
  +import java.util.Vector;
   
   import org.apache.batik.transcoder.wmf.WMFConstants;
   
  @@ -20,28 +21,42 @@
    * @author <a href="mailto:[EMAIL PROTECTED]">Luan O'Carroll</a>
    * @version $Id$
    */
  -public class WMFRecordStore extends RecordStore implements WMFConstants{
  -
  -    private byte js2B[] = new byte[ 2 ];
  -    private byte js4B[] = new byte[ 4 ];
  +public class WMFRecordStore implements WMFConstants{
   
       public WMFRecordStore(){
  +      reset();
  +    }
  +
  +    /**
  +     * Resets the internal storage and viewport coordinates.
  +     */
  +    public void reset(){
  +      numRecords = 0;
  +      vpX = 0;
  +      vpY = 0;
  +      vpW = 1000;
  +      vpH = 1000;
  +      numObjects = 0;
  +      records = new Vector( 20, 20 );
  +      objectVector = new Vector();
       }
   
       private short readShort( DataInputStream is  ) throws IOException{
  -        is.read( js2B );
  -        int iTemp = ((0xff) & js2B[ 1 ] ) << 8;
  +        byte js[] = new byte[ 2 ];
  +        is.read( js );
  +        int iTemp = ((0xff) & js[ 1 ] ) << 8;
           short i = (short)(0xffff & iTemp);
  -        i |= ((0xff) & js2B[ 0 ] );
  +        i |= ((0xff) & js[ 0 ] );
           return i;
       }
   
       private int readInt( DataInputStream is  ) throws IOException {
  -        is.read( js4B );
  -        int i = ((0xff) & js4B[ 3 ] ) << 24;
  -        i |= ((0xff) & js4B[ 2 ] ) << 16;
  -        i |= ((0xff) & js4B[ 1 ] ) << 8;
  -        i |= ((0xff) & js4B[ 0 ] );
  +        byte js[] = new byte[ 4 ];
  +        is.read( js );
  +        int i = ((0xff) & js[ 3 ] ) << 24;
  +        i |= ((0xff) & js[ 2 ] ) << 16;
  +        i |= ((0xff) & js[ 1 ] ) << 8;
  +        i |= ((0xff) & js[ 0 ] );
           return i;
       }
   
  @@ -206,6 +221,11 @@
                       mr.AddElement( new Integer( i1 ));
                       mr.AddElement( new Integer( i0 ));
                       records.addElement( mr );
  +
  +                    if ( functionId == WMFConstants.META_SETWINDOWEXT ) {
  +                      vpW = i0;
  +                      vpH = i1;
  +                    }
                   }
                   break;
   
  @@ -245,8 +265,6 @@
                       int width = readShort( is );
                       int colorref =  readInt( is );
                       int height = readShort( is );
  -                    for ( int j = 5; j < recSize; j++ )
  -                       readShort( is );
   
                       int red = colorref & 0xff;
                       int green = ( colorref & 0xff00 ) >> 8;
  @@ -438,4 +456,143 @@
           }
       }
   
  +    synchronized void setReading( boolean state ){
  +      bReading = state;
  +    }
  +
  +    synchronized boolean isReading(){
  +      return bReading;
  +    }
  +
  +    /**
  +     * Adds a GdiObject to the internal handle table.
  +     * Wmf files specify the index as given in EMF records such as
  +     * EMRCREATEPENINDIRECT whereas WMF files always use 0.
  +     *
  +     * This function should not normally be called by an application.
  +     */
  +    public void addObjectAt( int type, Object obj, int idx ) {
  +      if (( idx == 0 ) || ( idx > numObjects )) {
  +        addObject( type, obj );
  +        return;
  +      }
  +      lastObjectIdx = idx;
  +      for ( int i = 0; i < numObjects; i++ ) {
  +        GdiObject gdi = (GdiObject)objectVector.elementAt( i );
  +        if ( i == idx ) {
  +          gdi.Setup( type, obj );
  +          break;
  +        }
  +      }
  +    }
  +
  +    /**
  +     * Returns the current URL
  +     */
  +    public URL getUrl() {
  +      return url;
  +    }
  +
  +    /**
  +     * Sets the current URL
  +     */
  +    public void setUrl( URL newUrl) {
  +      url = newUrl;
  +    }
  +
  +    /**
  +     * Returns a GdiObject from the handle table
  +     */
  +    public GdiObject getObject( int idx ) {
  +      return (GdiObject)objectVector.elementAt( idx );
  +    }
  +
  +    /**
  +     * Returns a meta record.
  +     */
  +    public MetaRecord getRecord( int idx ) {
  +      return (MetaRecord)records.elementAt( idx );
  +    }
  +
  +    /**
  +     * Returns a number of records in the image
  +     */
  +    public int getNumRecords() {
  +      return numRecords;
  +    }
  +
  +    /**
  +     * Returns the number of GdiObjects in the handle table
  +     */
  +    public int getNumObjects() {
  +      return numObjects;
  +    }
  +
  +    /**
  +     * Returns the viewport x origin
  +     */
  +    public int getVpX() {
  +      return vpX;
  +    }
  +
  +    /**
  +     * Returns the viewport y origin
  +     */
  +    public int getVpY() {
  +      return vpY;
  +    }
  +
  +    /**
  +     * Returns the viewport width
  +     */
  +    public int getVpW() {
  +      return vpW;
  +    }
  +
  +    /**
  +     * Returns the viewport height
  +     */
  +    public int getVpH() {
  +      return vpH;
  +    }
  +
  +    /**
  +     * Sets the viewport x origin
  +     */
  +    public void setVpX( int newValue ) {
  +      vpX = newValue;
  +    }
  +
  +    /**
  +     * Sets the viewport y origin
  +     */
  +    public void setVpY( int newValue ) {
  +      vpY = newValue;
  +    }
  +
  +    /**
  +     * Sets the viewport width
  +     */
  +    public void setVpW( int newValue ) {
  +      vpW = newValue;
  +    }
  +
  +    /**
  +     * Sets the viewport height
  +     */
  +    public void setVpH( int newValue ) {
  +      vpH = newValue;
  +    }
  +
  +
  +    transient private URL url;
  +
  +    transient protected int numRecords;
  +    transient protected int numObjects;
  +    transient public int lastObjectIdx;
  +    transient protected int vpX, vpY, vpW, vpH;
  +    transient protected Vector       records;
  +    transient protected Vector       objectVector;
  +
  +    transient protected boolean bReading = false;
   }
  
  
  
  1.3       +16 -16    
xml-batik/sources/org/apache/batik/transcoder/wmf/tosvg/WMFTranscoder.java
  
  Index: WMFTranscoder.java
  ===================================================================
  RCS file: 
/home/cvs/xml-batik/sources/org/apache/batik/transcoder/wmf/tosvg/WMFTranscoder.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- WMFTranscoder.java        21 Aug 2001 15:26:01 -0000      1.2
  +++ WMFTranscoder.java        11 Mar 2003 16:02:52 -0000      1.3
  @@ -39,21 +39,21 @@
   
   
   /**
  - * This class implements the <tt>Transcoder</tt> interface and 
  + * This class implements the <tt>Transcoder</tt> interface and
    * can convert a WMF input document into an SVG document.
    *
    * It can use <tt>TranscoderInput</tt> that are either a URI
  - * or a <tt>InputStream</tt> or a <tt>Reader</tt>. The 
  + * or a <tt>InputStream</tt> or a <tt>Reader</tt>. The
    * <tt>XMLReader</tt> and <tt>Document</tt> <tt>TranscoderInput</tt>
    * types are not supported.
    *
    * This transcoder can use <tt>TranscoderOutputs</tt> that are
    * of any type except the <tt>XMLFilter</tt> type.
  - * 
  + *
    * @version $Id$
    * @author <a href="mailto:[EMAIL PROTECTED]">Luan O'Carroll</a>
    */
  -public class WMFTranscoder extends AbstractTranscoder 
  +public class WMFTranscoder extends AbstractTranscoder
       implements SVGConstants{
   
       /**
  @@ -69,7 +69,7 @@
        */
       public WMFTranscoder(){
       }
  -    
  +
       /**
        * Transcodes the specified input in the specified output.
        * @param input the input to transcode
  @@ -86,7 +86,7 @@
           //
           // Build a RecordStore from the input
           //
  -        RecordStore currentStore = new WMFRecordStore();
  +        WMFRecordStore currentStore = new WMFRecordStore();
           try{
               currentStore.read(is);
           }catch(IOException e){
  @@ -102,10 +102,10 @@
           //
           // Use SVGGraphics2D to generate SVG content
           //
  -        DOMImplementation domImpl 
  +        DOMImplementation domImpl
               = ExtensibleSVGDOMImplementation.getDOMImplementation();
   
  -        Document doc = domImpl.createDocument(SVG_NAMESPACE_URI, 
  +        Document doc = domImpl.createDocument(SVG_NAMESPACE_URI,
                                                 SVG_SVG_TAG, null);
   
           SVGGraphics2D svgGenerator = new SVGGraphics2D(doc);
  @@ -133,12 +133,12 @@
       }
   
       /**
  -     * Writes the SVG content held by the svgGenerator to the 
  +     * Writes the SVG content held by the svgGenerator to the
        * <tt>TranscoderOutput</tt>.
        */
       private void writeSVGToOutput(SVGGraphics2D svgGenerator,
                                     Element svgRoot,
  -                                  TranscoderOutput output) 
  +                                  TranscoderOutput output)
           throws TranscoderException {
           // XMLFilter
           XMLFilter xmlFilter = output.getXMLFilter();
  @@ -159,14 +159,14 @@
                   svgGenerator.stream(svgRoot, new OutputStreamWriter(os));
                   return;
               }
  -            
  +
               // Writer
               Writer wr = output.getWriter();
               if( wr != null ){
                   svgGenerator.stream(svgRoot, wr);
                   return;
               }
  -            
  +
               // URI
               String uri = output.getURI();
               if( uri != null ){
  @@ -186,8 +186,8 @@
               throw new TranscoderException(e);
           }
   
  -        throw new TranscoderException("" + ERROR_INCOMPATIBLE_OUTPUT_TYPE);        
  -        
  +        throw new TranscoderException("" + ERROR_INCOMPATIBLE_OUTPUT_TYPE);
  +
       }
   
       /**
  @@ -244,7 +244,7 @@
   
           WMFTranscoder transcoder = new WMFTranscoder();
           int nFiles = args.length;
  -        
  +
           for(int i=0; i<nFiles; i++){
               String fileName = args[i];
               if(!fileName.toLowerCase().endsWith(WMF_EXTENSION)){
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to