Sunday, 22 February 2015

Java Class Design using Builder

Background

Two important principle of Object Oriented programming are - 
  1. For each class design aim for low coupling and high cohesion.
  2. Classes should be open for extension but closed for modification.

We will see how we can use these to design any classes.



Class Design


Lets design a simple Employee class which has it's name.

public class Employee {
    
    private String name;
    
    public Employee(String name)
    {
        this.name = name;
    }
    
}


Looks good. Every time anyone has to create an instance of Employee he has to supply name in the constructor. So you see any flaw in this?

Well there is. Lets say new requirement comes up and you now have to add employee age. What would you do?

One way would be change the constructor to include age now.

public class Employee {
    
    private String name;
    private int age;
    
    public Employee(String name, int age)
    {
        this.name = name;
        this.age = age;
    }  
}


Though it solves our new requirement it will break all our existing code. All Users using our existing code will  have to make changes now. So we definitely cannot remove the constructor with name in it. So what do we do next ?

Lets create an overridden constructor.

public class Employee {
    
    private String name;
    private int age;
    
    public Employee(String name)
    {
        this.name = name;
    }
    
    public Employee(String name, int age)
    {
        this(name);
        this.age = age;
    }
    
}


Ok this looks good. This will not break existing code and will meet our existing requirement. Now take a minute to this what about future requirements. Lets say you may have to add employees sex, salary etc in the Employee mode. What will you do then? Keep adding overloaded constructors?

Sure you can. But that is a very poor design choice. Simplest thing to do is following -

public class Employee {
    
    private String name;
    private int age;
    
    public Employee(){}

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    
}


That's right. A simple no argument default constructor and getter, setter methods corresponding to instance variables. This is flexible design implementation. Going forward we can add as many instance variables with corresponding get and set methods.

Though this is good and simple class design. I would not say it is optimal. What if you want to ensure that user should not create a Employee instance without providing name.

Sure different developers will have different methods to ensure that and have good design. I like to use builder for that. See following -


import static org.apache.commons.lang3.Validate.*;
public class Employee
{
    private String name;
    private int age;
    
    private Employee() {}

    public String getName()
    {
        return name;
    }
    
    public int getAge()
    {
        return age;
    }

    public static class EmployeeBuilder
    {
        private final Employee employee;

        public EmployeeBuilder()
        {
            employee = new Employee();
        }

        public EmployeeBuilder setName(String name)
        {
            employee.name = name;
            return this;
        }
        
        public EmployeeBuilder setAge(int age)
        {
            employee.age = age;
            return this;
        }

        public Employee build()
        {
            validateFields();
            return employee;
        }

        private void validateFields()
        {
            notNull(employee.name, "Employee Name cannot be Empty");
            isTrue(employee.age >= 21, "Employee age cannot be less than 21");
        }
    }
}



Notice following points -
  1. We made constructor of Employee class private. So no one can directly instantiate Employee class. He or she has to use our Builder class.
  2. There is not setter methods in Employee class. Again builder should be used.
  3. Builder's build() methods validates our requirements like name cannot be null or age has to be more than 21.
  4. You can easily create Employee objects using - 
Employee employee = new EmployeeBuilder().setName("Aniket").setAge(23).build();

Friday, 20 February 2015

Using Android Emulator to test your Android Application

Background

I have written a couple of posts before on Android Application development, debugging and other general concepts. As you know Android is just an operating system running on Linux kernel customized for resource constrained environment like that of handheld systems. Before you roll out your application to other users you need to test it on various models (with different configurations). This is where you Emulator comes into picture. You can create a emulator that suits your testing requirement. In this post we will cover some of the events that we can simulate with emulators like setting batter to low etc. So basically we will use a telnet to connect to Android virtual device and issue commands to simulate various events.

Creating an Android virtual Device

Lets start by creating an Android virtual device. Open your Eclipse which come as a pert of ADT bundle.

Go to 

Windows -> Android Virtual Device Manager

I currently don't have any emulators. So the manager shows no emulators.



Go ahead and create one. Click on create button on the right. Fill in the configuration details as per your requirements.


After successful creation of AVD start it. Wait for it to initialize (It may take couple of minutes). My Emulator looks like the following at startup -



Now lets connect to it via telnet. See the number at the top of the Emulator ? (5554:athakur_Nexus) This number (5554) is the port number emulator is running on. You can do various action by connecting to it via telnet. Connecting is very simple. Simply type following in command prompt -

  • telnet localhost 5554
and you  get a 'OK' response. Notices the 3G network symbol at the top right corner. Lets change it to 2G or edge. Command for that is -
  • network speed edge


