package oneLiners;

import jafama.FastMath;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/** Java routines to do various simple tasks.
 * To be called in a single short line only.
 * 
 * The principal are:
 * 1) Someone else should be able to replace/rewrite the routine exactly without any information other than the routine's name (no JavaDoc or anything)
 *  	and it shouldn't take them more than a few minutes at the very most.
 * 2) Write them as you need them, don't try to make it general or make the float[] version and the double[] version etc just for the point of it.
 * 3) Don't worry about them existing elsewhere or trying to find if already exist in here, just write it and carry on.
 * 		(However if you see the same thing in here under different names, feel free to make one call the other and make it with [at]deprecate) 
 *  
 * @author oliford <codes(at)oliford.co.uk>
 * @author everyone-else
 *
 */
public class OneLiners {
	/** Finds the index into xs[] nearest x where xs[] < x (integers)
	 * @params xs Array of values
	 * @param x Single value 
	 */	
	public final static int getNearestLowerIndex(int xs[], int x){	
		int k,klo,khi;
		klo = 0;		
		khi = xs.length - 1;
		if(x <= xs[0])return 0;
		if(x >= xs[khi])return khi;
		while( khi - klo > 1){
			k = (khi + klo) / 2;
			if( x < xs[k])
				khi = k;
			else
				klo = k;			
		}		
		return klo;
	}
	
	/** Determines the index below x, first assuming xs is regularly spaced and then with a bisection search if not */
	public final static int getNearestLowerIndexProbablyRegular(double xs[], double x){
		if(x <= xs[0])return 0;
		if(x >= xs[xs.length-1])return xs.length-1;
		
		double dx = xs[1] - xs[0];		
		int i = (int)((x - xs[0]) / dx);
		if(i >= 0 && i <= (xs.length-2) && (xs[i] <= x && xs[i+1] > x))
			return i;
		else return getNearestLowerIndex(xs, x);
	}
		
	/** Finds the index into xs[] nearest x where xs[] < x (doubles)
	 * @params xs Array of values
	 * @param x Single value 
	 */	
	public final static int getNearestLowerIndex(double xs[], double x){	
		int k,klo,khi;
		klo = 0;		
		khi = xs.length - 1;
		if(x <= xs[0])return 0;
		if(x >= xs[khi])return khi;
		while( khi - klo > 1){
			k = (khi + klo) / 2;
			if( x < xs[k])
				khi = k;
			else
				klo = k;			
		}		
		return klo;
	}
	
	/** Finds the index into xs[] nearest x (doubles)
	 * @params xs Array of values
	 * @param x Single value 
	 */	
	public final static int getNearestIndex(double xs[], double x){	
		int k,klo,khi;
		klo = 0;		
		khi = xs.length - 1;
		if(x <= xs[0])return 0;
		if(x >= xs[khi])return khi;
		while( khi - klo > 1){
			k = (khi + klo) / 2;
			if( x < xs[k])
				khi = k;
			else
				klo = k;			
		}		
		if( (x - xs[klo]) < (xs[khi] - xs[klo])/2)
			return klo;		
		else
			return khi;
	}
	
