Package org.geotools.geometry.iso.primitive

Source Code of org.geotools.geometry.iso.primitive.PrimitiveFactoryImpl

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2006-2008, Open Source Geospatial Foundation (OSGeo)
*   
*    This library is free software; you can redistribute it and/or
*    modify it under the terms of the GNU Lesser General Public
*    License as published by the Free Software Foundation;
*    version 2.1 of the License.
*
*    This library 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
*    Lesser General Public License for more details.
*/
package org.geotools.geometry.iso.primitive;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.geotools.factory.Factory;
import org.geotools.factory.GeoTools;
import org.geotools.factory.Hints;
import org.geotools.geometry.GeometryFactoryFinder;
import org.geotools.geometry.iso.coordinate.DirectPositionImpl;
import org.geotools.geometry.iso.coordinate.LineSegmentImpl;
import org.geotools.geometry.iso.coordinate.LineStringImpl;
import org.geotools.geometry.iso.coordinate.PointArrayImpl;
import org.geotools.geometry.iso.coordinate.PositionImpl;
import org.geotools.geometry.iso.coordinate.SurfacePatchImpl;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.opengis.geometry.DirectPosition;
import org.opengis.geometry.Envelope;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.geometry.MismatchedReferenceSystemException;
import org.opengis.geometry.PositionFactory;
import org.opengis.geometry.coordinate.LineSegment;
import org.opengis.geometry.coordinate.Position;
import org.opengis.geometry.primitive.Curve;
import org.opengis.geometry.primitive.CurveSegment;
import org.opengis.geometry.primitive.OrientableCurve;
import org.opengis.geometry.primitive.Point;
import org.opengis.geometry.primitive.PrimitiveFactory;
import org.opengis.geometry.primitive.Ring;
import org.opengis.geometry.primitive.SolidBoundary;
import org.opengis.geometry.primitive.SurfaceBoundary;
import org.opengis.geometry.primitive.SurfacePatch;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CoordinateSystemAxis;

/**
* @author Jackson Roehrig & Sanjay Jena
*
*
*
*
*
* @source $URL$
*/
public class PrimitiveFactoryImpl implements Serializable, Factory, PrimitiveFactory {

  /**
   *
   */
  private static final long serialVersionUID = 1L;
  private CoordinateReferenceSystem crs;
  private PositionFactory positionFactory;
  private Boolean geomValidate;

  /** Map of hints we care about during construction, used by FactoryFinder/Registry madness */
  private Map hintsWeCareAbout = new HashMap();

  /** FactorySPI entry point */
  public PrimitiveFactoryImpl() {
    this(null );
  }
 
  /** Just the defaults, use GeometryFactoryFinder for the rest */
  public PrimitiveFactoryImpl( Hints hints ) {
    if (hints == null) {
      this.crs = DefaultGeographicCRS.WGS84;
      hints = GeoTools.getDefaultHints();
          hints.put(Hints.CRS, crs );
          geomValidate = true;
          hints.put(Hints.GEOMETRY_VALIDATE, geomValidate);
    }
    else {
      this.crs = (CoordinateReferenceSystem) hints.get( Hints.CRS );
      if( crs == null ){
        throw new NullPointerException("A CRS Hint is required in order to use PrimitiveFactoryImpl");
      }
      geomValidate = (Boolean) hints.get( Hints.GEOMETRY_VALIDATE );
      if (geomValidate == null) {
        geomValidate = true;
      }
    }
   
    this.positionFactory = GeometryFactoryFinder.getPositionFactory(hints);
    hintsWeCareAbout.put(Hints.CRS, crs );
    hintsWeCareAbout.put(Hints.POSITION_FACTORY, positionFactory );
    hintsWeCareAbout.put(Hints.GEOMETRY_VALIDATE, geomValidate );
  }

