misc/src/main/java/io/hummer/util/log/LogUtil.java
public class LogUtil {

	private static final AtomicBoolean loggerInitialized = new AtomicBoolean(false); /* this variable needs to stay BEFORE the logger initialization call getLogger(...)! */

	/**
	 * Determines the calling class from the Thread's 
	 * callstack and returns a logger for this class.
	 * 
	 * The entry we want is at position 2, example:
	 * 
	 * 0: java.lang.Thread.getStackTrace()
	 * 1: io.hummer.util.Util.getLogger()
	 * 2: my.package.MyClass.myInitMethod()
	 * 3: ...
	 * @return logger for the calling class
	 */
	public static Logger getLogger() {
		StackTraceElement[] stack = Thread.currentThread().getStackTrace();
		try {
			return getLogger(Class.forName(stack[2].getClassName()));
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e);
		}
	}
 
	public static java.util.logging.Logger getLogger(String name) {
		java.util.logging.Logger logger = java.util.logging.Logger.getLogger(name);
		logger.setParent(java.util.logging.Logger.getLogger(java.util.logging.Logger.GLOBAL_LOGGER_NAME));
		return logger;
	}

	public static Logger getLogger(Class<?> c) {
		Object lock = loggerInitialized != null ? loggerInitialized : new Object();
		synchronized(lock) {
			//System.out.println(Thread.currentThread() + " in locked zone");
			final String logPropFile = "log4j.properties";
			if(loggerInitialized == null || !loggerInitialized.get()) {
				if(loggerInitialized != null) loggerInitialized.set(true);

				File conf = new File(logPropFile);
				//System.out.println("sysconfig: ---> " + System.getProperty("log4j.configuration") + " - " + conf.exists());
				if(conf.exists()
						&& System.getProperty("log4j.configuration") == null) {
					System.out.println("Logger configuration (file): " + new File(logPropFile).toURI());
					System.setProperty("log4j.configuration", "file:" + conf);
					if(loggerInitialized != null) loggerInitialized.set(true);
				} else if(!conf.exists()) {
					final Properties props = new Properties();
					try {
						Map<URL,String> res = ClasspathUtil.getSystemResources(
								logPropFile, "^((?!((org/apache/xml/security)|(foobar))).)*$", false, true);
						if(!res.isEmpty()) {
							//System.out.println("Found " + logPropFile + " system resources: " + res);
							for(URL u : res.keySet()) {
								InputStream configStream = u.openStream();
								props.load(configStream);
								System.out.println("Logger config (classpath): " + u);
								configStream.close();
							}
							//System.out.println("Done loading system resources.");
						} else if(ClassLoader.getSystemResource("/" + logPropFile) != null) {
							System.out.println("Loading " + logPropFile + " via ClassLoader system stream.");
							props.load(ClassLoader.getSystemResourceAsStream("/" + logPropFile));
						} else if(c.getClass().getResource(logPropFile) != null) {
							System.out.println("Loading " + logPropFile + " via resource stream.");
							props.load(c.getClass().getResourceAsStream(logPropFile));
						} else if(c.getClass().getClassLoader() != null && 
								c.getClass().getClassLoader().getResource(logPropFile) != null) {
							System.out.println("Loading " + logPropFile + " via classloader resource stream of class " + c.getClass());
							props.load(c.getClass().getClassLoader().getResourceAsStream(logPropFile));
						} else if(ClassLoader.getSystemClassLoader().getResource(logPropFile) != null) {
							System.out.println("Loading " + logPropFile + " via ClassLoader resource stream.");
							props.load(ClassLoader.getSystemClassLoader().getResourceAsStream(logPropFile));
						} else {
							System.out.println(
									"Error: Cannot find log4j configuration file.");
						}
					} catch(Exception e) {
						System.out.println(
								"Error: Cannot load log4j configuration file: " + e);
						e.printStackTrace();
					}
					/* determine whether we are running within Storm (creates threading problems) */
					boolean isStorm = false;
					try {
						Class.forName("backtype.storm.utils.Utils");
						System.out.println("Found Storm classes (http://nathanmarz.github.io) on the classpath, " +
								"which introduce threading/synchronization issues. Leaving Logger unconfigured!");
						isStorm = true;
					} catch (Exception e) { /*swallow*/ }

					if(!isStorm) {
						//System.out.println("Resetting logger config.");
						LogManager.resetConfiguration();
						//System.out.println("Configuring logger using properties: " + props);
						PropertyConfigurator.configure(props);
					}
				}
				
			}
			//System.out.println(Thread.currentThread() + " getting logger to return");
			Logger l = Logger.getLogger(c);
			//System.out.println(Thread.currentThread() + " returning logger " + l);
			return l;
		}
	}


}
misc/src/main/java/io/hummer/util/time/TimeUtil.java
public class TimeUtil {

	private static TimeUtil instance;
	private MathUtil mathUtil = new MathUtil();
	private StringUtil strUtil = new StringUtil();
	public Logger logger = LogUtil.getLogger(TimeUtil.class);

	private static class DurationEstimate {
		long startTime;
		long lastTime;
		int totalSteps;
		final List<Long> times = new LinkedList<Long>();
	}

	private Map<String,DurationEstimate> estimates = new HashMap<String,DurationEstimate>();

	public static TimeUtil getInstance() {
		if(instance == null) {
			instance = new TimeUtil();
		}
		return instance;
	}

	public String format(long milliseconds) {
		NumberFormat nf = NumberFormat.getInstance();
		nf.setMaximumFractionDigits(3);
		if(milliseconds < 0) {
			return "n/a";
		}
		if(milliseconds < 10*1000) {
			return milliseconds + "ms";
		}
		if(milliseconds < 2*60*1000) {
			return nf.format((double)milliseconds/1000.0) + "sec";
		}
		return nf.format((double)milliseconds/1000.0/60.0) + "min";
	}