To change it back to 3G you can use command -
  • network speed full
 You can also change the battery status of your emulated device.  Notice the battery icon. It about little more than 50% charged and battery is still charging (power is connected).

Lets first reduce the battery level. To do so you can use following command -
  • power capacity 4
and notice how battery level drops.



Battery is still charging. Notice the lightning symbol inside battery icon. Lets stop the charging. To do so use the following command -
  • battery status not-charging (Usage: "status unknown|charging|discharging|not-charging|full")
You can also simulate sms.  I am going to send a dummy message from telnet and you should see it as a proper message received in the emulator. Command for the same is -
  • sms send 9999999999 "Hi! - From Open Source For Geeks" (Syntax : sms send <phonenumber> <text message>)




You can even change your  coordinates on the map with following command -

  • geo fix 2.00 39.12
It is also possible to make a call from one emulator to  another. Simple go to dialer and dial port number of the other emulator. Emulator number running with that port will receive the call.






These are only some command. To get a full list of command you can type help after connecting to telnet -


Note :

  • You can reorient your device in the emulator by pressing Ctrl+F12 (Command+F12 on Mac). When this happens and your current Activity is killed and restarted.

Related Links

Monday, 16 February 2015

Proxy Design Pattern in Java

Background

We know proxy design pattern involves a representative object that controls access to it's subject that may be - 
  1. Remote
  2. Expensive to create (Virtual Proxy) or
  3. Need secure access (Protection Proxy)
In last post on

Understanding Java Remote Method Invocation (RMI)

We say example of Remote proxy. Stub is essentially the proxy that controls access of actual remote object.

Here is the summary of what happens in Proxy design pattern -

Proxy class implements the same interface as that of the Subject. Client crates a instance of proxy class (Typically using Factory pattern.) rather than the actual subject and calls methods on proxy (this is possible since both proxy and subject implement same interface). Now proxy internally instantiates Subject and calls methods on it depending on the purpose of the proxy.




We will see example of both Virtual as well as Protection proxy in this example. Later we will also see how proxies are dynamically created (Java has in built support for it).

 Virtual Proxy

Lets say we are creating a news website. Lets design Interface for it - 

public interface NewsSiteInterface {
    void showNews();
}

Now lets write the actual implementation - 
public class NewsSiteImpl implements NewsSiteInterface {
    
    String news;
    
    public NewsSiteImpl() {
        //simulate blocking data transfer
        try {
            Thread.sleep(5000);
            System.out.println("Data Received");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        news = "Hello World";
    }
    
    public void showNews() {
        System.out.println(news);
    }

  
}


Notice the constructor simulates fetching data which is a block call. If you directly make instance of NewsSiteImpl and call showNews() on it site may possible hang as instance creation will take time. Lets now create a proxy that would avoid this blocking call.


public class NewsSiteProxy implements NewsSiteInterface {
    
    NewsSiteInterface newsSite;
    
    public NewsSiteProxy() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                newsSite = new NewsSiteImpl();
                showNews();
            }
        }).start();
    }

    @Override
    public void showNews() {
        if(newsSite == null) {
            System.out.println("Loading....");]
        }
        else {
            newsSite.showNews();
        }
        
    }

}

So now we create instance of  NewsSiteInterface in another thread asynchronously. So user can go ahead and call showNews(). Obviously data may not be loaded by then, So we just show Loading...
Important point out program will not get hanged. Lets test out setup.

public class NewsDemo {
    public static void main(String args[])
    {
        NewsSiteInterface newSite  = new NewsSiteProxy();
        newSite.showNews();
        newSite.showNews();
    }
    
}

and the output is -

Loading....
Loading....
Data Received
Hello World

So that was our virtual proxy that helped us tackle creating on expensive time consuming instance.

Now lets see our protection proxy. Well the concept remains the same. Instead of doing task asynchronously we do some validation.

 In our next protection proxy demo we will use Java Dynamic proxies.

Protection Proxy and Java Dynamic proxy

Lets say we are designing a programming QnA site like Stack Overflow.  When user create a account on Stack Overflow he essentially created a profile. Lets write a class for that -


public interface StackOverflowProfile {
    String askQuestion(String question);
    String writeAnswer(String answer);
    void upVote();
    void downVote();
}


Now lets create a concrete implementation of this profile interface.

public class StackOverflowProfileImpl implements StackOverflowProfile {

    @Override
    public void askQuestion(String question) {
        //Ask Question
    }

    @Override
    public void writeAnswer(String answer) {
        //Provide Answer to a question
    }