	/** Finds the index into xs[] nearest x (floats)
	 * @params xs Array of values
	 * @param x Single value 
	 */	
	public final static int getNearestIndex(float xs[], float x){	
		int k,klo,khi;
		klo = 0;		
		khi = xs.length - 1;
		if(x <= xs[0])return 0;
		if(x >= xs[khi])return khi;
		while( khi - klo > 1){
			k = (khi + klo) / 2;
			if( x < xs[k])
				khi = k;
			else
				klo = k;			
		}		
		if( (x - xs[klo]) < (xs[khi] - xs[klo])/2)
			return klo;		
		else
			return khi;
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(double a[][], String fileName){
		makePath(fileName);
		try {
			PrintWriter out = new PrintWriter(fileName);		
			dumpArray(a, out);		
			out.close();
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}
	
	public final static void dumpArray(int a[][], String fileName){
		makePath(fileName);
		try {
			PrintWriter out = new PrintWriter(fileName);		
			dumpArray(a, out);		
			out.close();
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(double a[], String fileName){
		makePath(fileName);
		try {
			PrintWriter out = new PrintWriter(fileName);
			dumpArray(a, out);	
			out.close();
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}
	
	public final static void dumpArray(int a[], String fileName){
		makePath(fileName);
		try {
			PrintWriter out = new PrintWriter(fileName);
			dumpArray(a, out);	
			out.close();
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}
	
	
	/** does what is says on the tin */
	public final static void dumpArray(double a[][]){
		dumpArray(a, new PrintWriter(System.out, true));	
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(int a[][]){
		dumpArray(a, new PrintWriter(System.out, true));	
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(double a[]){
		dumpArray(a, new PrintWriter(System.out, true));
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(Double a[]){
		dumpArray(a, new PrintWriter(System.out, true));
	}
	

	/** does what is says on the tin */
	public final static void dumpArray(float a[]){
		dumpArray(a, new PrintWriter(System.out, true));
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(int a[]){
		dumpArray(a, new PrintWriter(System.out, true));
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(boolean a[]){
		dumpArray(a, new PrintWriter(System.out, true));
	}

	/** does what is says on the tin */
	public final static void dumpArray(String a[]){
		dumpArray(a, new PrintWriter(System.out, true));
	}

	/** does what is says on the tin */
	public final static void dumpArray(byte a[]){
		dumpArray(a, new PrintWriter(System.out, true));
	}

	/** does what is says on the tin */
	public final static void dumpArray(double a[][], PrintWriter out){
		for(int i=0;i<a.length;i++)
			dumpArray(a[i], out);
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(int a[][], PrintWriter out){
		for(int i=0;i<a.length;i++)
			dumpArray(a[i], out);
	}
	
	
	/** does what is says on the tin */
	public final static void dumpArray(double a[], PrintWriter out){
		out.print(a[0]);
		for(int i=1;i<a.length;i++)
			out.print("\t"+a[i]);				
		
		out.println("");		
	}

	/** does what is says on the tin */
	public final static void dumpArray(Double a[], PrintWriter out){
		out.print(a[0]);
		for(int i=1;i<a.length;i++)
			out.print("\t"+a[i]);				
		
		out.println("");		
	}

	/** does what is says on the tin */
	public final static void dumpArray(float a[], PrintWriter out){
		out.print(a[0]);
		for(int i=1;i<a.length;i++)
			out.print("\t"+a[i]);				
		
		out.println("");		
	}

	/** does what is says on the tin */
	public final static void dumpArray(int a[], PrintWriter out){
		out.print(a[0]);
		for(int i=1;i<a.length;i++)
			out.print("\t"+a[i]);				
		
		out.println("");		
	}

	/** does what is says on the tin */
	public final static void dumpArray(boolean a[], PrintWriter out){
		out.print(a[0]);
		for(int i=1;i<a.length;i++)
			out.print("\t"+a[i]);				
		
		out.println("");		
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(String a[], PrintWriter out){
		out.print(a[0]);
		for(int i=1;i<a.length;i++)
			out.print("\t"+a[i]);				
		
		out.println("");		
	}

	/** does what is says on the tin */
	public final static void dumpArray(byte a[], PrintWriter out){
		out.print(a[0]);
		for(int i=1;i<a.length;i++)
			out.print("\t"+a[i]);				
		
		out.println("");		
	}
	
	/** 
	 * Dumps an array in what way? 
	 **/
	public final static void dumpArray(double a[], int n, int m, PrintWriter out){
		for (int i=0; i<m; i++)
			out.print("\t");
		out.print(a[0]);
		for(int i=1;i<a.length;i++) {
			if ((i)%n!=0)
				out.print("\t");
			else
				for (int j=0; j<m; j++)
					out.print("\t");
			out.print(a[i]);
			if ((i+1)%n==0)
				out.print("\n");
		}
		out.println("");		
	}

	/** 
	 * Dumps an array in what way? 
	 **/
	public final static void dumpArray(double a[], int n, int m, String fileName){
		makePath(fileName);
		try {
			PrintWriter out = new PrintWriter(fileName);
			dumpArray(a, n, m, out);	
			out.close();
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}

	
	public final static double[][] transpose(double dIn[][]){
		int i,j,ni,nj;
		ni = dIn.length;
		if(ni <= 0)return new double[0][0];
		nj = dIn[0].length;
		double dOut[][] = new double[nj][ni];
		for(i=0;i<ni;i++)
			for(j=0;j<nj;j++)
				dOut[j][i]=dIn[i][j];
		
		return dOut;
		
	}
	
	public final static int[][] transpose(int dIn[][]){
		int i,j,ni,nj;
		ni = dIn.length;
		if(ni <= 0)return new int[0][0];
		nj = dIn[0].length;
		int dOut[][] = new int[nj][ni];
		for(i=0;i<ni;i++)
			for(j=0;j<nj;j++)
				dOut[j][i]=dIn[i][j];
		
		return dOut;
		
	}
	
	public final static double[] getColumn(double mat[][], int idx){
		int n = mat.length;
		double ret[] = new double[n];
		for(int i=0; i < n; i++)
			ret[i] = mat[i][idx];
		return ret;
	}
		
	
	public final static float[][] transpose(float dIn[][]){
		int i,j,ni,nj;
		ni = dIn.length;
		if(ni <= 0)return new float[0][0];
		nj = dIn[0].length;
		float dOut[][] = new float[nj][ni];
		for(i=0;i<ni;i++)
			for(j=0;j<nj;j++)
				dOut[j][i]=dIn[i][j];
		
		return dOut;		
	}
	
	/**
	 * Returns the diagonal elements of the given square matrix.
	 * @param dIn 
	 * @return
	 */
	public final static double[] diag(double dIn[][]) {
		if (dIn.length != dIn[0].length) {
			throw new RuntimeException("Matrix must be square: "+dIn.length+" != "+dIn[0].length);
		}
		double[] ret = new double[dIn.length];
		for(int i=0;i<ret.length;++i) {
			ret[i] = dIn[i][i];
		}
		
		return ret;
	}
	
	public final static void makeDir(String dirName) {
		makePath(dirName+"/dummy");
	}
	
	/** Makes the dirs in the path ready for the given file */
	public final static void makePath(String fileName){
		//build dir up to and not including file name
		String bits[] = fileName.split("\\/");
		if(bits.length <= 1)return; //file into current dir, ignore
		
		StringBuffer dir = new StringBuffer("");
		for(int i=0;i<bits.length-1;i++){
			if(i > 0 || fileName.startsWith("/"))
				dir.append("/");
			dir.append(bits[i]);
		}
		
		File dirDesc = new File(dir.toString());
		if(dirDesc.exists()){
			if(!dirDesc.isDirectory())
				throw new RuntimeException("Cannot create directory '" + dir + "' because it already exists but is not a directory.");
				
			return; //already OK
		}
		
		//try to make it
		if(!dirDesc.mkdirs())
			throw new RuntimeException("Directory '" + dir + "' does not exist and we cannot create it.");
	}
	
	 /** Deletes all files and subdirectories under dir.
	     Returns true if all deletions were successful.
	     If a deletion fails, the method stops attempting to delete and returns false. */
	public final static boolean recursiveDelete(String path){
	   File dir = new File(path);
	    if (dir.isDirectory()) {
	        String[] children = dir.list();
	        for (int i=0; i<children.length; i++) {
	            boolean success = recursiveDelete(path+"/"+children[i]);
	            if (!success) {
	                return false;
	            }
	        }
	    }

	    // The directory is now empty so delete it
	    return dir.delete();
	    
	}
	
	public final static boolean[] doubleToBoolean(double[] a) {
		boolean[] ret = new boolean[a.length];
		for(int i=0;i<ret.length;++i) {
			if (a[i] > 0.5) ret[i] = true;
		}
		
		return ret;
	}
	
	public final static double[][] intToDouble(int a[][]){
		int n=a.length;
		int m=a[0].length;
		double b[][] = new double[n][m];
		
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
				b[i][j] = a[i][j];
		
		return b;
	}
	
	public final static int[][] doubleToInt(double a[][]){
		int n=a.length;
		int m=a[0].length;
		int b[][] = new int[n][m];
		
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
				b[i][j] = (int)a[i][j];
		
		return b;
	}
	
	public final static double[] intToDouble(int a[]){
		int n=a.length;
		double b[] = new double[n];
		
		for(int i=0;i<n;i++)
				b[i] = a[i];
		
		return b;
	}
	
	public final static int[] doubleToInt(double a[]){
		int n=a.length;
		int b[] = new int[n];
		
		for(int i=0;i<n;i++)
				b[i] = (int)a[i];
		
		return b;
	}
	
	public final static void TextToFile(String fileName, String text){
		OneLiners.makePath(fileName);
		
		try{
			FileOutputStream fOut = new FileOutputStream(fileName);
			fOut.write(text.getBytes());
			fOut.close();
		}catch(IOException err){
			throw new RuntimeException(err);
		}
	}
	
	/**
	 * From http://www.javapractices.com/topic/TopicAction.do?Id=42
	 */
	public final static String fileToText(String fileName) {
		FileReader fileReader = null;
		try {
			fileReader = new FileReader(new File(fileName));
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		
		return fileToText(fileReader);
	}
	
	public final static String urlToText(String urlString) {
		URL url = null;
		try {
			url = new URL(urlString);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
		
		String text = null;
		try {
	        BufferedReader in = new BufferedReader(
	                                new InputStreamReader(
	                                url.openStream()));
	        text = fileToText(in);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
		return text;
	}
	
	
	/**
	 * From http://www.javapractices.com/topic/TopicAction.do?Id=42
	 */
	public static String fileToText(Reader reader) {
	    StringBuilder contents = new StringBuilder();
	    
	    try {
	      //use buffering, reading one line at a time
	      //FileReader always assumes default encoding is OK!
	      BufferedReader input =  new BufferedReader(reader);
	      try {
	        String line = null; //not declared within while loop
	        /*
	        * readLine is a bit quirky :
	        * it returns the content of a line MINUS the newline.
	        * it returns null only for the END of the stream.
	        * it returns an empty String if two newlines appear in a row.
	        */
	        while (( line = input.readLine()) != null){
	          contents.append(line);
	          contents.append(System.getProperty("line.separator"));
	        }
	      }
	      finally {
	        input.close();
	      }
	    }
	    catch (IOException ex){ 
	      ex.printStackTrace();  
	      return null; //This needs to tell the caller something went wrong
	    }
	    
	    return contents.toString();		
	}
	
	/**
	 * Converts an input stream into a string.
	 * Taken from http://stackoverflow.com/questions/309424/in-java-how-do-i-read-convert-an-inputstream-to-a-string
	 *  
	 * @param is The input stream.
	 * @param charsetName The character encoding, for example "UTF-8"
	 * @return A string with the content of the input stream.
	 */
	public static String streamToText(InputStream is, String charsetName) throws IOException {
		final char[] buffer = new char[0x10000];
		StringBuilder out = new StringBuilder();
		Reader in = new InputStreamReader(is, charsetName);
		int read;
		do {
		  read = in.read(buffer, 0, buffer.length);
		  if (read>0) {
		    out.append(buffer, 0, read);
		  }
		} while (read>=0);	
		
		return out.toString();
	}
	
	/**
	 * Converts an input stream into a string using default character set UTF-8.
	 *  
	 * @param is The input stream.
	 * @param encoding The character encoding, for example "UTF-8"
	 * @return A string with the content of the input stream.
	 */
	public static String streamToText(InputStream is) throws IOException {
		return streamToText(is, "UTF-8");
	}
	
	public final static String[] linesFromFile(String fileName) {
	    //...checks on aFile are elided
		File aFile = new File(fileName);
	    ArrayList <String>lines = new ArrayList <String>();
	    
	    try {
	      //use buffering, reading one line at a time
	      //FileReader always assumes default encoding is OK!
	      BufferedReader input =  new BufferedReader(new FileReader(aFile));
	      try {
	        String line = null; //not declared within while loop
	        /*
	        * readLine is a bit quirky :
	        * it returns the content of a line MINUS the newline.
	        * it returns null only for the END of the stream.
	        * it returns an empty String if two newlines appear in a row.
	        */
	        while (( line = input.readLine()) != null){
	        	lines.add(line);	          
	        }
	      }
	      finally {
	        input.close();
	      }
	    }
	    catch (IOException ex){
	      ex.printStackTrace();
	      return null;
	    }
	    
	    //return (String[])lines.toArray();
	    String lineArr[] = new String[lines.size()];
	    for(int i=0; i < lines.size(); i++)
	    	lineArr[i] = lines.get(i);
	    
	    return lineArr;
	}
	
	/** @return double[min/max][col] = min/max(f[*][col]) */
	public final static double[][] columnRanges(double f[][]){	
		double ret[][] = new double[2][f[0].length];

		for(int j=0; j < f[0].length; j++){
			ret[0][j] = Double.POSITIVE_INFINITY;
			ret[1][j] = Double.NEGATIVE_INFINITY;
			for(int i=0; i < f.length; i++){
				if( f[i][j] < ret[0][j] )
					ret[0][j] = f[i][j];
				if( f[i][j] > ret[1][j] )
					ret[1][j] = f[i][j];
			}        	
		}
		return ret;
	}
	
	public final static double[] getRange(double f[][]){	
		double minF = Double.POSITIVE_INFINITY;
		double maxF = Double.NEGATIVE_INFINITY;
		for(int i=0; i < f.length; i++)
	        for(int j=0; j < f[i].length; j++){
	        	if( f[i][j] > maxF )
	        		maxF = f[i][j];
	        	if( f[i][j] < minF )
	        		minF = f[i][j];
	        }        	
        return new double[]{ minF, maxF };
	}
	
	public final static double[] getRange(double f[]){		
		double minF = Double.POSITIVE_INFINITY;
		double maxF = Double.NEGATIVE_INFINITY;
        for(int i=0; i < f.length; i++){
        	if( f[i] > maxF )
        		maxF = f[i];
        	if( f[i] < minF )
        		minF = f[i];
        }        	
        return new double[]{ minF, maxF };
	}
	
	public final static int min(int f[]){		
		int minF = Integer.MAX_VALUE;
		  for(int i=0; i < f.length; i++){
        	if( f[i] < minF )
        		minF = f[i];
        }        	
        return minF;
	}
	
	public final static int max(int f[]){		
		int maxF = Integer.MIN_VALUE;
        for(int i=0; i < f.length; i++){
        	if( f[i] > maxF )
        		maxF = f[i];
        }        	
        return maxF;
	}
	
	public final static double min(double f[]){		
		double minF = Double.POSITIVE_INFINITY;
		  for(int i=0; i < f.length; i++){
        	if( f[i] < minF )
        		minF = f[i];
        }        	
        return minF;
	}
	
	public final static double max(double f[]){		
		double maxF = Double.NEGATIVE_INFINITY;
        for(int i=0; i < f.length; i++){
        	if( f[i] > maxF )
        		maxF = f[i];
        }        	
        return maxF;
	}
	
	public final static double[] linSpace(double x0, double x1, int n){
		if(n == 1) return new double[]{ (x0+x1)/2 };
        double f[] = new double[n];
        double dx = (x1 - x0)/(double)(n - 1.0);
        for(int i=0; i<n; i++)
            f[i] = x0 + i*dx;
        return f;
	}
	
	public final static double[] linSpace(double x0, double x1, double dx){
		int n = (int)((x1 - x0)/dx + 1.0);		
        double f[] = new double[n];
        
        for(int i=0; i<n; i++)
            f[i] = x0 + i*dx;
        return f;
	}

	public final static float[] linSpaceFloat(float x0, float x1, int n){
		if(n == 1) return new float[]{ (x0+x1)/2 };
        float f[] = new float[n];
		float dx = (x1 - x0)/(float)(n - 1.0);
        for(int i=0; i<n; i++)
            f[i] = x0 + i*dx;
        return f;
	}
	
	public final static float[] linSpaceFloat(float x0, float x1, float dx){
		int n = (int)((x1 - x0)/dx + 1.0);		
		float f[] = new float[n];
        
        for(int i=0; i<n; i++)
            f[i] = x0 + i*dx;
        return f;
	}

	/** Copies 2D arrays with rectangular shapes. For 1D arrays use the java Arrays class instead. */
	public final static double[][] copyArray(double[][] a) {
		int nr = a.length, nc = a[0].length;
		double[][] ret = new double[nr][nc];
		for(int i=0;i<nr;++i) {
			for(int j=0;j<nc;++j) {
				ret[i][j] = a[i][j];
			}
		}
		
		return ret;
	}
	
	/**
	 * Applies the given operator from the Math class to all elements
	 * in the given array. Slow but sometimes convenient.
	 * 
	 * Special operators: "+", "-", "*", "/" for the corresponding operations
	 * between two arrays.
	 * 
	 * @param op A Math method name, for example "sqrt"
	 * @param x An array with doubles.
	 * @param args Extra arguments for the operation.
	 * 
	 * @return An array with the given operation performed on each element in the original array.
	 */
	public final static double[] arrayOp(String op, double[] x, Object...args) {
		double[] ret = new double[x.length];
		
		if (op.equals("+")) {
			double[] y = (double[]) args[0];
			for(int i=0;i<ret.length;++i) {
				ret[i] = x[i]+y[i];
			}
			return ret;
		} else if (op.equals("-")) {
			double[] y = (double[]) args[0];
			for(int i=0;i<ret.length;++i) {
				ret[i] = x[i]-y[i];
			}
			return ret;			
		} else if (op.equals("*")) {
			double[] y = (double[]) args[0];
			for(int i=0;i<ret.length;++i) {
				ret[i] = x[i]*y[i];
			}
			return ret;			
		} else if (op.equals("/")) {
			double[] y = (double[]) args[0];
			for(int i=0;i<ret.length;++i) {
				ret[i] = x[i]/y[i];
			}
			return ret;
		}
		
		Method method = null;
		try {
			Class<?>[] argTypes = new Class<?>[1+args.length];
			argTypes[0] = double.class;
			for(int i=1;i<argTypes.length;++i) {
				argTypes[i] = args[i-1].getClass();
			}
			method = Math.class.getDeclaredMethod(op, argTypes);
			for(int i=0;i<ret.length;++i) {
				ret[i] = (Double) method.invoke(null, x[i]);
			}	
		} catch (Exception ex) { 			
			throw new RuntimeException("Field "+op+" with double argument does not exist in Math class.");
		}
					
		return ret;
	}
	
	/** Multiplies all the elements of the given array by the given scalar */
	public final static double[] arrayMultiply(double x[], double c){
		double ret[] = new double[x.length];
		for(int i=0; i<x.length; i++)
			ret[i] = x[i] * c;
		return ret;
	}
	
	/** Multiplies all the elements of the given array by the given scalar */
	public final static double[][] arrayMultiply(double x[][], double c){
		double ret[][] = new double[x.length][x[0].length];
		for(int i=0; i<x.length; i++)
			for(int j=0; j<x[i].length; j++)
				ret[i][j] = x[i][j] * c;
		return ret;
	}
	
	/**
	 * Allocates and fills a double array with a specified value.
	 * @param value The value for each element in the array.
	 * @param n The array size.
	 * @return The allocated array.
	 */
	public final static double[] fillArray(double value, int n) {
		double[] ret = new double[n];
		for(int i=0;i<n;++i) {
			ret[i] = value;
		}
		return ret;
	}
	
	/**
	 * Takes the specified subsection of the given array an puts it in a new array of length n
	 * @param value The array to take n elements from 
	 * @param n The array size.
	 * @return The allocated array.
	 */
	public final static double[] subArray(double in[], int i0, int n) {
		double[] ret = new double[n];
		for(int i=0;i<n;++i) {
			ret[i] = in[i0 + i];			
		}
		return ret;
	}


	/**
	 * Allocates and fills a float array with a specified value.
	 * @param value The value for each element in the array.
	 * @param n The array size.
	 * @return The allocated array.
	 */
	public final static float[] fillFloatArray(float value, int n) {
		float[] ret = new float[n];
		for(int i=0;i<n;++i) {
			ret[i] = value;
		}
		return ret;
	}
	
	/**
	 * Allocates and fills an int array with a specified value.
	 * @param value The value for each element in the array.
	 * @param n The array size.
	 * @return The allocated array.
	 */
	public final static int[] fillIntArray(int value, int n) {
		int[] ret = new int[n];
		for(int i=0;i<n;++i) {
			ret[i] = value;
		}
		return ret;
	}
	
	/** Flatten a 2D double array to 1D. Data returned is stored row by row data from 'mat'. */
	public final static double[] flatten(double mat[][]){
			int n = mat.length;
			int m = mat[0].length;
			double flatMat[] = new double[n*m];
			for(int i=0; i < n; i++)
				System.arraycopy(mat[i], 0, flatMat, i*m, m);
			return flatMat;
	}
	
	/** Unflattens a 1D double array to 2D. 
	 * @param flatMat	The matrix data, stored row by row
	 * @param n	Number of rows (shallowest dimension)
	 * @param m Number of columns (deepest dimension / fastest changing index)
	 * @return mat[n][m]
	 */
	public final static double[][] unflatten(double flatMat[], int n, int m){
		double mat[][] = new double[n][m];
		for(int i=0; i < n; i++)
			System.arraycopy(flatMat, i*m, mat[i], 0, m);
		return mat;
	}
	
	/** Unflattens a 1D int array to 2D. 
	 * @param flatMat	The matrix data, stored row by row
	 * @param n	Number of rows (shallowest dimension)
	 * @param m Number of columns (deepest dimension)
	 * @return mat[n][m]
	 */
	public final static int[][] unflatten(int flatMat[], int n, int m){
		int mat[][] = new int[n][m];
		for(int i=0; i < n; i++)
			System.arraycopy(flatMat, i*m, mat[i], 0, m);
		return mat;
	}
	
	/** Appends arrayTwo onto the end of arrayOne
	 * @param arrayOne - array to be extended by adding arrayTwo to its end
	 * @param arrayTwo - the array concatenated onto the end of arrayOne
	 * @return the concatenated array
	 */
	public final static int[] appendArray(int[] arrayOne, int[] arrayTwo) {
		if (arrayOne == null)
			arrayOne = new int[0];
		
		int n = arrayOne.length;
		int m = arrayTwo.length;
		int[] ans = new int[m+n];
		System.arraycopy(arrayOne, 0, ans, 0, n);
		System.arraycopy(arrayTwo, 0, ans, n, m);
		
		return ans;
	}
	
	/** Appends arrayTwo onto the end of arrayOne
	 * @param arrayOne - array to be extended by adding arrayTwo to its end
	 * @param arrayTwo - the array concatenated onto the end of arrayOne
	 * @return the concatenated array
	 */
	public final static double[][] appendArray(double[][] arrayOne, double[][] arrayTwo) {
		if (arrayOne == null)
			arrayOne = new double[0][0];
		
		int n = arrayOne.length;
		int m = arrayTwo.length;
		double[][] ans = new double[m+n][];
		System.arraycopy(arrayOne, 0, ans, 0, n);
		System.arraycopy(arrayTwo, 0, ans, n, m);
		
		return ans;
	}

	
	/** Appends arrayTwo onto the end of arrayOne
	 * @param arrayOne - array to be extended by adding arrayTwo to its end
	 * @param arrayTwo - the array concatenated onto the end of arrayOne
	 * @return the concatenated array
	 */
	public final static double[] appendArray(double[] arrayOne, double[] arrayTwo) {
		if (arrayOne == null)
			arrayOne = new double[0];
		
		int n = arrayOne.length;
		int m = arrayTwo.length;
		double[] ans = new double[m+n];
		System.arraycopy(arrayOne, 0, ans, 0, n);
		System.arraycopy(arrayTwo, 0, ans, n, m);
		
		return ans;
	}
	
	/** Flatten a 2D double array that hasn't necessarily been square allocated to a 1D array. */
	public final static double[] flattenNonUniform(double mat[][]){
			int n = mat.length;
			int m = 0;
			int currentIdx = 0;
			
			for(int i=0; i < n; i++)
				m += mat[i].length;
			
			double flatMat[] = new double[m];
			
			for(int i=0; i < n; i++) {
				m = mat[i].length;
				System.arraycopy(mat[i], 0, flatMat, currentIdx, m);
				currentIdx += m;
			}
			return flatMat;
	}


	
	/** Mumble, mumble ... no way to call sensible OS routines ... mumble mumble */ 
	public final static void copyFile(String sourceName, String destName) throws IOException { copyFile(new File(sourceName), new File(destName)); }
	
	/** Mumble, mumble ... no way to call sensible OS routines ... mumble mumble */ 
	public final static void copyFile(File sourceFile, File destFile) throws IOException {

		
		if(!destFile.exists()) 
			destFile.createNewFile();		

		FileChannel source = null, destination = null;
		try {
			source = new FileInputStream(sourceFile).getChannel();
			destination = new FileOutputStream(destFile).getChannel();
			destination.transferFrom(source, 0, source.size());
		} finally {
			if(source != null) 
				source.close();			
			if(destination != null)
				destination.close();
		}
	}
	
    /** Java doesn't have the error function, which is annoying.
     * This was copied from somewhere. I can't remember where, but it works.
     * 
     * Fractional error in math formula less than 1.2 * 10 ^ -7.
     * although subject to catastrophic cancellation when z in very close to 0 */
	 public final static double erf(double z) {
	     double t = 1.0 / (1.0 + 0.5 * Math.abs(z));
	
	     // use Horner's method
	     double ans = 1 - t * FastMath.exp( -z*z   -   1.26551223 +
	                                         t * ( 1.00002368 +
	                                         t * ( 0.37409196 + 
	                                         t * ( 0.09678418 + 
	                                         t * (-0.18628806 + 
	                                         t * ( 0.27886807 + 
	                                         t * (-1.13520398 + 
	                                         t * ( 1.48851587 + 
	                                         t * (-0.82215223 + 
	                                         t * ( 0.17087277))))))))));
	     if (z >= 0) return  ans;
	     else        return -ans;
	 }

	public final static int indexOfStringInList(String[] list, String string) {
		for(int i=0; i < list.length; i++){
			if(string.equals(list[i]))
				return i;
		}
		return -1;
	}	
	
	/** NB: I've not yet checked atan2() for quadrants etc. correctness 
	  (R,phi,Z) <-- (x,y,z) = (R cos phi, R sin phi, Z)
	  if y == null, (x, ,z) = (R, , z) and assume all R > 0 (not checked) */ 
	public final static double[][] XYZToRPhiZ(double XYZ[][]){
		// If y is null (shorthand for all 0), than we can have just R=X, Z=Z and hope all R > 0
		if(XYZ[1] == null)
			return new double[][]{ XYZ[0], null, XYZ[2] };
		int n = XYZ[0].length;
		double R[] = new double[n];
		double phi[] = new double[n];
		for(int i=0; i < n; i++){ 
			phi[i] = FastMath.atan2(XYZ[1][i], XYZ[0][i]);
			R[i] = Math.sqrt(XYZ[0][i]*XYZ[0][i] + XYZ[1][i]*XYZ[1][i]);
		}
		return new double[][]{ R, phi, XYZ[2] };
	}
	
	
	/** NB: I've not yet checked atan2() for quadrants etc. correctness 
	  (R,phi,Z) <-- (x,y,z) = (R cos phi, R sin phi, Z)
	  if y == null, (x, ,z) = (R, , z) and assume all R > 0 (not checked) */ 
	public final static double[] XYZToRPhiZSingle(double XYZ[]){
		double[][] ret = XYZToRPhiZ(new double[][] { {XYZ[0]}, {XYZ[1]}, {XYZ[2]} });
		return new double[] { ret[0][0], ret[1][0], ret[2][0] };		
	}
	
	/** (R,phi,Z) --> (x,y,z) = (R cos phi, R sin phi, Z) 
	 * if y == null, (x, ,z) = (R, , z) */
	public final static double[][] RPhiZToXYZ(double RPhiZ[][]){
		// If phi is null (shorthand for all 0), than we can have just X=R, Z=Z
		if(RPhiZ[1] == null)
			return new double[][]{ RPhiZ[0], null, RPhiZ[2] };
		int n = RPhiZ[0].length;
		double X[] = new double[n];
		double Y[] = new double[n];
		for(int i=0; i < n; i++){
			X[i] = RPhiZ[0][i] * FastMath.cos(RPhiZ[1][i]);
			Y[i] = RPhiZ[0][i] * FastMath.sin(RPhiZ[1][i]);
		}
		return new double[][]{ X, Y, RPhiZ[2] };
	}

	/** (R,phi,Z) --> (x,y,z) = (R cos phi, R sin phi, Z) 
	 * if y == null, (x, ,z) = (R, , z) */
	public final static double[] RPhiZToXYZSingle(double RPhiZ[]){
		double[][] ret = RPhiZToXYZ(new double[][] { {RPhiZ[0]}, {RPhiZ[1]}, {RPhiZ[2]} });
		return new double[] { ret[0][0], ret[1][0], ret[2][0] };				
	}

	public final static double[][] addColumRowHeaders(double[][] in, double rowHead[], double colHead[]) {
		int nRows = in.length, nCols=in[0].length;
		
		double out[][] = new double[nRows+1][nCols+1];
		for(int j=0; j < nCols; j++)
			out[0][j+1] = colHead[j];
		
		for(int i=0; i< nRows; i++){
			out[i+1][0] = rowHead[i];
			for(int j=0; j < nCols; j++){
				out[i+1][j+1] = in[i][j];
			}
		}
		
		return out;
	}

	public final static double[][] RPhiZVectorToXYZVector(double posRPhiZ[][], double vecRPhiZ[][]){
		
		//otherwise we need to project accordingly
		double vecXYZ[][] = new double[][]{ 	new double[posRPhiZ[0].length],
												new double[posRPhiZ[0].length],
												vecRPhiZ[2]	/* Bz=Bz always */		};
		
		for(int i=0; i < posRPhiZ[0].length; i++){
			double sinPhi = FastMath.sin(posRPhiZ[1][i]);
			double cosPhi = FastMath.cos(posRPhiZ[1][i]);
			vecXYZ[0][i] = vecRPhiZ[0][i] * cosPhi - vecRPhiZ[1][i] * sinPhi;
			vecXYZ[1][i] = vecRPhiZ[1][i] * cosPhi + vecRPhiZ[0][i] * sinPhi;
		}
		
		return vecXYZ;
	}
	

	public static double[][] XYZVectorToRPZVector(double[][] posXYZ, double[][] vecXYZ) {
		
		double vecRPhiZ[][] = new double[][]{ 	new double[posXYZ[0].length],
												new double[posXYZ[0].length],
												vecXYZ[2]	/* Bz=Bz always */		};

		for(int i=0; i < posXYZ[0].length; i++){
			 //TODO: trig avoidance
			double phi = FastMath.atan2(posXYZ[1][i], posXYZ[0][i]);
			double sinPhi = FastMath.sin(phi);
			double cosPhi = FastMath.cos(phi);
			vecRPhiZ[0][i] = vecXYZ[0][i] * cosPhi + vecXYZ[1][i] * sinPhi;
			vecRPhiZ[1][i] = vecXYZ[1][i] * cosPhi - vecXYZ[0][i] * sinPhi;
		}
		
		return vecRPhiZ;
	}

	/** (equ from wikipedia/rotation matrix) */
	public static final double[] rotateVectorAroundAxis(double angle, double rotVec[], double sourceVec[]){
		double cosAng = Math.cos(angle);
		double sinAng = Math.sin(angle);
		
		return new double[]{
				sourceVec[0] * (cosAng + rotVec[0]*rotVec[0]*(1.0 - cosAng) ) +
				sourceVec[1] * (rotVec[0]*rotVec[1]*(1.0 - cosAng) - rotVec[2]*sinAng) +
				sourceVec[2] * (rotVec[0]*rotVec[2]*(1.0 - cosAng) + rotVec[1]*sinAng),
		
				sourceVec[0] * (rotVec[1]*rotVec[0]*(1.0 - cosAng) + rotVec[2]*sinAng) +
				sourceVec[1] * (cosAng + rotVec[1]*rotVec[1]*(1.0 - cosAng) ) +
				sourceVec[2] * (rotVec[1]*rotVec[2]*(1.0 - cosAng) - rotVec[0]*sinAng),
				
				sourceVec[0] * (rotVec[2]*rotVec[0]*(1.0 - cosAng) - rotVec[1]*sinAng) +
				sourceVec[1] * (rotVec[2]*rotVec[1]*(1.0 - cosAng) + rotVec[0]*sinAng) +
				sourceVec[2] * (cosAng + rotVec[2]*rotVec[2]*(1.0 - cosAng) ),		
		};	
	}
	
	public static final double[] rotateVectorAroundAxis(double angle, 
			double rotVecX, double rotVecY, double rotVecZ,
			double sourceVecX, double sourceVecY, double sourceVecZ,
			double ret[]){
		double cosAng = Math.cos(angle);
		double sinAng = Math.sin(angle);
		
		
		ret[0] = 	sourceVecX * (cosAng + rotVecX*rotVecX*(1.0 - cosAng) ) +
					sourceVecY * (rotVecX*rotVecY*(1.0 - cosAng) - rotVecZ*sinAng) +
					sourceVecZ * (rotVecX*rotVecZ*(1.0 - cosAng) + rotVecY*sinAng);
			
		ret[1] = 	sourceVecX * (rotVecY*rotVecX*(1.0 - cosAng) + rotVecZ*sinAng) +
					sourceVecY * (cosAng + rotVecY*rotVecY*(1.0 - cosAng) ) +
					sourceVecZ * (rotVecY*rotVecZ*(1.0 - cosAng) - rotVecX*sinAng);
					
		ret[2] = 	sourceVecX * (rotVecZ*rotVecX*(1.0 - cosAng) - rotVecY*sinAng) +
					sourceVecY * (rotVecZ*rotVecY*(1.0 - cosAng) + rotVecX*sinAng) +
					sourceVecZ * (cosAng + rotVecZ*rotVecZ*(1.0 - cosAng) );
		return ret;
	}

	/** Converts all any of %;?/:#&=+$, <>~ to % and the hex char code like in a URL 
	 * This is probably a little overkill, but meh */
	public static String sanitizeFilename(String name) {
		return name.replaceAll("\\%", "%25")
					.replaceAll("\\;", "%3B")
					.replaceAll("\\?", "%3F")
					.replaceAll("\\/", "%2F")
					.replaceAll("\\\\", "%92")
					.replaceAll("\\:", "%3A")
					.replaceAll("\\#", "%23")
					.replaceAll("\\&", "%26")
					.replaceAll("\\=", "%3D")
					.replaceAll("\\+", "%2B")
					.replaceAll("\\*", "%2A")
					.replaceAll("\\$", "%24")
					.replaceAll("\\,", "%2C")
					.replaceAll("\\ ", "%20")
					.replaceAll("\\<", "%3C")
					.replaceAll("\\>", "%3E")
					.replaceAll("\\~", "%7E");
		// ... yes, there's probably a more elegant way of doing that
		//and I escaped everything to be sure
	}

	public static String desanitizeFilename(String name) {
		StringBuffer sb = new StringBuffer();
		Matcher m = Pattern.compile("%([0-9A-Fa-f][0-9A-Fa-f])").matcher(name);
		while (m.find()) {
			String x = m.group(1);
		  m.appendReplacement(sb, new Character((char) Integer.parseInt(x,16)).toString());
		}
		m.appendTail(sb);
		
		return sb.toString();
	}

	/** Generates flat arrays xx[], yy[] for all points in the grid (x[], y[])
	 * The x coordinate changes fastest.
	 * 
	 * @param x0	Min value of x coord
	 * @param x1	Max value of x coord
	 * @param nX	Number of x coord points
	 * @param y0	Min value of y coord
	 * @param y1	Max value of y coord
	 * @param nY	Number of y coord points
	 * @return	double[][]{ x[nX*nY], y[nX*nY] }
	 */
	public static double[][] flatGrid(double x[], double y[]) {
		double xx[] = new double[x.length*y.length];
		double yy[] = new double[x.length*y.length];
		
		for(int iY=0; iY < y.length; iY++){
			for(int iX=0; iX < x.length; iX++){
				xx[iY*x.length + iX] = x[iX];
				yy[iY*x.length + iX] = y[iY];
			}	
		}
		
		return new double[][]{ xx, yy };
	}
	
	/** Generates flat arrays x[], y[] for all points in the grid nX x nY grid on (x0,y0) - (x1-y1)
	 * The x coordinate changes fastest.
	 * 
	 * @param x0	Min value of x coord
	 * @param x1	Max value of x coord
	 * @param nX	Number of x coord points
	 * @param y0	Min value of y coord
	 * @param y1	Max value of y coord
	 * @param nY	Number of y coord points
	 * @return	double[][]{ x[nX*nY], y[nX*nY] }
	 */
	public static double[][] flatGrid(double x0, double x1, int nX, double y0, double y1, int nY) {
		double xx[] = new double[nX*nY];
		double yy[] = new double[nX*nY];
		double dx = (x1 - x0) / (nX - 1.0);
		double dy = (y1 - y0) / (nY - 1.0);
		
		for(int iY=0; iY < nY; iY++){
			for(int iX=0; iX < nX; iX++){
				xx[iY*nX + iX] = x0 + iX * dx;
				yy[iY*nX + iX] = y0 + iY * dy;
			}	
		}
		
		return new double[][]{ xx, yy };
	}
	
	/** See OneLiners.fixWeirdContainers(Object obj, boolean forcePrimitive) */
	public static final Object fixWeirdContainers(Object obj){ return fixWeirdContainers(obj, false); }

	/** Rebuild n-dimension object as a proper array of numeric types.
	 * Lists and Object[] are all converted to the base type.
	 * 
	 * Unless forcePrimitiveTypes is true, it doesn't necessarily convert 
	 * to primitive types.
	 *   i.e. the result might be a int[][][] or an Integer[][][]
	 * 
	 * This will try to cast things where possible and only fills
	 * and new array when necessary.
	 * 
	 * @param obj
	 * @param forcePrimitiveTypes 
	 * @return
	 */
	public static final Object fixWeirdContainers(Object obj, boolean forcePrimitive){
		return fixWeirdContainersRecurse(obj, forcePrimitive, 0);
	}
	
	private static final Object fixWeirdContainersRecurse(Object obj, boolean forcePrimitive, int depth){
		if(depth > 1000)
			throw new RuntimeException("Trying to de-List a rank > 1000 object. You probably have a ciruclar links!");

		if(obj instanceof List<?>){
			List<?> oList = (List<?>)obj;
			
			Object oArrOut = null; //don't know type yet
			int i=0;
			for(Object o : oList){
				Object entry = fixWeirdContainersRecurse(o, forcePrimitive, depth+1);
				
				if(oArrOut == null){ //we can now type it correctly
					Class entryClass = entry.getClass();
					if(forcePrimitive && !entryClass.isArray() &&  !entryClass.isPrimitive())
						entryClass = getPrimitiveType(entryClass);	
					oArrOut = Array.newInstance(entryClass, oList.size());
				}

				Array.set(oArrOut, i, entry);
				i++;
			}
			return oArrOut;
			
		}else if(obj instanceof Object[]){
			Object[] oArrIn = (Object[])obj;
			Object oArrOut = null;
			
			for(int i=0; i < oArrIn.length; i++){
				Object entry = fixWeirdContainersRecurse(oArrIn[i], forcePrimitive, depth+1);
				if(oArrOut == null){
					if(finalTypesMatch(oArrIn, entry) && !forcePrimitive){
						oArrOut = oArrIn; //the array is OK as it is
					}else{
						Class entryClass = entry.getClass();
						if(forcePrimitive && !entryClass.isArray() &&  !entryClass.isPrimitive())
							entryClass = getPrimitiveType(entryClass);						
						oArrOut = Array.newInstance(entryClass, oArrIn.length);
					}
				}
				Array.set(oArrOut, i, entry);
			}
			return oArrOut;
		}
		
		return obj;
	}
	
	private static final Class getPrimitiveType(Class objType){
		if(objType == Byte.class){
			return byte.class;
		}else if(objType == Character.class){
			return char.class;
		}else if(objType == Short.class){
			return short.class;
		}else if(objType == Integer.class){
			return int.class;
		}else if(objType == Long.class){
			return long.class;
		}else if(objType == Float.class){
			return float.class;
		}else if(objType == Double.class){
			return double.class;
		}else if(objType == String.class){
			return String.class; //can't do anything with this one
		}else
			throw new IllegalArgumentException("fixWeirdContainersRecurse() called with forcePrimitive=true, but found type '"+
													objType.getName()+"' with no compatible primitive");
	}
		

	/** Checks that the actual 'type' of the two objects match.
	 * If the objects are arrays, this refers to the type that this claims
	 * to be an array of.
	 * 
	 * This counter-intuitive and actually just plain stupid, Java well and truly messed this stuff up 
	 * 
	 * Examples: 
	 * 	new Integer[][][]{ { { 1, 2, 3} } } would be 'java.lang.Integer
	 * 	new Object[]{ new Integer[]{ 1, 2, 3 } } would be 'java.lang.Object' (i.e. not Integer)
	 *  (Object[])(new Integer[]{ 1, 2, 3 }) would be 'java.lang.Integer' despite being viewes as an Object[]
	 *  new int[][][] would probably be 'I'
	 *  new (Object[][][])(new int[][][]{ 
	 * 
	 *  The point is that both Integer[] and int[] can be cast to an Object[], but that the result is not the
	 *  same things as an actual Object[].
	 */  
	private final static boolean finalTypesMatch(Object a, Object b){
		//the regex removes all leading '[' and a single leading 'L'
		// and also a single trailing ';'
		
		String aClassName = a.getClass().getName();
		String aFinalType = aClassName.replaceFirst("^\\[*", "").replaceFirst("^L", "").replaceFirst(";$", "");
		
		String bClassName = b.getClass().getName();
		String bFinalType = bClassName.replaceFirst("^\\[*", "").replaceFirst("^L", "").replaceFirst(";$", "");
		
		return bFinalType.equals(aFinalType);
		
	}

	public static final int mustParseInt(String str){
		try{
			return Integer.parseInt(str);
		}catch(NumberFormatException err){
			return 0;
		}
	}
	
	public static final long mustParseLong(String str) {
		try{
			return Long.parseLong(str);
		}catch(NumberFormatException err){
			return 0;
		}
	}
	
	public static final double mustParseDouble(String str){
		try{
			return Double.parseDouble(str);
		}catch(NumberFormatException err){
			return 0;
		}
	}
	
	public static boolean mustParseBoolean(String str) {
		try{
			if(str.startsWith("t") || str.startsWith("T") || str.startsWith("Y") || str.startsWith("y") 
				|| Double.parseDouble(str) != 0.0)
					return true;
			else 
				return false;
		}catch(NumberFormatException err){
			return false;
		}
		
	}
		
		
	public final static double length(double x[]){ 
		return FastMath.sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]); 
	}
		
	/** Renormalise the given vector */
	public final static double[] reNorm(double x[]){
		double sum=0;
		
		for(int i=0;i<3;i++)
			sum += x[i] * x[i];
		
		sum = FastMath.sqrt(sum);
		
		for(int i=0;i<3;i++)
			x[i] /= sum;
		
		return x;
	}
	
	/** Calculates the cross production of A and B*/
	public final static double[] cross(double A[], double B[]){
		double AxB[] = new double[3];
		
		AxB[0] =  A[1] * B[2] - A[2] * B[1];
		AxB[1] = -A[0] * B[2] + A[2] * B[0];
		AxB[2] =  A[0] * B[1] - A[1] * B[0];
		
		return AxB;
	}
	
	/** Dot product */
	public final static double dot(double A[], double B[]){
		return A[0]*B[0] + A[1]*B[1] + A[2]*B[2];
	}
	
	/** @return a - b */
	public final static double[] minus(double[] a, double[] b) { 
		return new double[]{ a[0] - b[0], a[1] - b[1], a[2] - b[2] };
	}
	
	/** @return a + b */
	public final static double[] plus(double[] a, double[] b) { 
		return new double[]{ a[0] + b[0], a[1] + b[1], a[2] + b[2] };
	}
	
	/** @return a * b */
	public final static double[] mul(double[] a, double b) { 
		return new double[]{ a[0] * b, a[1] * b, a[2] * b };
	}

	/** @return new Object[]{ double row0[], double col0[], double data[], Double topLeftCornerVal }; */
	public static Object[] splitRowColHeaders(double[][] in) {
		int n = in.length - 1;
		int m = in[0].length - 1;
		double row0[] = new double[m];
		double col0[] = new double[n];
		double out[][] = new double[n][m];
		System.arraycopy(in[0], 1, row0, 0, m);
		for(int i=0; i < n; i++){
			col0[i] = in[i+1][0];
			System.arraycopy(in[i+1], 1, out[i], 0, m);
		}
		return new Object[]{ row0, col0, out, in[0][0] };
	}

	public final static int[] booleanToDoubleArray(boolean[] bool) {
		int ret[] = new int[bool.length];
		for(int i =0; i < bool.length; i++)
			ret[i] = bool[i] ? 1 : 0;
		return ret;
	}

	public final static double[] booleanToIntArray(boolean[] bool) {
		double ret[] = new double[bool.length];
		for(int i =0; i < bool.length; i++)
			ret[i] = bool[i] ? -1 : 0;
		return ret;
	}

	/** @return Index of the string in possible[] that matches text to the most characters */
	public static int findBestMatchingString(String possible[], String text) {
		int bestMatchIdx = -1;
		int bestMatchLen = 0;
		for(int i=0; i < possible.length; i++){
			int matchLen;
			int n = Math.min(text.length(), possible[i].length());
			for(matchLen=0; matchLen < n; matchLen++){ //for each character
				//check if the match fails here
				if(Character.toLowerCase(text.charAt(matchLen)) !=
						Character.toLowerCase(possible[i].charAt(matchLen))){
					break;
				}

			}
			if(matchLen > bestMatchLen){
				bestMatchIdx = i;
				bestMatchLen = matchLen;								
			}					
		}
		return bestMatchIdx;
	}

	public final static double[] deg2Rad(double deg[]){ 
		for(int i=0; i < deg.length; i++){ 
			deg[i] *= Math.PI / 180; 
		} 
		return deg; 
	}
	
	public final static double[][] deg2Rad(double deg[][]){ 
		for(int i=0; i < deg.length; i++){ 
			deg[i] = deg2Rad(deg[i]); 
		} 
		return deg; 
	}
	
}
