// Path: src/com/infdot/analysis/solver/DataflowExpression.java
// public interface DataflowExpression<V> {
// 	/**
// 	 * Evaluates expression using the given variable values.
// 	 */
// 	V eval(V[] values);
// 	
// 	/**
// 	 * Helper to collect all variables,
// 	 */
// 	void collectVariables(Set<Integer> variables);
// }
// 
// Path: src/com/infdot/analysis/solver/lattice/ElementJoinOperation.java
// public interface ElementJoinOperation<V> {
// 	V join(V e1, V e2);
// }
// 
// Path: src/com/infdot/analysis/util/StringUtil.java
// public class StringUtil {
// 	
// 	public static String join(Collection<?> col, String separator) {
// 		StringBuilder builder = new StringBuilder();
// 		
// 		boolean first = true;
// 		for (Object o : col) {
// 			if (first) {
// 				first = false;
// 			} else {
// 				builder.append(separator);
// 			}
// 			builder.append(o);
// 		}
// 		
// 		return builder.toString();
// 	}
// }


import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.infdot.analysis.solver.DataflowExpression;
import com.infdot.analysis.solver.lattice.ElementJoinOperation;
import com.infdot.analysis.util.StringUtil;
		Map<K, V> result = new HashMap<K, V>(expressions.get(0).eval(values));
		
		for (DataflowExpression<Map<K, V>> e : expressions.subList(1, expressions.size())) {
			joinInto(result, e.eval(values));
		}
		
		return result;
	}
	
	private void joinInto(Map<K, V> result, Map<K, V> joinable) {
		for (K k : result.keySet()) {
			result.put(k, elementJoin.join(result.get(k), joinable.get(k)));
		}
		
		for (K k : joinable.keySet()) {
			if (!result.containsKey(k)) {
				result.put(k, elementJoin.join(result.get(k), joinable.get(k)));
			}
		}
	}

	@Override
	public void collectVariables(Set<Integer> variables) {
		for (DataflowExpression<Map<K, V>> e : expressions) {
			e.collectVariables(variables);
		}
	}

	@Override
	public String toString() {
// Path: src/com/infdot/analysis/solver/DataflowExpression.java
// public interface DataflowExpression<V> {
// 	/**
// 	 * Evaluates expression using the given variable values.
// 	 */
// 	V eval(V[] values);
// 	
// 	/**
// 	 * Helper to collect all variables,
// 	 */
// 	void collectVariables(Set<Integer> variables);
// }
// 
// Path: src/com/infdot/analysis/solver/lattice/ElementJoinOperation.java
// public interface ElementJoinOperation<V> {
// 	V join(V e1, V e2);
// }
// 
// Path: src/com/infdot/analysis/util/StringUtil.java
// public class StringUtil {
// 	
// 	public static String join(Collection<?> col, String separator) {
// 		StringBuilder builder = new StringBuilder();
// 		
// 		boolean first = true;
// 		for (Object o : col) {
// 			if (first) {
// 				first = false;
// 			} else {
// 				builder.append(separator);
// 			}
// 			builder.append(o);
// 		}
// 		
// 		return builder.toString();
// 	}
// }


// Path: src/com/infdot/analysis/solver/lattice/map/AllJoinOperation.java
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.infdot.analysis.solver.DataflowExpression;
import com.infdot.analysis.solver.lattice.ElementJoinOperation;
import com.infdot.analysis.util.StringUtil;

		Map<K, V> result = new HashMap<K, V>(expressions.get(0).eval(values));
		
		for (DataflowExpression<Map<K, V>> e : expressions.subList(1, expressions.size())) {
			joinInto(result, e.eval(values));
		}
		
		return result;
	}
	
	private void joinInto(Map<K, V> result, Map<K, V> joinable) {
		for (K k : result.keySet()) {
			result.put(k, elementJoin.join(result.get(k), joinable.get(k)));
		}
		
		for (K k : joinable.keySet()) {
			if (!result.containsKey(k)) {
				result.put(k, elementJoin.join(result.get(k), joinable.get(k)));
			}
		}
	}

	@Override
	public void collectVariables(Set<Integer> variables) {
		for (DataflowExpression<Map<K, V>> e : expressions) {
			e.collectVariables(variables);
		}
	}

	@Override
	public String toString() {
		return "ALLJOIN(" + StringUtil.join(expressions, ",") + ")";