    @Override
    public void upVote() {
        //Up vote an Answer or Question
        
    }

    @Override
    public void downVote() {
        //Down vote an Answer or Question
    }

}


So far so good. Program would work but we did a major mistake here. We do not have verification check in the code which means a user can keep asking questions, answer them and keep upvoting the same thereby increasing his or her reputation.  Only if we knew proxy pattern before :)

Lets divide out auth checks / Proxy into two parts -
  1. Owner of a Question
  2. Non Owner
Our use case is -
  • Owner can ask question, answer question but cannot do upvote or downvote.
  • Non owner cannot ask question but he can answer, upvote or downvote.
Note : Each profile can use either of the proxy depending on if he or she is the owner of the Question. If owner then Owner Proxy will be used and upvote or downvote operations will not be allowed. If non owner proxy is used then question cannot be asked (as someone else is the owner) but answer, upvote, dowvote operations are allowed.

We are now going to use Dynamic proxies to implement above checks -

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class OwnerSOProfile implements InvocationHandler {
    
    StackOverflowProfile soProfile;
    
    public OwnerSOProfile(StackOverflowProfile soProfile)
    {
        this.soProfile = soProfile;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        try
        {
            if(method.getName().equalsIgnoreCase("askQuestion"))
            {
                method.invoke(proxy, args);
            }
            else if(method.getName().equalsIgnoreCase("writeAnswer"))
            {
                method.invoke(proxy, args);
            }
            else if(method.getName().equalsIgnoreCase("upVote"))
            {
                throw new IllegalAccessException("Cannot Up vote own question or answer");
            }
            else if(method.getName().equalsIgnoreCase("downVote"))
            {
                throw new IllegalAccessException("Cannot down vote own question or answer");
            }
        }
        catch(InvocationTargetException ex) {
            ex.printStackTrace();
        }
        return null;
    }
}




and

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class NonOwnerSoProfile implements InvocationHandler {
    
    StackOverflowProfile soProfile;
    
    public NonOwnerSoProfile(StackOverflowProfile soProfile)
    {
        this.soProfile = soProfile;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        
        try
        {
            if(method.getName().equalsIgnoreCase("askQuestion"))
            {
                throw new IllegalAccessException("Cannot edit question as you are not the owner");
            }
            else if(method.getName().equalsIgnoreCase("writeAnswer"))
            {
                method.invoke(proxy, args);
            }
            else if(method.getName().equalsIgnoreCase("upVote"))
            {
                method.invoke(proxy, args);
            }
            else if(method.getName().equalsIgnoreCase("downVote"))
            {
                method.invoke(proxy, args);
            }
        }
        catch(InvocationTargetException ex) {
            ex.printStackTrace();
        }
        return null;
    }
}



and finally lets do a demo -

import java.lang.reflect.Proxy;

public class SODemo {
    
    public static void main(String args[])
    {
        //general profile
        StackOverflowProfile profile = new StackOverflowProfileImpl();
        //allowed
        (profile).askQuestion("What is proxy pattern?");
        //not allowed
        getOwnerSoProxy(profile).upVote();
        //not allowed
        getNonOwnerSoProxy(profile).askQuestion("Java anti patterns?");
        //alowed
        getNonOwnerSoProxy(profile).upVote();
    }
    
    public static StackOverflowProfile getOwnerSoProxy(StackOverflowProfile profile)
    {
        return (StackOverflowProfile) Proxy.newProxyInstance(profile.getClass().getClassLoader(), profile.getClass().getInterfaces(), new OwnerSOProfile(profile));
    }
    
    public static StackOverflowProfile getNonOwnerSoProxy(StackOverflowProfile profile)
    {
        return (StackOverflowProfile) Proxy.newProxyInstance(profile.getClass().getClassLoader(), profile.getClass().getInterfaces(), new NonOwnerSoProfile(profile));
    }

}

Note : For above demo code. Try one call at a time because we have not added any Exception handling so whenever IllegalAccess Exception is thrown JVM will terminate.

Related Links

Saturday, 14 February 2015

Understanding Java Remote Method Invocation (RMI)

Background

Everyone with Java background would know we can easily call methods on an instantiated object as long as everything is limited to same JVM (Java virtual machine). Even imagined if we can invoke methods on a remote object as if they were local. Well the answer is yes and that is exactly what we are going to see in this post. Infact RMI uses one of the famous design patters - The Proxy Pattern . We will cover that in detail under design patterns. For now keep following in mind -