	public double getRemainingTime(int totalExpectedItems, boolean addOneItem) {
		return getRemainingTime(null, totalExpectedItems, addOneItem);
	}
	public double getRemainingTime(String id, int totalExpectedSteps, boolean addOneFinishedSteps) {
		if(addOneFinishedSteps) {
			if(id == null)
				id = "";
			if(!estimates.containsKey(id)) {
				DurationEstimate d = new DurationEstimate();
				d.startTime = System.currentTimeMillis();
				d.lastTime = d.startTime;
				d.totalSteps = totalExpectedSteps;
				estimates.put(id, d);
			} else {
				DurationEstimate d = estimates.get(id);
				if(addOneFinishedSteps) {
					long lastTime = d.lastTime;
					d.lastTime = System.currentTimeMillis();
					d.totalSteps = totalExpectedSteps;
					d.times.add(d.lastTime - lastTime);
				}
			}
		}
		DurationEstimate d = estimates.get(id);
		if(d != null && !d.times.isEmpty()) {
			double avgTime = mathUtil.avg(d.times);
			return ((double)d.totalSteps - (double)d.times.size()) * avgTime;
		}
		return -1;
	}
	public void printRemainingTime(int totalExpectedSteps, boolean addOneFinishedSteps) {
		printRemainingTime(null, totalExpectedSteps, addOneFinishedSteps);
	}
	public void printRemainingTime(String id, int totalExpectedSteps, boolean addOneFinishedSteps) {
		String prefix = strUtil.isEmpty(id) ? "" : ("'" + id + "': ");
		logger.info(prefix + "Time remaining (apprx.): " + 
				format((long)getRemainingTime(id, totalExpectedSteps, addOneFinishedSteps)));
	}

}
cloud/src/main/java/io/hummer/util/cloud/CloudUtil.java
public abstract class CloudUtil {

	private static CloudUtil instance;
	private static final Logger logger = LogUtil.getLogger(CloudUtil.class);

	public abstract void startNewInstance(String imageID, boolean publicIP, boolean blockUntilRunning) throws Exception;
	
	public abstract List<CloudInstance> getInstances(String imageID, String userID) throws Exception;

	/**
	 * This method is Eucalyptus-specific. It takes as argument a string pattern
	 * for an image manifest file name, and returns a set of image IDs which match 
	 * the pattern. The manifest file name in Eucalyptus contains the name of 
	 * the S3/Walrus bucket in which the image parts (and the manifest) are 
	 * stored, plus the actual file name of the manifest; e.g., myBucket/myImage.manifest.xml
	 * 
	 * @param manifestPattern
	 * @return
	 * @throws Exception
	 */
	public abstract Set<String> getImageIDsForManifestName(String manifestPattern) throws Exception;

	public abstract Set<String> getImageIDsForImageName(String namePattern) throws Exception;

	public void startNewInstance(String imageID) throws Exception {
		startNewInstance(imageID, false);
	}
	public void startNewInstance(String imageID, boolean publicIP) throws Exception {
		startNewInstance(imageID, publicIP, true);
	}

	/**
	 * This method is Eucalyptus-specific. It takes as argument a string pattern
	 * for an image manifest file name. The manifest file name in Eucalyptus contains
	 * the name of the S3/Walrus bucket in which the image parts (and the manifest) are 
	 * stored, plus the actual file name of the manifest; e.g., myBucket/myImage.manifest.xml
	 * 
	 * @param manifestPattern
	 * @return
	 * @throws Exception
	 */
	public String getImageIDForManifestName(String manifestPattern) throws Exception {
		Set<String> ids = getImageIDsForManifestName(manifestPattern);
		if(ids.isEmpty())
			return null;
		if(ids.size() > 1)
			logger.warn("multiple Cloud VM image IDs found for name pattern '" + manifestPattern + "': " + ids);
		return ids.iterator().next();
	}

	/**
	 * This method is Openstack-specific. It takes as argument a string pattern
	 * for an image name.
	 * 
	 * @param namePattern
	 * @return
	 * @throws Exception
	 */
	public String getImageIDForImageName(String namePattern) throws Exception {
		Set<String> ids = getImageIDsForManifestName(namePattern);
		if(ids.isEmpty())
			return null;
		if(ids.size() > 1)
			logger.warn("multiple Cloud VM image IDs found for name pattern '" + namePattern + "': " + ids);
		return ids.iterator().next();
	}

	public int getNumInstances(String imageID, String userID) throws Exception {
		return getInstances(imageID, userID).size();
	}
	
	public List<CloudInstance> getInstancesOfImage(String imageID) throws Exception {
		return getInstances(imageID, null);
	}
	public List<CloudInstance> getInstancesOfUser(String userID) throws Exception {
		return getInstances(null, userID);
	}
	public List<CloudInstance> getInstances() throws Exception {
		return getInstances(null, null);
	}
	
	public CloudInstance getInstanceByIP(String ip) throws Exception {
		for(CloudInstance i : getInstances()) {
			if(i.getPrivateIP().equals(ip) || i.getPublicIP().equals(ip)) {
				return i;
			}
		}
		return null;
	}
	
	public String getMyIP() {
		String ip = new IOUtil().exec("/sbin/ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'");
		if(ip != null) ip = ip.trim();
		return ip;
	}
	