  /**
   * @param crs
   */
  public PrimitiveFactoryImpl(CoordinateReferenceSystem crs, PositionFactory positionFactory) {
    this.crs = crs;
    if( crs == null ){
      throw new NullPointerException("A non null crs is required in order to use PrimitiveFactoryImpl");
    }
    if (positionFactory == null) {
      Hints hints = GeoTools.getDefaultHints();
          hints.put(Hints.CRS, crs );
      this.positionFactory = GeometryFactoryFinder.getPositionFactory(hints);
    }
    else {
      this.positionFactory = positionFactory;
    }
   
    geomValidate = true;
    hintsWeCareAbout.put(Hints.CRS, crs );
    hintsWeCareAbout.put(Hints.POSITION_FACTORY, positionFactory );
    hintsWeCareAbout.put(Hints.GEOMETRY_VALIDATE, geomValidate );
  }

  /** These are the hints we used */
  public Map getImplementationHints() {
    return Collections.unmodifiableMap( hintsWeCareAbout );
  }
 
  /*
   * (non-Javadoc)
   *
   * @see org.opengis.geometry.primitive.PrimitiveFactory#getCoordinateReferenceSystem()
   */
  public CoordinateReferenceSystem getCoordinateReferenceSystem() {
    // TODO test
    // TODO documentation
    return this.crs;
  }
 
  /*
   * (non-Javadoc)
   *
   * @see org.opengis.geometry.primitive.PrimitiveFactory#getCoordinateReferenceSystem()
   */
  public PositionFactory getPositionFactory() {
    // TODO test
    // TODO documentation
    return this.positionFactory;
  }

  /**
   * Returns the Coordinate Dimension of the used Coordinate System (Sanjay)
   *
   * @return dimension Coordinate Dimension used in this Factory
   */
  public int getDimension() {
    // Test OK
    return this.crs.getCoordinateSystem().getDimension();
  }

  /*
   * (non-Javadoc)
   *
   * @see org.opengis.geometry.primitive.PrimitiveFactory#createPoint(double[])
   */
  public PointImpl createPoint(double[] coord) {
    // Test ok
    if (coord == null)
      throw new NullPointerException();
    if (coord.length != this.getDimension())
      throw new MismatchedDimensionException();

    return new PointImpl(positionFactory.createDirectPosition(coord));
  }

  /**
   * Creates a Point by copying the coordinates of a given DirectPosition
   *
   * @param dp
   *            DirectPosition, will be copied
   * @return PointImpl
   */
  public PointImpl createPoint(DirectPositionImpl dp) {
    if (dp == null)
      throw new NullPointerException();
    // Test ok
    // Compare Dimension (which is the Coordinate Dimension) of the
    // DirectPosition with the CoordinateDimension of the current Coordinate
    // System in Euclidian Space
    if (dp.getDimension() != this.getDimension())
      throw new MismatchedDimensionException();

    return new PointImpl(dp.clone());
  }

  /*
   * (non-Javadoc)
   *
   * @see org.opengis.geometry.primitive.PrimitiveFactory#createPoint(org.opengis.geometry.coordinate.Position)
   */
  public PointImpl createPoint(Position position)
      throws MismatchedReferenceSystemException,
      MismatchedDimensionException {
    // Test ok
    if (position == null) {
      throw new IllegalArgumentException("Parameter position is null.");
    }
    if (position.getDirectPosition().getDimension() != this.getDimension()) {
      throw new MismatchedDimensionException();
    }
    DirectPosition copy = positionFactory.createDirectPosition(position.getDirectPosition().getCoordinate());
    return new PointImpl(copy);
  }

  /**
   * Creates a CurveBoundary
   *
   * @param dp0
   * @param dp1
   * @return CurveBoundaryImpl
   */
  public CurveBoundaryImpl createCurveBoundary(DirectPosition dp0,
      DirectPosition dp1) {
    // Test OK (Sanjay)
    if (dp0 == null || dp1 == null)
      throw new NullPointerException(
          "One or both of the parameters is NULL");
    return new CurveBoundaryImpl(getCoordinateReferenceSystem(),
        createPoint(dp0),
        createPoint(dp1));
  }

