public class Chan<T> {

    private MVar<MVar<ChanElem<T>>> read;
    private MVar<MVar<ChanElem<T>>> write;


    public Chan () {
	MVar<ChanElem<T>> hole = new MVar<ChanElem<T>>();
	read = new MVar<MVar<ChanElem<T>>>(hole);
	write = new MVar<MVar<ChanElem<T>>>(hole);
    }

    public T read () {
	MVar<ChanElem<T>> rend = read.take();
	ChanElem<T> item = rend.read();
	read.put(item.next());
	return item.value();
    }

    public void write (T o) {
	MVar<ChanElem<T>> newHole = new MVar<ChanElem<T>>();
	MVar<ChanElem<T>> oldHole = write.take();
	oldHole.put(new ChanElem<T>(o,newHole));
	write.put(newHole);
    }

    public boolean isEmpty () {
	MVar<ChanElem<T>> rend = read.take();
	boolean b = rend.isEmpty();
	read.put(rend);
	return b;
    }

    public void unGet (T o) {
        MVar<ChanElem<T>> newRend = new MVar<ChanElem<T>>();
	MVar<ChanElem<T>> rend = read.take();
	newRend.put(new ChanElem<T> (o,rend));
	read.put(newRend);
    }
}
    

class ChanElem<T> {
	
    private T value;
    private MVar<ChanElem<T>> next;
    
    public ChanElem (T value, MVar<ChanElem<T>> next) {
	this.value = value;
	this.next = next;
    }
    
    public ChanElem () {
	this.value = null;
	this.next = null;
    }
    
    public T value () {
	return value;
    }
    
    public MVar<ChanElem<T>> next () {
	return next;
    }
}