	public String getIPPrivate(String publicOrPrivateIP) {
		try {
			CloudInstance i = getInstanceByIP(publicOrPrivateIP);
			if(i == null) {
				logger.warn("Instance not found for IP address: " + publicOrPrivateIP);
				return null;
			}
			return i.getPrivateIP();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	public String getIPPublic(String publicOrPrivateIP) {
		try {
			CloudInstance i = getInstanceByIP(publicOrPrivateIP);
			if(i == null) {
				logger.info("Found no Cloud VM Instance with IP: " + publicOrPrivateIP);
				return publicOrPrivateIP;
			}
			return i.getPublicIP();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public String getMyIPPrivate() {
		return getIPPrivate(getMyIP());
	}
	public String getMyIPPublic() {
		return getIPPublic(getMyIP());
	}

	public static synchronized CloudUtil getInstance() {
		if(instance == null) {
			String className = Configuration.getValue(Configuration.PROP_CLOUD_UTIL_CLASS);
			Class<?> clazz;
			try {
				clazz = Class.forName(className);
				instance = (CloudUtil) clazz.getConstructor().newInstance();
			} catch(NoClassDefFoundError e) {
				logger.warn("Unable to instantiate CloudUtil instance; class: " + className + "; error: " + e);
			} catch (Exception e) {
				throw new RuntimeException("Unable to instantiate CloudUtil instance; class: " + className + "; error: " + e);
			} 
		}
		return instance;
	}

}
misc/src/main/java/io/hummer/util/misc/MiscUtil.java
public class MiscUtil {
	
	private static final MiscUtil instance = new MiscUtil();

	public static MiscUtil getInstance() {
		return instance;
	}


	public void sleep(long duration) {
		try {
			Thread.sleep(duration);
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
	}
	public void sleepRandom(long maxDuration) {
		sleepRandom(0, maxDuration);
	}
	public void sleepRandom(long minDuration, long maxDuration) {
		try {
			Thread.sleep(minDuration + (long)(Math.random() * (double)(maxDuration - minDuration)));
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
	}

	public String getCaller() {
		StackTraceElement el = Thread.currentThread().getStackTrace()[3];
		return el.getClassName() + "." + el.getMethodName() + "(...)";
	}
	
}
misc/src/main/java/io/hummer/util/net/NetUtil.java
public class NetUtil {

	private static final NetUtil instance = new NetUtil();

	private static Logger logger = LogUtil.getLogger();

	static final int DEFAULT_PORT = 80;
	static final int DEFAULT_TIMEOUT = 3*1000;

	public boolean isPortOpen(String url) {
		try {
			URL _url = new URL(url);
			return isPortOpen(_url);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	public boolean isPortOpen(URL url) {
		return isPortOpen(url.getHost(), url.getPort());
	}
	public boolean isPortOpen(int port) {
		return isPortOpen("localhost", port);
	}
	/**
	 * attempts to establish a connection to the given host and port,
	 * with default timeout of 3000 milliseconds.
	 * @param host
	 * @param port
	 * @return
	 */
	public boolean isPortOpen(String host, int port) {
		return isPortOpen(host, port, DEFAULT_TIMEOUT, false);
	}
	public boolean isPortOpen(String host, int port, long timeoutMS, boolean requirePingResponse) {
		boolean conn = false;
		try {
			host = host.trim();
			if(isLocalhost(host)) {
				/* try to open a server socket on the given port. */
				try {
					ServerSocket s = new ServerSocket(port);
					conn = false;
					s.close();
				} catch (Exception e) {
					conn = true;
				}
			} else {
				/* try to connect to the given remote host and port. */
				SocketAddress sockaddr = new InetSocketAddress(host, port);
				if(requirePingResponse) {
					if(!ping(host, (int)timeoutMS)) {
						return false;
					}
				}
				Socket s = new Socket();
				s.connect(sockaddr, (int)timeoutMS);
				conn = s.isConnected();
				s.close();
			}
		} catch (Exception e) { /* swallow */ }
		return conn;
	}

	public URL replaceHost(URL url, String newHost) {
		return replaceHost(url.toString(), newHost);
	}
	public URL replaceHost(String url, String newHost) {
		try {
			if(newHost.contains(":")) {
				/* host with port */
				return new URL(url.replaceAll("([^/]*://)[^/]*(/.*)", "$1" + newHost + "$2"));
			} else {
				/* host without port */
				return new URL(url.replaceAll("([^/]*://)[^:]*(:.*)", "$1" + newHost + "$2"));
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public boolean ping(String host) {
		return ping(host, DEFAULT_TIMEOUT);
	}
	public boolean ping(String host, int timeout) {
		try {
			InetAddress a = InetAddress.getByName(host);
			return a.isReachable(timeout);
		} catch (Exception e) {
			logger.info("Unable to perform ping.", e);
			return false;
		}
	}

	public long getDownloadSize(String url) throws MalformedURLException {
		return getDownloadSize(new URL(url));
	}
	public long getDownloadSize(URL url) {
		try {
			List<?> values = url.openConnection().getHeaderFields().get("Content-Length");
			if (values != null && !values.isEmpty()) {
				String sLength = (String) values.get(0);
				System.out.println("Content-Length: " + sLength);
				if (sLength != null) {
					return Long.parseLong(sLength);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			/* swallow */
		}
		return -1;
	}

	public boolean isLocalhost(String host) {
		// TODO improve/extend this method..
		host = host.trim();
		if(host.equalsIgnoreCase("localhost") || host.equals("127.0.0.1") || host.equals("0.0.0.0")) {
			return true;
		}
		return false;
	}
	
	public static NetUtil getInstance() {
		return instance;
	}

	public String getUrlBeforePath(URL u) {
		if(u == null)
			return null;
		String url = u.toExternalForm();
		String out = "";
		out = u.getProtocol() + "://";
		url = url.substring(url.indexOf("://") + "://".length());
		if(!url.contains("/")) {
			out += url;
		} else {
			out += url.substring(0, url.indexOf("/"));
		}
		return out;
	}

}
misc/src/main/java/io/hummer/util/cp/ClasspathUtil.java
public class ClasspathUtil {

	private static final ClasspathUtil instance = new ClasspathUtil();

	/**
	 * reads a system resource, i.e., a file which is available at runtime
	 * either in one of the directories/JARs in the CLASSPATH, or in the directory
	 * from which the JVM is executing.
	 */
	public String getSystemResource(String name) {
		Map<URL,String> res = getSystemResources(name, null, true);
		if(res.isEmpty())
			return null;
		return res.values().iterator().next();
	}
	public Map<URL, String> getSystemResources(String name) {
		return getSystemResources(name, null, false);
	}
	public Map<URL, String> getSystemResources(String name, String urlPattern) {
		return getSystemResources(name, urlPattern, false);
	}
	private Map<URL, String> getSystemResources(String name, String urlPattern, boolean returnFirst) {
		return getSystemResources(name, urlPattern, returnFirst, true);
	}
	public static Map<URL, String> getSystemResources(String name, String urlPattern, boolean returnFirst, boolean dontUseLogger) {
		try {
			if(urlPattern == null)
				urlPattern = ".*";
			Map<URL, String> result = new HashMap<URL, String>();
			Set<URL> urls = new HashSet<URL>();
			urls.addAll(ClasspathHelper.forPackage(""));
			Configuration.fixJavaClasspath(); /* required to avoid bug in reflections lib. */
			urls.addAll(ClasspathHelper.forJavaClassPath());
//			if(!dontUseLogger) {
//				logger.info("Reflection urls: " + urls);
//			}
			Vfs.addDefaultURLTypes(new UrlTypeVFS());
			Reflections reflections = new Reflections(
					new ConfigurationBuilder()
	                .setUrls(urls)
					.setScanners(new ResourcesScanner()));
			if(name.startsWith("/"))
				name = name.substring(1);
			Set<String> files = reflections.getResources(Pattern.compile(name));
			if(files != null && !files.isEmpty()) {
				for(String f : files) {
					for(URL u : doGetSystemResources(f)) {
						//System.out.println("--> " + u);
						if(u.toString().matches(urlPattern)) {
							String content = new String(readBytes(u.openStream()));
							result.put(u, content);
							if(returnFirst)
								return result;
						}
					}
				}
			}
			return result;
		} catch(Exception e) {
			throw new RuntimeException(e);
		}
	}

	private static List<URL> doGetSystemResources(String name) throws IOException {
		List<URL> result = new LinkedList<URL>();
		Enumeration<URL> e = ClassLoader.getSystemResources(name);
		while(e.hasMoreElements()) {
			result.add(e.nextElement());
		}
		return result;
	}

	public static byte[] readBytes(InputStream in) throws Exception {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		int b = 0;
		while((b = in.read()) >= 0)
			bos.write(b);
		in.close();
		bos.close();
		return bos.toByteArray();
	}

	public static synchronized ClasspathUtil getInstance() {
		return instance;
	}

}
misc/src/main/java/io/hummer/util/io/IOUtil.java
public class IOUtil {

	static final Logger logger = LogUtil.getLogger(IOUtil.class);

	/** environment variables used for exec(...) */
	private String[] envp;

	/**
	 * Executes the given command in the host operating system, waits until the 
	 * process has finished, and returns the stdout output produced by the
	 * process.
	 */
	public String exec(String command) {
		return exec(command, true)[0];
	}

	/**
	 * Set an array of environment variables in the form "var=value"
	 * to be used with the exec(...) .
	 */
	public void setEnvironmentVariablesForExec(String ... envp) {
		if(this.envp == null) {
			this.envp = envp;
		} else {
			Set<String> vals = new HashSet<String>(Arrays.asList(this.envp));
			vals.addAll(Arrays.asList(envp));
			this.envp = vals.toArray(new String[0]);
		}
	}

	/**
	 * Executes the given command in the external Runtime, waits until the 
	 * process has finished (if parameter blocking==true), and returns the 
	 * stdout (array index 0) and stderr output (array index 1) produced 
	 * by the process.
	 */
	public String[] exec(String command, boolean blocking) {
		return exec(command, this.envp, true);
	}

	/**
	 * Executes the given command in the external Runtime using the additional
	 * environment variables in the given String array, waits until the 
	 * process has finished (if parameter blocking==true), and returns the 
	 * stdout (array index 0) and stderr output (array index 1) produced 
	 * by the process.
	 */
	public String[] exec(String command, String[] envp, boolean blocking) {
		try {
			Process p = null;
			if(envp != null) {
				p = Runtime.getRuntime().exec(new String[]{"sh", "-c", command});
			} else {
				p = Runtime.getRuntime().exec(new String[]{"sh", "-c", command}, envp);
			}
			String stdout = "", stderr = "";
			if(blocking) {
				p.waitFor();
				stdout = readFile(p.getInputStream());
				stderr = readFile(p.getErrorStream());
			}
			return new String[]{stdout, stderr};
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public boolean isUnixProcessRunning(String command) {
		return !getUnixPIDs(command).isEmpty();
	}
	public List<Integer> getUnixPIDs(String command) {
		List<Integer> result = new LinkedList<Integer>();
		String ps = exec("ps -C '" + command + "'");
		for(String p : ps.split("\\n")) {
			try {
				result.add(Integer.parseInt(p.trim().split("\\s+")[0].trim()));
			} catch (Exception e) {
				/* swallow */
			}
		}
		for(int pid : getUnixPIDs1(command)) {
			if(!result.contains(pid))
				result.add(pid);
		}
		return result;
	}

	private List<Integer> getUnixPIDs1(String command) {
		List<Integer> result = new LinkedList<Integer>();

		if (command.contains("/"))
			command = command.substring(command.lastIndexOf("/") + 1);

		try {
			Process p = Runtime.getRuntime().exec(
					new String[] { "ps", "-A", "-o", "comm,pid", "h" });
			p.waitFor();
			String list = readStream(p.getInputStream());
			String[] lines = list.split("\n");
			for (String s : lines) {
				s = s.replaceAll("\\s+", " ").trim();
				String[] pair = s.split(" ");
				try {
					int pid = Integer.parseInt(pair[1].trim());
					String cmd = pair[0].trim();
					if (cmd.equals(command)) {
						result.add(pid);
					}
				} catch (Exception e) {
					// swallow
				}
			}
			
		} catch (Exception e) {
			logger.info("Unable to determine PIDs of running processes.", e);
		}

		return result;
	}

	public String readURL(String urlString) throws Exception {
		URL url = new URL(urlString);
		return readFile(url.openStream());
	}

	public String readFile(File file) throws Exception {
		return readFile(new FileInputStream(file));
	}

	public String readStream(InputStream in) throws Exception {
		return new String(readBytes(in));
	}

	public String readStream(InputStream in, String encoding) throws Exception {
		return new String(readBytes(in), encoding);
	}

	public String readFile(InputStream in, String encoding) throws Exception {
		return readStream(in, encoding);
	}

	public String readFile(InputStream in) throws Exception {
		return readStream(in);
	}

	public static byte[] readBytes(InputStream in) throws Exception {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		int b = 0;
		while((b = in.read()) >= 0)
			bos.write(b);
		in.close();
		bos.close();
		return bos.toByteArray();
	}

	public String readFile(String url) throws Exception {
		InputStream in = null;
		URL u = null;
		try {
			u = new URL(url);
		} catch(Exception e) {
			u = new File(url).toURI().toURL();
		}
		in = u.openStream();
		return readFile(in);
	}

	public InputStream getInputStream(String fileURI) throws Exception {
		if(fileURI == null)
			return null;
		if(fileURI.matches("[a-z]+://.+")) {
			try {
				URL url = new URL(fileURI);
				return url.openStream();
			} catch(MalformedURLException e) {
				return null;
			}
		}
		return new FileInputStream(fileURI);
	}

	public void saveFile(String fName, String content) throws Exception {
		FileWriter writer = new FileWriter(fName);
		writer.write(content);
		writer.close();
	}

	public void saveFile(String file, byte[] data) throws Exception {
		FileOutputStream fos = new FileOutputStream(file);
		fos.write(data);
		fos.close();
	}

	public List<String> files(String directory) {
		String[] list = new File(directory).list();
		if(list == null) {
			logger.warn("Cannot list files of non-directory path: '" + directory + "'");
			return new LinkedList<String>();
		}
		return Arrays.asList(list);
	}

	public void rm_rf(String dir) {
		try {
			FileUtils.deleteDirectory(new File(dir));
		} catch (IOException e) {
			logger.warn("Unable to delete directory: " + dir, e);
		}
	}

	/**
	 * @param src
	 * @param dst
	 * @return true if file already existed and has been overwritten
	 */
	public boolean cp(String src, String dst) {
		try {
			File dstFile = new File(dst);
			boolean exists = dstFile.exists();
			File srcFile = new File(src);
			if(srcFile.isDirectory()) {
				FileUtils.copyDirectory(srcFile, dstFile);
			} else {
				FileUtils.copyFile(srcFile, dstFile);
			}
			return exists;
		} catch (IOException e) {
			logger.warn("Unable to copy file from '" + src + "' to '" + dst + "'", e);
			throw new RuntimeException(e);
		}
	}

	/**
	 * @param src
	 * @param dst
	 * @return true if file already existed and has been overwritten
	 */
	public boolean mv(String src, String dst) {
		try {
			File dstFile = new File(dst);
			boolean exists = dstFile.exists();
			FileUtils.moveFile(new File(src), dstFile);
			return exists;
		} catch (IOException e) {
			logger.warn("Unable to move file from '" + src + "' to '" + dst + "'", e);
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * Copy the contents of an input stream to an output stream.
	 * @param fileInputStream
	 * @param output
	 * @throws IOException 
	 */
	public void pipe(InputStream in, OutputStream out) throws IOException {
		copy(in,out);
	}
	/**
	 * Copy the contents of an input stream to an output stream.
	 * @param fileInputStream
	 * @param output
	 * @throws IOException 
	 */
	public void copy(InputStream in, OutputStream out) throws IOException {
		IOUtils.copy(in,out);
	}

}
misc/src/main/java/io/hummer/util/misc/ExceptionsUtil.java
public class ExceptionsUtil {
	
	private static final ExceptionsUtil instance = new ExceptionsUtil();

	public static ExceptionsUtil getInstance() {
		return instance;
	}


	private void getAllCauses(Throwable t, List<Throwable> list) {
		if(t == null)
			return;
		list.add(t);
		getAllCauses(t.getCause(), list);
	}
		
	public List<Throwable> getAllCauses(Throwable t) {
		List<Throwable> result = new LinkedList<Throwable>();
		getAllCauses(t, result);
		return result;
	}

	public List<Class<?>> getAllCauseClasses(Throwable t) {
		List<Class<?>> result = new LinkedList<Class<?>>();
		for(Throwable t1 : getAllCauses(t))
			result.add(t1.getClass());
		return result;
	}

	public boolean containsCauseClass(Throwable t, Class<BindException> clazz) {
		return getAllCauseClasses(t).contains(clazz);
	}

	public String getStackTrace(Throwable t) {
		return ExceptionUtils.getStackTrace(t);
	}

}
misc/src/main/java/io/hummer/util/math/MathUtil.java
public class MathUtil {
	
	/** static instance */
	private static final MathUtil instance = new MathUtil();
	/** default significance level */
	public static final double DEFAULT_SIGNIFICANCE_LEVEL = 0.95;
	
	public boolean hasOutlier(Object ... values) {
		return hasOutlier(Arrays.asList(values));
	}
	public boolean hasOutlier(List<?> values) {
		return getOutlier(values) != null;
	}

	/** 
	 * Returns a statistical outlier with the default significance level (0.95),
	 * or null if no such outlier exists..
	 */
	public <T> T getOutlier(List<T> values) {
		return getOutlier(values, DEFAULT_SIGNIFICANCE_LEVEL);
	}
	public <T> T getOutlier(List<T> values, double significanceLevel) {
		AtomicReference<T> outlier = new AtomicReference<T>();
		double grubbs = getGrubbsTestStatistic(values, outlier);
		double size = values.size();
		if(size < 3) {
			return null;
		}
		TDistributionImpl t = new TDistributionImpl(size - 2.0);
		try {
			double criticalValue = t.inverseCumulativeProbability((1.0 - significanceLevel) / (2.0 * size));
			double criticalValueSquare = criticalValue * criticalValue;
			double grubbsCompareValue = ((size - 1) / Math.sqrt(size)) * 
					Math.sqrt((criticalValueSquare) / (size - 2.0 + criticalValueSquare));
			System.out.println("critical value: " + grubbs + " - " + grubbsCompareValue);
			if(grubbs > grubbsCompareValue) {
				return outlier.get();
			} else {
				return null;
			}
		} catch (MathException e) {
			throw new RuntimeException(e);
		}
	}
	/** returns a minimum outlier (if one exists) */
	public <T> T getOutlierMin(List<T> values) {
		T d = getOutlier(values, DEFAULT_SIGNIFICANCE_LEVEL);
		if(d == null)
			return null;
		double d1 = toDouble(d);
		double d2 = toDouble(min(values));
		if(d1 == d2)
			return d;
		return null;
	}
	/** returns a minimum outlier (if one exists) */
	public <T> T getOutlierMax(List<T> values) {
		T d = getOutlier(values, DEFAULT_SIGNIFICANCE_LEVEL);
		if(d == null)
			return null;
		double d1 = toDouble(d);
		double d2 = toDouble(max(values));
		if(d1 == d2)
			return d;
		return null;
	}
	
	public <T> double getGrubbsTestStatistic(List<T> values, AtomicReference<T> outlier) {
		double[] array = toArray(values);
		double mean = StatUtils.mean(array);
		double stddev = stdDev(values);
		double maxDev = 0;
		for(T o : values) {
			double d = toDouble(o);
			if(Math.abs(mean - d) > maxDev) {
				maxDev = Math.abs(mean - d);
				outlier.set(o);
			}
		}
		double grubbs = maxDev / stddev;
		System.out.println("mean/stddev/maxDev/grubbs: " + mean + " - " + stddev + " - " + maxDev + " - " + grubbs);
		return grubbs;
	}

	private static enum Operator {
		MIN, MAX
	}

	public double sum(Collection<?> c) {
		double s = 0;
		for(Object o : c) {
			s += Double.parseDouble("" + o);
		}
		return s;
	}

	public double average(Collection<?> c) {
		return sum(c) / (double) c.size();
	}
	public double avg(Collection<?> c) {
		return average(c);
	}

	public <T> T min(List<T> values) {
		return executeOp(values, Operator.MIN);
	}
	public <T> T max(List<T> values) {
		return executeOp(values, Operator.MAX);
	}
	public double max(double[] values) {
		return executeOp(asList(values), Operator.MAX);
	}
	public int max(int[] values) {
		return executeOp(asList(values), Operator.MAX);
	}
	public long max(long[] values) {
		return executeOp(asList(values), Operator.MAX);
	}

	private <T> T executeOp(List<T> values, Operator op) {
		double res = op == Operator.MIN ? Double.MAX_VALUE : Double.MIN_VALUE;
		T obj = null;
		for(T o : values) {
			double d = toDouble(o);
			if((op == Operator.MIN && d < res) ||
					(op == Operator.MAX && d > res)){
				res = d;
				obj = o;
			}
		}
		return obj;
	}

	public List<Integer> asList(int[] values) {
		List<Integer> result = new LinkedList<Integer>();
		for(int v : values) {
			result.add(v);
		}
		return result;
	}
	public List<Long> asList(long[] values) {
		List<Long> result = new LinkedList<Long>();
		for(long v : values) {
			result.add(v);
		}
		return result;
	}
	public List<Double> asList(double[] values) {
		List<Double> result = new LinkedList<Double>();
		for(double v : values) {
			result.add(v);
		}
		return result;
	}
		
	public Double stdDev(List<?> values) {
		return stdDev(toArray(values));
	}
	public Double stdDev(double[] values) {
		return Math.sqrt(StatUtils.variance(values));
	}
	
	public Double toDouble(Object o) {
		if(o instanceof Double)
			return (Double)o;
		if(o instanceof Integer)
			return (double)(int)(Integer)o;
		if(o instanceof Long)
			return (double)(long)(Long)o;
		return Double.parseDouble("" + o);
	}
	public List<Double> toDoubles(List<?> values) {
		List<Double> d = new LinkedList<Double>();
		for(Object o : values) {
			double val = toDouble(o);
			d.add(val);
		}
		return d;
	}
	public double[] toArray(List<?> values) {
		double[] d = new double[values.size()];
		int count = 0;
		for(Object o : values) {
			double val = o instanceof Double ? (Double)o : Double.parseDouble("" + o);
			d[count++] = val;
		}
		return d;
	}

	public Integer toInteger(String in) {
		if(in == null)
			return null;
		try {
			return Integer.parseInt(in);
		} catch(Exception e) {
			return null;
		}
	}
	
	public static MathUtil getInstance() {
//		System.out.println(Thread.currentThread().toString() + "-" + Thread.currentThread().getId() + " - " +
//				"MathUtil.getInstance()");
		return instance;
	}

	private static void assertion(boolean value) {
		if(!value)
			throw new RuntimeException("Assertion failed.");
	}
	
	public static void main(String[] args) {
		MathUtil m = new MathUtil();

		Integer d0 = m.getOutlier(Arrays.asList(1, 2), 0.95);
		assertion(d0 == null);

		Integer d1 = m.getOutlier(Arrays.asList(1, 2, 3, 8, 4, 10, 20), 0.95);
		assertion(d1 == null);
		
		Integer d2 = m.getOutlier(Arrays.asList(1, 2, 3, 8, 4, 10, 50), 0.95);
		assertion(d2 != null);
		
		Integer d3 = m.getOutlier(Arrays.asList(1, 2, 3, 8, 4, 10, 100), 0.95);
		assertion(d3 != null);
		
		Object d4 = m.getOutlier(Arrays.asList(), 0.95);
		assertion(d4 == null);

		Integer d5 = m.getOutlier(Arrays.asList(1, 2, 3, 8, 4, 10, 100), 0.9999999);
		assertion(d5 == null);

		Integer d6 = m.getOutlier(Arrays.asList(1, 2, 3, 8, 4, 10, 100), 0.999);
		assertion(d6 != null);
		
	}
	
}
misc/src/main/java/io/hummer/util/str/StringUtil.java
public class StringUtil {
	
	private static final StringUtil instance = new StringUtil();

	public List<String> getMatchingLines(String textWithNewlines, String regex) {
		List<String> result = new LinkedList<String>();
		for(String s : textWithNewlines.split("\n")) {
			if(s.matches(regex)) {
				result.add(s);
			}
		}
		return result;
	}

	public List<String> extractFromMatchingLines(
			String textWithNewlines, String regex) {
		return extractFromMatchingLines(textWithNewlines, "(" + regex + ")", 1);
	}
	public List<String> extractFromMatchingLines(
			String textWithNewlines, String regex, int regexGroupID) {
		List<String> result = new LinkedList<String>();
		List<List<String>> tmpResult = extractFromMatchingLines(
				textWithNewlines, regex, new int[]{regexGroupID});
		for(List<String> t : tmpResult) {
			result.add(t.get(0));
		}
		return result;
	}
	public List<List<String>> extractFromMatchingLines(
			String textWithNewlines, String regex, int ... regexGroupIDs) {
		List<List<String>> result = new LinkedList<List<String>>();
		for(String s : textWithNewlines.split("\n")) {
			Pattern p = Pattern.compile(regex);
			Matcher m = p.matcher(s);
			while(m.find()) {
				List<String> tmpResult = new LinkedList<String>();
				result.add(tmpResult);
				for(int regexGroupID : regexGroupIDs) {
					tmpResult.add(m.group(regexGroupID));
				}
			}
		}
		return result;
	}
		
	public static StringUtil getInstance() {
		return instance;
	}

	/**
	 * Concatenate the strings in a collection into a single string,
	 * with another string as delimter. The delimiter string is inserted 
	 * between successive strings; it is not inserted before the first 
	 * string or after the last string in the collection.
	 * @param strings
	 * @param delimiter
	 * @return
	 */
	public String join(Collection<String> strings, String delimiter) {
		StringBuilder b = new StringBuilder();
		List<String> parts = new ArrayList<String>();
		for(String s : strings) {
			parts.add(s);
		}
		for(int i = 0; i < parts.size() - 1; i ++) {
			b.append(parts.get(i));
			b.append(delimiter);
		}
		if(!parts.isEmpty()) {
			b.append(parts.get(parts.size() - 1));
		}
		return b.toString();
	}

	public boolean isEmpty(String in) {
		return in == null || in.trim().isEmpty();
	}
	
	public String getUnicodeCodeForExtendedChars(String s) {
		StringBuilder sb = new StringBuilder();
		for(int i = 0; i < s.length(); i++) {
			char c = s.charAt(i);
			if(c <= 0x7E) {
				sb.append(c);
			} else {
				sb.append(String.format("\\u%04X", (int) c));
			}
		}
		return sb.toString();
	}
	
	public String md5(String password) {
		return DigestUtils.md5Hex(password);
	}
	
	public boolean isMD5(String test) {
		return test.matches("[a-fA-F0-9]{32}");
	}
	
	public String trimForOutput(String str, int maxLength) {
		if(str == null)
			return null;
		if(maxLength <= 0)
			return "";
		if(str.length() <= maxLength)
			return str;
		return str.substring(0, maxLength) + " ... [trimmed " + 
			(str.length() - maxLength) + " chars]";
	}

	public String trim(String value, int maxLength) {
		if(value == null)
			return null;
		if(value.length() <= maxLength)
			return value;
		return value.substring(0, maxLength) + " [...]";
	}

	public List<String> replace(String template, String placeholder, List<?> replacements) {
		List<String> result = new LinkedList<String>();
		for(Object o : replacements) {
			String replacement = "" + o;
			result.add(template.replaceAll(placeholder, replacement));
		}
		return result;
	}
	public <T> String[] replace(String template, String placeholder, T[] replacements) {
		return replace(template, placeholder, Arrays.asList(replacements)).toArray(new String[0]);
	}

	public String format(double value, int decimalDigits) {
		NumberFormat nf = NumberFormat.getInstance();
		nf.setMinimumFractionDigits(decimalDigits);
		nf.setMaximumFractionDigits(decimalDigits);
		nf.setGroupingUsed(false);
		return nf.format(value);
	}

	public String encodeUrl(String urlString) {
		try {
			return URLEncoder.encode(urlString, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
	}

	public String toHexCode(long number) {
		return Long.toHexString(number);
	}
	public String hex(long number) {
		return toHexCode(number);
	}

	public boolean isRelativeURL(String url) {
		return !isAbsoluteURL(url);
	}
	public boolean isAbsoluteURL(String url) {
		try {
			new URL(url);
			return true;
		} catch (Exception e) {
			return false;
		}
	}
	public String concatURLs(String relativeTo, String fileURL) {
		try {
			if(relativeTo == null) {
				return fileURL;
			}
			if(fileURL == null) {
				return relativeTo;
			}
			return new URL(new URL(relativeTo), fileURL).toExternalForm();
		} catch (MalformedURLException e) {
			throw new RuntimeException(e);
		}
	}

	public static interface StringReplacer {

		String replace(String toReplace, Map<Integer,String> regexGroups);

	}

	public String replace(String string, String searchPattern, StringReplacer replacer) {
		return replace(string, searchPattern, replacer, 0);
	}
	public String replace(String string, String searchPattern, 
			StringReplacer replacer, int regexGroup) {
		Pattern pattern = Pattern.compile(searchPattern);
		Matcher matcher = pattern.matcher(string);
		StringBuilder builder = new StringBuilder();
		int i = 0;
		while (matcher.find()) {
			Map<Integer,String> regexGroups = new HashMap<Integer,String>();
			for(int j = 0; j < matcher.groupCount(); j ++) {
				regexGroups.put(j, matcher.group(j));
			}
		    String replacement = replacer.replace(matcher.group(regexGroup), regexGroups);
		    builder.append(string.substring(i, matcher.start()));
		    if (replacement == null)
		        builder.append(matcher.group(0));
		    else
		        builder.append(replacement);
		    i = matcher.end();
		}
		builder.append(string.substring(i, string.length()));
		return builder.toString();
	}

}
misc/src/main/java/io/hummer/util/coll/CollectionsUtil.java
public class CollectionsUtil {
	
	private static final CollectionsUtil instance = new CollectionsUtil();

	public static CollectionsUtil getInstance() {
		return instance;
	}

	public <T1, T2> List<Map<T1, T2>> generateCombinations(
			Map<T1, ? extends Collection<T2>> values) {
		List<Map<T1, T2>> result = new LinkedList<Map<T1, T2>>();
		generateCombinations(new HashMap<T1, Collection<T2>>(values),
				new HashMap<T1, T2>(), result,
				new LinkedList<T1>(values.keySet()));
		return result;
	}

	private <T1, T2> void generateCombinations(
			Map<T1, ? extends Collection<T2>> values, Map<T1, T2> valuesSoFar,
			List<Map<T1, T2>> allResults, List<T1> keyList) {

		if(valuesSoFar.size() >= values.size()) {
			if(!allResults.contains(valuesSoFar)) {
				allResults.add(valuesSoFar);
			}
			return;
		}

		if(keyList.isEmpty())
			return;

		T1 key = keyList.get(0);

		List<T1> keyListCopy = new LinkedList<T1>(keyList);
		keyListCopy.remove(key);

		for(T2 value : values.get(key)) {
			Map<T1, T2> valuesSoFarCopy = new HashMap<T1, T2>(valuesSoFar);
			valuesSoFarCopy.put(key, value);
			generateCombinations(values, valuesSoFarCopy, allResults,
					keyListCopy);
		}
	}

	public <T> List<Set<T>> generateCombinations(Collection<T> values) {
		return generateCombinations(values, 1, values.size());
	}

	public <T> List<Set<T>> generateCombinations(Collection<T> values,
			int combinationLength) {
		return generateCombinations(values, combinationLength,
				combinationLength);
	}

	public <T> List<Set<T>> generateCombinations(Collection<T> values,
			int minCombinationLength, int maxCombinationLength) {
		List<Set<T>> result = new LinkedList<Set<T>>();

		for(int i = minCombinationLength; i <= maxCombinationLength; i++) {
			int combinationLength = i;
			generateCombinations(new LinkedList<T>(values), new HashSet<T>(),
					result, combinationLength);
		}
		return result;
	}

	private <T> void generateCombinations(Collection<T> values,
			Set<T> valuesSoFar, List<Set<T>> allResults, int combinationLength) {

		if(valuesSoFar.size() == combinationLength) {
			if(!allResults.contains(valuesSoFar)) {
				allResults.add(valuesSoFar);
			}
			return;
		}

		for(T value : values) {
			if(!valuesSoFar.contains(value)) {
				Set<T> valuesSoFarCopy = new HashSet<T>(valuesSoFar);
				valuesSoFarCopy.add(value);
				List<T> valuesCopy = new LinkedList<T>(values);
				valuesCopy.remove(value);
				generateCombinations(valuesCopy, valuesSoFarCopy, allResults,
						combinationLength);
			}
		}
	}

	public String[] generateArray(String namePattern, List<?> values) {
		return generateArray(namePattern, "<placeholder>", values);
	}
	public String[] generateArray(String namePattern, String placeholder, List<?> values) {
		List<String> result = new LinkedList<String>();
		for(Object i : values) {
			result.add(namePattern.replace(placeholder, ""+i));
		}
		return result.toArray(new String[0]);
	}

	public List<Integer> createSequence(int end) {
		return createSequence(0, end);
	}
	
	public List<Integer> createSequence(int start, int end) {
		return createSequence(start, end, 1);
	}
	
	public List<Integer> createSequence(int start, int end, int increment) {
		List<Integer> result = new ArrayList<Integer>();
		for(int i = start; i <= end; i += increment)
			result.add(i);
		return result;
	}
	

	private class ObjectComparator implements Comparator<Object> {
		@SuppressWarnings({"unchecked","rawtypes"})
		public int compare(Object o2, Object o1) {

			if(o1 instanceof AtomicInteger)
				o1 = ((AtomicInteger) o1).get();
			if(o2 instanceof AtomicInteger)
				o2 = ((AtomicInteger) o2).get();
			if(o1 instanceof AtomicLong)
				o1 = ((AtomicLong) o1).get();
			if(o2 instanceof AtomicLong)
				o2 = ((AtomicLong) o2).get();

			if((o1 instanceof Comparable<?>) && (o2 instanceof Comparable<?>)) {
				return ((Comparable) o1).compareTo(o1);
			}
			if((o1 instanceof Comparable<?>) && (o2 instanceof Comparable<?>)) {
				Number number1 = (Number) o1;
				Number number2 = (Number) o2;
				if(((Object) number2).getClass().equals(
						((Object) number1).getClass())) {
					if(number1 instanceof Comparable) {
						return ((Comparable) number1).compareTo(number2);
					}
				}
				if(Math.abs(number1.doubleValue() - number2.doubleValue()) < 0.0000001) // small
																						// threshold
					return 0;
				if(number1.doubleValue() < number2.doubleValue())
					return -1;
				if(number1.doubleValue() > number2.doubleValue())
					return 1;
			}
			throw new IllegalArgumentException(
					"Not sure how to compare objects of the following types: "
							+ o1.getClass() + " - " + o2.getClass());
		}
	}

	public void removeKeyWithSmallestValue(Map<?, ?> map) {
		if(map.size() <= 0)
			return;
		Object minKey = map.keySet().iterator().next();
		Object minValue = map.get(minKey);
		ObjectComparator c = new ObjectComparator();
		for(Object k : new HashSet<Object>(map.keySet())) {
			if(c.compare(map.get(k), minValue) < 0) {
				minValue = map.get(k);
				minKey = k;
			}
		}
		map.remove(minKey);
	}

	public List<?> flattenValues(Object values) {
		if(values instanceof Map<?,?>) 
			return flattenValues((Map<?,?>)values);
		else if(values instanceof List<?>) 
			return flattenValues((List<?>)values);
		return new LinkedList<Object>(Arrays.asList(values));
	}
	public List<?> flattenValues(Map<?,?> values) {
		List<Object> result = new LinkedList<Object>();
		for(Object o : values.values()) {
			result.addAll(flattenValues(o));
		}
		return result;
	}
	public List<?> flattenValues(List<?> values) {
		List<Object> result = new LinkedList<Object>();
		for(Object o : values) {
			result.addAll(flattenValues(o));
		}
		return result;
	}

	@SuppressWarnings("unchecked")
	public <T extends Number> List<T> sort(List<T> in) {
		Object[] copy = in.toArray();
		Arrays.sort(copy);
		List<T> result = new LinkedList<T>();
		for(Object o : copy) {
			result.add((T) o);
		}
		return result;
	}

	public List<String> toStringList(List<?> list) {
		List<String> result = new LinkedList<String>();
		for(Object o : list) {
			result.add("" + o);
		}
		return result;
	}

	@SuppressWarnings("all")
	public <T> Set<T> union(Set<T>... sets) {
		Set<T> result = new HashSet<T>();
		for(Set<T> s : sets)
			result.addAll(s);
		return result;
	}

	public <T> boolean inRange(T[] array, int index) {
		return index > 0 && index < array.length;
	}

	public <K, V> MapBuilder<K, V> asMap(K key, V value) {
	    return new MapBuilder<K, V>().entry(key, value);
	}
	
	public static class MapBuilder<K, V> extends HashMap<K, V> {
		private static final long serialVersionUID = 1L;

		public MapBuilder() { }
		public MapBuilder(K key, V value) {
			entry(key, value);
		}
		public MapBuilder<K, V> entry(K key, V value) {
	        this.put(key, value);
	        return this;
	    }
		public static <K,V> MapBuilder<K,V> map(K key, V value) {
			return new MapBuilder<K, V>(key, value);
		}
	}

	/**
	 * Shift the entries of an array by a fixed number of positions to
	 * the right (positive) or to the left (negative). Drops any entries that .
	 * @param array the array to modify
	 * @param numPositions positive or negative number of index positions
	 */
	public <T> void shift(T[] array, int numPositions) {
		if(numPositions > 0) {
			System.arraycopy(array, 0, array, numPositions, array.length-numPositions);
//			for(int i = array.length - 1; i >= numPositions; i --) {
//				if(inRange(array, i)) {
//					if(inRange(array, i - numPositions)) {
//						array[i] = array[i - numPositions];
//					}
//					//if(i < numPositions)
//					//	array[i] = null;
//				}
//			}
//			for(int i = 0; i < numPositions; i ++) {
//				array[i] = null;
//			}
//			for(int i = array.length - numPositions - 1; i >= 0; i --) {
//				if(inRange(array, i)) {
//					if(inRange(array, i + numPositions)) {
//						array[i + numPositions] = array[i];
//					}
//					if(i < numPositions)
//						array[i] = null;
//				}
//			}
		} else if(numPositions < 0) {
			for(int i = numPositions; i <= array.length; i ++) {
				if(inRange(array, i)) {
					if(inRange(array, i - numPositions)) {
						array[i - numPositions] = array[i];
					}
					if(i >= array.length - numPositions)
						array[i] = null;
				}
			}
		}
	}
	
	public <T> T[] concat(T item, T[] items) {
		items = Arrays.copyOf(items, items.length + 1);
		shift(items, 1);
		items[0] = item;
		return items;
	}
	public <T> T[] concat(T[] items, T item) {
		return append(items, item);
	}
	public <T> T[] append(T[] items, T item) {
		items = Arrays.copyOf(items, items.length + 1);
		items[items.length - 1] = item;
		return items;
	}

	public <T> T getRandom(Collection<T> items) {
		if(items == null || items.isEmpty())
			return null;
		List<T> list = null;
		if(!(items instanceof List<?>)) {
			list = new LinkedList<T>(items);
		} else {
			list = (List<T>)items;
		}
		int index = (int)((double)list.size() * Math.random());
		return list.get(index);
	}

	public String join(List<?> list) {
		return join(list, "\n");
	}
	public String join(List<?> list, String delimiter) {
		StringBuilder b = new StringBuilder();
		int counter = 0;
		for(Object o : list) {
			b.append("" + o);
			if(++counter < list.size()) {
				b.append(delimiter);
			}
		}
		return b.toString();
	}
}


Question: package io.hummer.util;
import org.apache.log4j.Logger;
import io.hummer.util.cloud.CloudUtil;
import io.hummer.util.coll.CollectionsUtil;
import io.hummer.util.cp.ClasspathUtil;
import io.hummer.util.io.IOUtil;
import io.hummer.util.log.LogUtil;
import io.hummer.util.math.MathUtil;
import io.hummer.util.misc.ExceptionsUtil;
import io.hummer.util.misc.MiscUtil;
import io.hummer.util.net.NetUtil;
import io.hummer.util.str.StringUtil;
import io.hummer.util.time.TimeUtil;



/**
 * Util aggregator with references to sub-utils
 * @author hummer
 */
public class Util {

	private static final Util instance = new Util();

Answer: 	public final IOUtil io = new IOUtil();