Proxy Design Pattern involves a representative Object (A proxy) that controls access to another object which may be - 
  • Remote
  • Expensive to Create (Virtual Proxy)
  • Needs secure access (Protection Proxy)

This post aims to help you understand how RMI works, how objects interact with a simple demo.

Getting Started

Java RMI APIs essentially help you to invoke methods on remote object.  There are four essential entities that take part in RMI - 
  1. Client
  2. Stub / Client Helper (Proxy)
  3. Server
  4. Skeleton / Server Helper

Server is where you have your actual implementation of service. Client want to call it.  Client code cannot directly call methods on remote server object as they are on different JVMs .So client creates a representation of actual service called stub or proxy and invokes methods on it. Stub takes this call, serializes method name, parameters etc and send its over network to the skeleton on the server. skeleton then deserializes the information and invokes the method on actual object. It takes the result serializes it and sends in back to stub. Stub deserializes the result and returns it back to the client code.


That's for the overview of how RMI works. Now lets see an actual demo in Java.


To The Code....

Lets start by writing an interface for the remote service - 

import java.rmi.Remote;
import java.rmi.RemoteException;


public interface GreeterService extends Remote {
    public String displayWelcomeMessage(String name) throws RemoteException;
}

Notice how our interface extends java.rmi.Remote interface? It is a marker interface(No methods in it) just like - 
  • java.lang.Cloneable
  • java.io.Serializable

It is used to mark that methods of instances of class that implement this interface can be called from non local (remote) virtual machines.

Also notices how our method declaration throws RemoteException ? Well it's not mandatory but a good practice so that the implementation handles it and is aware that thing may go wrong as calls are made to another virtual machine (which may be remote).

Lets write implementation for this -

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;


public class GreeterServiceImpl extends UnicastRemoteObject implements GreeterService {

    protected GreeterServiceImpl() throws RemoteException { }

    @Override
    public String displayWelcomeMessage(String name) throws RemoteException {
        return "Hi " + name + " welcome to Open Source For Geeks!";
    }
    
    public static void main(String args[])
    {
        try {
            GreeterService greeterService = new GreeterServiceImpl();
            Naming.rebind("greeterServiceObj", greeterService);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


So we wrote a class that implements the GreeterService and it's methods.

Notice how we have extended UnicastRemoteObject? That is because that super class takes care of actual communication part with remote VM.

Also notice we have declared a no-args constructor that throws RemoteException. That's because super class UnicastRemoteObject has constructor that throws that Exception.
  • UnicastRemoteObject is used for exporting a remote object with JRMP and obtaining a stub that communicates to the remote object (Socket level logic). 
  • We will use this GreeterServiceImpl class to generate skeleton and stub and the communication logic is handled by UnicastRemoteObject that GreeterServiceImpl extends.
  • JRMP is Java Remote Method Protocol.  It is a Java-specific, stream-based protocol for Java-to-Java remote calls, requiring both clients and server to use Java objects. RMI-IIOP is an alternative protocol which exposes Java objects to CORBA ORBs.
We are done with our server level logic. Now lets
  1. Create skeleton and stub, 
  2. start rmi registry
  3. Start Remote Service
First Compile classes -
  • javac *.java

You should have two class files - GreeterService.class and GreeterServiceImpl.class. Now you can go ahead and create stub skeleton . Run

  • rmic GreeterServiceImpl 
 You should get GreeterServiceImpl_Stub.class file.


Note : From rmic 1.2 onwards, Java don't generate skeletion class any more. New JRMP protocol supported for RMI has got rid of the use of skeleton files.  




Now start rmiregistry. Just type rmiregistry in command line.


Note 1 : Start rmiregistry from location that has access to the stub class file.
Note 2 : If you want to start your rmi registry on different port (defult is 1099) you can use command - rmiregistry [port]

 Now start your remote Service -

  • java GreeterServiceImpl
Your remote service and rmiregistry are all set. Now lets write client and test our setup -

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;


public class GreeterClient {

    public static void main(String args[])
    {
        try {
            GreeterService greeterService = (GreeterService) Naming.lookup("rmi://127.0.0.1/greeterServiceObj");
            System.out.println(greeterService.displayWelcomeMessage("Aniket"));
        } catch (MalformedURLException | RemoteException | NotBoundException e) {
            e.printStackTrace();
        }
    }
    
}


Make sure your client Java process has access to following Java class files -
  1. GreeterClient.class
  2. GreeterService.class
  3. GreeterServiceImpl_Stub.class
 Yes! That's all client needs. Lets run client.


  • javac *.java
  • java GreeterClient

 Related Links



Friday, 13 February 2015

Understanding how HashMap and HashSet work in Java

Background

Hashing is a very important concept in computer programming and a very popular concept for interview questions. Two important data structures related to hashing are HashMap and HashSet which is exactly what we are going to look at in this post.

Overview

If you are from a computer science background you would know HashMap is a data structure which stores key value pairs where as a HashSet stores unique data. In HashMap we have kind of buckets and each data added to a HashMap falls into one of the buckets depending on the hash value of it. Also you must have heard that adding and retrieving objects in HashMap happen in time complexity O(1).

But still there are open end question like -
  • What happens when two objects added to HashMap have same hash (code) value ? - a situation typically known as collision.
  • If above is handled how get and put work in hashmap?.... and so on.
We will address them now.

Understanding how HashMap works

 You can visualize HashMap as follows-




So you have an Array and each array position is essentially a Linked List. As you know you don't have to specify size of the HashMap. It increases dynamically like ArrayList.  The main data structure is essentially an array.

    /**
     * The table, resized as necessary. Length MUST Always be a power of two.
     */
    transient Entry[] table;


When you create a HashMap you either choose to provide initial capacity or when you don't a default value is used.

    /**
     * The default initial capacity - MUST be a power of two.
     */
    static final int DEFAULT_INITIAL_CAPACITY = 16;


 When table is created it is created with either this initial default capacity or the capacity you provide in the constructor.

Next important thing is when should out table we resized to meet the dynamically changing data size of HashMap. Answer depends on a threshold that is determined by load factor.

    /**

     * The load factor used when none specified in constructor.

     */

    static final float DEFAULT_LOAD_FACTOR = 0.75f;


HashMap provides a constructor to initialize load factor as well. So when your data size equals

  • threshold = table capacity * load factor

then the HashMap table is resized. Constructors are as follows -

    /**
     * Constructs an empty <tt>HashMap</tt> with the specified initial
     * capacity and load factor.
     *
     * @param  initialCapacity the initial capacity
     * @param  loadFactor      the load factor
     * @throws IllegalArgumentException if the initial capacity is negative
     *         or the load factor is nonpositive
     */
    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);

        // Find a power of 2 >= initialCapacity
        int capacity = 1;
        while (capacity < initialCapacity)
            capacity <<= 1;

        this.loadFactor = loadFactor;
        threshold = (int)(capacity * loadFactor);
        table = new Entry[capacity];
        init();
    }