  /**
   * Creates a CurveBoundary
   *
   * @param p0
   * @param p1
   * @return CurveBoundaryImpl
   */
  public CurveBoundaryImpl createCurveBoundary(Point p0, Point p1) {
    if (p0 == null || p1 == null)
      throw new NullPointerException(
          "One or both of the parameters is NULL");
    return new CurveBoundaryImpl(getCoordinateReferenceSystem(), p0, p1);
   
  }

  /*
   * (non-Javadoc)
   *
   * @see org.opengis.geometry.primitive.PrimitiveFactory#createCurve(java.util.List)
   */
  public CurveImpl createCurve(List<CurveSegment> segments) {
    // test OK
    if (segments == null)
      throw new NullPointerException();

    // A curve will be created
    // - The curve will be set as parent curves for the Curve segments
    // - Start and end params for the CurveSegments will be set
    return new CurveImpl(getCoordinateReferenceSystem(), segments);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.opengis.geometry.primitive.PrimitiveFactory#createRing(java.util.List)
   */
  public Ring createRing(List<OrientableCurve> orientableCurves)
      throws MismatchedReferenceSystemException,
      MismatchedDimensionException {
    /**
     * Creates a Ring from triple Array of DirectPositions (Array of arrays,
     * which each represent a future Curve. Each array contain an array of
     * positions, which each represent a future lineString)
     */
    // TODO semantic JR
    // test OK
    for (OrientableCurve orientableCurve : orientableCurves) {
      // Comment by Sanjay
      // TODO JR: Zur Kenntnisnahme und Berücksichtigung in Sourcen: Für
      // alle
      // Primitives gilt, dass getDimension die Dimension des Objektes,
      // und getCoordinateDimension die Dimension des Koordinatensystems,
      // in welchem das Objekt instanziert wurde, wiedergibt
      // if (this.getDimension() != orientableCurve.getDimension(null)) {
      if (this.getDimension() != orientableCurve.getCoordinateDimension()) {
        throw new MismatchedDimensionException();
      }
      if (!CRS.equalsIgnoreMetadata(this.getCoordinateReferenceSystem(), orientableCurve
          .getCoordinateReferenceSystem()) ) {
        throw new MismatchedReferenceSystemException();
      }
    }
   
    // if we don't want to validate the ring upon creation (for faster creation) use
    // RingImplUnsafe instead of RingImpl
    if ( geomValidate ) {
      return new RingImpl(orientableCurves);
    }
    else {
      return new RingImplUnsafe(orientableCurves);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.opengis.geometry.primitive.PrimitiveFactory#createSurfaceBoundary(org.opengis.geometry.primitive.Ring,
   *      java.util.List)
   */
  public SurfaceBoundaryImpl createSurfaceBoundary(Ring exterior,
      List<Ring> interiors) throws MismatchedReferenceSystemException,
      MismatchedDimensionException {
    // Test ok

    if (interiors == null && exterior == null)
      throw new NullPointerException();
    CoordinateReferenceSystem thisCRS = this.getCoordinateReferenceSystem();
    if (exterior != null) {
      if (this.getDimension() != exterior.getCoordinateDimension()) {
        throw new MismatchedDimensionException();
      }
      CoordinateReferenceSystem exteriorCRS = exterior
          .getCoordinateReferenceSystem();
      if (!CRS.equalsIgnoreMetadata(thisCRS,exteriorCRS)) {
        throw new MismatchedReferenceSystemException();
      }
    }
    if (interiors != null) {
      for (Ring ring : interiors) {
        if (ring != null) {
          if (this.getDimension() != ring.getCoordinateDimension()) {
            throw new MismatchedDimensionException();
          }
          if (!CRS.equalsIgnoreMetadata(thisCRS, ring
              .getCoordinateReferenceSystem()) ) {
            throw new MismatchedReferenceSystemException();
          }
        }
      }
    }
    return new SurfaceBoundaryImpl(getCoordinateReferenceSystem(),
        exterior, interiors);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.opengis.geometry.primitive.PrimitiveFactory#createSurface(java.util.List)
   */
  public SurfaceImpl createSurface(List<SurfacePatch> surfacePatches)
      throws MismatchedReferenceSystemException,
      MismatchedDimensionException {

    // tested in /test/TestSurface.java
    // TODO SurfaceBoundary NOT calculated !!!

    // Create Surface
    SurfaceImpl rSurface = new SurfaceImpl(getCoordinateReferenceSystem(),
        surfacePatches);
    // Set reference to the generated Surface for each SurfacePatch
    for (int i = 0; i < surfacePatches.size(); i++) {
      SurfacePatchImpl actPatch = (SurfacePatchImpl) surfacePatches
          .get(i);
      actPatch.setSurface(rSurface);
    }

    return rSurface;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.opengis.geometry.primitive.PrimitiveFactory#createSurface(org.opengis.geometry.primitive.SurfaceBoundary)
   */
  public SurfaceImpl createSurface(SurfaceBoundary boundary)
      throws MismatchedReferenceSystemException,
      MismatchedDimensionException {
    // Test ok
    // Creates a Surface without SurfacePatches
    return new SurfaceImpl(boundary);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.opengis.geometry.primitive.PrimitiveFactory#createSolid(org.opengis.geometry.primitive.SolidBoundary)
   */
  public SolidImpl createSolid(SolidBoundary boundary)
      throws MismatchedReferenceSystemException,
      MismatchedDimensionException {
    // TODO semantic SJ, JR
    // TODO implementation
    // TODO test
    // TODO documentation
    return new SolidImpl(boundary);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.opengis.geometry.primitive.PrimitiveFactory#createPrimitive(org.opengis.geometry.coordinate.Envelope)
   */
//  public PrimitiveImpl createPrimitive_try2(Envelope envelope)
//      throws MismatchedReferenceSystemException,
//      MismatchedDimensionException {
//
//    List<DirectPosition> positions = new ArrayList<DirectPosition>();
//
//    for (int d = 0; d < crs.getCoordinateSystem().getDimension(); d++) {
//      CoordinateSystemAxis axis = crs.getCoordinateSystem().getAxis(d);
//      AxisDirection direction = axis.getDirection();
//      double min, max;
//      if (direction == AxisDirection.OTHER) {
//        // we are going to "skip" min/max calculation on OTHER
//        // used for 2.5 D stuff
//        min = Double.NaN;
//        max = Double.NaN;
//      } else {
//        // figure out min & max from envelope
//        min = envelope.getMinimum(d);
//        max = envelope.getMaximum(d);
//      }
//      if (positions.isEmpty()) {
//        DirectPositionImpl min1 = (DirectPositionImpl) positionFactory.createDirectPosition(null);//new DirectPositionImpl(crs);
//        min1.setOrdinate(d, min);
//        DirectPositionImpl max1 = (DirectPositionImpl) positionFactory.createDirectPosition(null);//new DirectPositionImpl(crs);
//        max1.setOrdinate(d, max);
//
//        positions.add(min1);
//        positions.add(max1);
//      } else {
//        // update min in place
//        for (DirectPosition minN : positions) {
//          minN.setOrdinate(d, min);
//        }
//        // copy and update max
//        List<DirectPosition> copy = new ArrayList<DirectPosition>();
//        for (DirectPosition position : positions) {
//          DirectPositionImpl maxN = (DirectPositionImpl) positionFactory.createDirectPosition(position.getCoordinate()); //new DirectPositionImpl(position);
//          maxN.setOrdinate(d, max);
//        }
//        positions.addAll(copy);
//      }
//    }
//
//    return this.createSurfaceByDirectPositions(positions);
//  }
 
  /*
   * (non-Javadoc)
   *
   * @see org.opengis.geometry.primitive.PrimitiveFactory#createPrimitive(org.opengis.geometry.coordinate.Envelope)
   */
  public PrimitiveImpl createPrimitive(Envelope bounds)
      throws MismatchedReferenceSystemException,
      MismatchedDimensionException {
    //final int D = crs.getCoordinateSystem().getDimension();
   
    LineSegment segment = processBoundsToSegment(bounds);   
    return processSegmentToPrimitive( bounds, segment, 1 );   
  }
 
  private PrimitiveImpl processSegmentToPrimitive(Envelope bounds, LineSegment segment, int dimension) {
    //int D = crs.getCoordinateSystem().getDimension();
    CoordinateSystemAxis axis = crs.getCoordinateSystem().getAxis( dimension );
   
    if( axis.getDirection() == AxisDirection.OTHER ){
      return processSegmentToPrimitive( bounds, segment, dimension+1 );
    }
    Ring ring = processBoundsToRing( bounds, segment, dimension );
    return processRingToPrimitive( bounds, ring, dimension+1 );       
  }

  private PrimitiveImpl processRingToPrimitive(Envelope bounds, Ring ring, int dimension) {
    int D = crs.getCoordinateSystem().getDimension();
    if( dimension == D ){ // create Surface from ring and return     
      SurfaceBoundary boundary = new SurfaceBoundaryImpl( crs, ring, Collections.EMPTY_LIST );
      return new SurfaceImpl( boundary );
    }   
    CoordinateSystemAxis axis = crs.getCoordinateSystem().getAxis( dimension );
    if( axis.getDirection() == AxisDirection.OTHER ){
      return processRingToPrimitive( bounds, ring, dimension+1 );
    }
    return processRingToVolumne( bounds, ring, dimension+1 );
  }

  private PrimitiveImpl processRingToVolumne(Envelope bounds, Ring ring, int i) {
    // go into a volume
    throw new UnsupportedOperationException("Not yet 3D");
  }

  /**
   * This is the first and easy step ...
   * @param bounds
   * @param dimension
   */
  public LineSegment processBoundsToSegment( Envelope bounds ){
    final int D=0;
    CoordinateReferenceSystem crs = bounds.getCoordinateReferenceSystem();
    CoordinateSystemAxis axis = crs.getCoordinateSystem().getAxis( D );
   
    DirectPosition positionA = positionFactory.createDirectPosition(null); //new DirectPositionImpl(crs);
    DirectPosition positionB = positionFactory.createDirectPosition(null); //new DirectPositionImpl(crs);   
    if( axis.getDirection() != AxisDirection.OTHER ){
      positionA.setOrdinate(D, bounds.getMinimum(D) );
      positionB.setOrdinate(D, bounds.getMaximum(D) );
    }   
    PointArrayImpl array = new PointArrayImpl(crs );
    array.add( positionA );
    array.add( positionB );
   
    return new LineSegmentImpl( array, 0.0 );
  }
  /**
   * This is pass #2 ...
   * @return
   */
  public Ring processBoundsToRing( Envelope bounds, LineSegment segment, final int D ){
    DirectPosition one = positionFactory.createDirectPosition(segment.getStartPoint().getCoordinate()); //new DirectPositionImpl( segment.getStartPoint() );
    one.setOrdinate( D, bounds.getMinimum(D) );
   
    DirectPosition two = positionFactory.createDirectPosition(segment.getEndPoint().getCoordinate()); //new DirectPositionImpl( segment.getEndPoint() );
    two.setOrdinate( D, bounds.getMinimum(D) );
   
    DirectPosition three = positionFactory.createDirectPosition(two.getCoordinate()); //new DirectPositionImpl( two );
    three.setOrdinate( D, bounds.getMaximum(D) );
   
    DirectPosition four = positionFactory.createDirectPosition(one.getCoordinate()); //new DirectPositionImpl( one );
    four.setOrdinate( D, bounds.getMaximum(D) );
   
    LineSegment edge1 = new LineSegmentImpl( one, two, 0.0 );
    LineSegment edge2 = new LineSegmentImpl( two, three, 0.0 );
    LineSegment edge3 = new LineSegmentImpl( three, four, 0.0 );
    LineSegment edge4 = new LineSegmentImpl( four, one, 0.0 );
   
    List<OrientableCurve> edges = new ArrayList<OrientableCurve>();
    edges.add( new CurveImpl( edge1 ));
    edges.add( new CurveImpl( edge2 ));
    edges.add( new CurveImpl( edge3 ));
    edges.add( new CurveImpl( edge4 ));
    return this.createRing(edges);
  }
   
  /**
   * Creates a Ring conforming to the given DirectPositions. Helps to build
   * Rings for SurfaceBoundaries.
   *
   * @param directPositions
   * @return a Ring
   */
  public Ring createRingByDirectPositions(List<DirectPosition> directPositions) {
    // Test ok

    // Create List of OrientableCurve´s (Curve´s)
    OrientableCurve curve = this
        .createCurveByDirectPositions(directPositions);
    List<OrientableCurve> orientableCurves = new ArrayList<OrientableCurve>();
    orientableCurves.add(curve);

    return this.createRing(orientableCurves);
  }

  /**
   * Creates a Ring conforming to the given Positions
   *
   * @param aPositions
   * @return
   */
  public Ring createRingByPositions(List<Position> aPositions) {

    // Create List of OrientableCurve´s (Curve´s)
    OrientableCurve curve = this.createCurveByPositions(aPositions);
    List<OrientableCurve> orientableCurves = new ArrayList<OrientableCurve>();
    orientableCurves.add(curve);

    return this.createRing(orientableCurves);

  }

  /**
   * Creates a Curve conforming to the given DirectPositions Tested by Sanjay -
   *
   * @param directPositions
   * @return a Ring
   */
  public Curve createCurveByDirectPositions(
      List<DirectPosition> aDirectPositions) {
    // Test ok

    // GeometryFactoryImpl coordFactory =
    // this.geometryFactory.getGeometryFactoryImpl();

    // Create List of Position´s
    List<Position> positionList = createPositions(aDirectPositions);
    // List<Position> positionList =
    // coordFactory.createPositions(aDirectPositions);

    // Create List of CurveSegment´s (LineString´s)
    LineStringImpl lineString = new LineStringImpl(new PointArrayImpl(
        positionList), 0.0);
    // LineStringImpl lineString =
    // coordFactory.createLineString(aPositions);
    List<CurveSegment> segments = new ArrayList<CurveSegment>();
    segments.add(lineString);
   
    // Create List of OrientableCurve´s (Curve´s)
    return this.createCurve(segments);
  }

  /**
   * Converts a List of DirectPosition objects to a List of Position objects
   *
   * @param aDirectPositions
   *            List of DirectPosition objects
   * @return List of Position objects
   */
  public List<Position> createPositions(List<DirectPosition> aDirectPositions) {

    List<Position> rPositions = new LinkedList<Position>();
    for (int i = 0; i < aDirectPositions.size(); i++) {
      rPositions.add(new PositionImpl(aDirectPositions.get(i)));
    }

    return rPositions;
  }

  /**
   * Creates a curve bu Positions
   *
   * @param aPositions
   * @return Curve
   */
  public CurveImpl createCurveByPositions(List<Position> aPositions) {
    // GeometryFactoryImpl coordFactory =
    // this.geometryFactory.getGeometryFactoryImpl();

    // Create List of CurveSegment´s (LineString´s)
    LineStringImpl lineString = new LineStringImpl(new PointArrayImpl(
        aPositions), 0.0);
    // LineStringImpl lineString =
    // coordFactory.createLineString(aPositions);
    List<CurveSegment> segments = new ArrayList<CurveSegment>();
    segments.add(lineString);

    // Create List of OrientableCurve´s (Curve´s)
    return this.createCurve(segments);
  }

  /**
   * Creates a simple surface without holes by a list of DirectPositions
   *
   * @param positions
   *            List of positions, the last positions must be equal to the
   *            first position
   * @return a Surface defined by the given positions
   */
  public SurfaceImpl createSurfaceByDirectPositions(
      List<DirectPosition> positions) {
    // Test ok
    Ring extRing = this.createRingByDirectPositions(positions);
    List<Ring> intRings = new ArrayList<Ring>();
    SurfaceBoundary sfb = this.createSurfaceBoundary(extRing, intRings);
    return this.createSurface(sfb);
  }
 
}
TOP

Related Classes of org.geotools.geometry.iso.primitive.PrimitiveFactoryImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.