    /**
     * Constructs an empty <tt>HashMap</tt> with the specified initial
     * capacity and the default load factor (0.75).
     *
     * @param  initialCapacity the initial capacity.
     * @throws IllegalArgumentException if the initial capacity is negative.
     */
    public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    /**
     * Constructs an empty <tt>HashMap</tt> with the default initial capacity
     * (16) and the default load factor (0.75).
     */
    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
        table = new Entry[DEFAULT_INITIAL_CAPACITY];
        init();
    }


How is data with keys generating same hash code stored in HashMap?

As mentioned earlier each index has reference to object of type Entry which is a Linked List. It has a next pointer. So if an entry is added to hash map it's hash code is computed which determines the index at which it should be put. If that index has an entry then new entry is added to the start of the linked list and existing linked list is appended to next of it.

    public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

    void addEntry(int hash, K key, V value, int bucketIndex) {
    Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        if (size++ >= threshold)
            resize(2 * table.length);
    }


Also note how null is handled. Yes null is an acceptable key in HashMap.

So how is data retrieved if two keys generate same has code?

Same hash code will make searched for both keys data land on same index in the table. From there the each Entry object is iterated over and it's key compared with the search key. On successful match corresponding value is returned.

    public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
        }
        return null;
    }


Lastly lets see HashSet.

Understanding HashSet

Well if you are still guessing the data structure of HashSet then following would be a surprise -

    private transient HashMap<E,Object> map;

    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();



Yup HashSet stores data as keys of HashMap with dummy value. Constructor is equivalent to that of HashMap -

    /**
     * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
     * default initial capacity (16) and load factor (0.75).
     */
    public HashSet() {
    map = new HashMap<E,Object>();
    } 



    public HashSet(int initialCapacity, float loadFactor) {
    map = new HashMap<E,Object>(initialCapacity, loadFactor);
    }



    public HashSet(int initialCapacity) {
    map = new HashMap<E,Object>(initialCapacity);
    }


Add and Remove methods are as follows -

    public boolean add(E e) {
    return map.put(e, PRESENT)==null;
    }



    public boolean remove(Object o) {
    return map.remove(o)==PRESENT;
    }


Related Links

t> UA-39527780-1 back to top