diff CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/opt/bbmap-39.01-1/current/fileIO/ReadWrite.java @ 68:5028fdace37b

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 16:23:26 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/opt/bbmap-39.01-1/current/fileIO/ReadWrite.java	Tue Mar 18 16:23:26 2025 -0400
@@ -0,0 +1,1946 @@
+package fileIO;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.lang.ProcessBuilder.Redirect;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+import dna.Data;
+import shared.KillSwitch;
+import shared.Shared;
+import shared.Tools;
+import stream.ConcurrentReadOutputStream;
+import stream.ConcurrentReadStreamInterface;
+import stream.MultiCros;
+import structures.ByteBuilder;
+
+public class ReadWrite {
+	
+	
+	public static void main(String[] args){
+		File f=new File(args[1]);
+		assert(!f.exists()) : "Destination file already exists.";
+		copyFile(args[0], args[1]);
+	}
+	
+	public static void writeStringInThread(CharSequence x, String fname){
+		writeStringInThread(x, fname, false);
+	}
+	
+	public static void writeStringInThread(CharSequence x, String fname, boolean append){
+		addThread(1);
+		new Thread(new WriteStringThread(x, fname, append)).start();
+	}
+	
+	public static void writeObjectInThread(Object x, String fname, boolean allowSubprocess){
+		addThread(1);
+		new Thread(new WriteObjectThread(x, fname, allowSubprocess)).start();
+	}
+	
+	private static class WriteStringThread implements Runnable{
+		
+		private final CharSequence x;
+		private final String fname;
+		private final boolean append;
+		WriteStringThread(CharSequence x_, String fname_, boolean append_){
+			x=x_;
+			fname=fname_;
+			append=append_;
+		}
+		
+		@Override
+		public void run() {
+			if(verbose){System.err.println("WriteStringThread.run() started for fname "+fname);}
+			addRunningThread(1);
+			writeStringAsync(x, fname, append);
+			addThread(-1);
+			if(verbose){System.err.println("WriteStringThread.run() finished for fname "+fname);}
+		}
+		
+	}
+	
+	private static class WriteObjectThread implements Runnable{
+		
+		private final Object x;
+		private final String fname;
+		private final boolean allowSubprocess;
+		WriteObjectThread(Object x_, String fname_, boolean allowSubprocess_){
+			x=x_;
+			fname=fname_;
+			allowSubprocess=allowSubprocess_;
+		}
+		
+		@Override
+		public void run() {
+			if(verbose){System.err.println("WriteObjectThread.run() started for fname "+fname);}
+			addRunningThread(1);
+//			System.out.println(fname+" began writing.");
+			writeAsync(x, fname, allowSubprocess);
+//			System.out.println(fname+" finished writing.");
+			addThread(-1);
+//			System.out.println(fname+" reports "+countActiveThreads()+" active threads.");
+			if(verbose){System.err.println("WriteObjectThread.run() finished for fname "+fname);}
+		}
+		
+	}
+	
+	public static boolean setPermissions(String fname, boolean read, boolean write, boolean execute, boolean ownerOnly){
+		File f=new File(fname);
+		if(!f.exists()){return false;}
+		try {
+			f.setReadable(read, ownerOnly);
+			f.setWritable(write, ownerOnly);
+			f.setExecutable(execute, ownerOnly);
+		} catch (Exception e) {
+			return false;
+		}
+		return true;
+	}
+
+	public static void writeString(CharSequence x, String fname){writeString(x, fname, false);}
+	public static void writeString(CharSequence x, String fname, boolean append){
+		if(verbose){System.err.println("writeString(x, "+fname+", "+append+")");}
+		OutputStream os=getOutputStream(fname, append, true, false);
+		
+		try {
+
+			synchronized(diskSync){
+				PrintWriter out=new PrintWriter(os);
+				out.print(x);
+				out.flush();
+
+				if(os.getClass()==ZipOutputStream.class){
+					ZipOutputStream zos=(ZipOutputStream)os;
+					zos.closeEntry();
+					zos.finish();
+				}
+//				else if(PROCESS_XZ && os.getClass()==org.tukaani.xz.XZOutputStream.class){
+//					org.tukaani.xz.XZOutputStream zos=(org.tukaani.xz.XZOutputStream)os;
+//					zos.finish();
+//				}
+				out.close();
+			}
+//			System.out.println("Wrote to "+fname);
+			
+//			String read=readString(fname);
+//			assert(x.equals(read)) : x.length()+", "+read.length();
+			
+		} catch (FileNotFoundException e) {
+			throw new RuntimeException(e);
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		} catch (OutOfMemoryError e) {
+			KillSwitch.memKill(e);
+		}
+	}
+
+	public static void writeStringAsync(CharSequence x, String fname){writeStringAsync(x, fname, false);}
+	public static void writeStringAsync(CharSequence x, String fname, boolean append){
+		if(verbose){System.err.println("writeStringAsync(x, "+fname+", "+append+")");}
+		
+		OutputStream os=getOutputStream(fname, append, true, false);
+		
+		try {
+
+			synchronized(diskSync){
+				PrintWriter out=new PrintWriter(os);
+				out.print(x);
+				out.flush();
+
+				if(os.getClass()==ZipOutputStream.class){
+					ZipOutputStream zos=(ZipOutputStream)os;
+					zos.closeEntry();
+					zos.finish();
+				}
+//				else if(PROCESS_XZ && os.getClass()==org.tukaani.xz.XZOutputStream.class){
+//					org.tukaani.xz.XZOutputStream zos=(org.tukaani.xz.XZOutputStream)os;
+//					zos.finish();
+//				}
+				out.close();
+			}
+//			System.out.println("Wrote to "+fname);
+			
+//			String read=readString(fname);
+//			assert(x.equals(read)) : x.length()+", "+read.length();
+			
+		} catch (FileNotFoundException e) {
+			throw new RuntimeException(e);
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		} catch (OutOfMemoryError e) {
+			KillSwitch.memKill(e);
+		}
+	}
+	
+	public static <X> void write(X x, String fname, boolean allowSubprocess){
+		if(verbose){System.err.println("write(x, "+fname+", "+allowSubprocess+")");}
+		
+		OutputStream os=getOutputStream(fname, false, true, allowSubprocess);
+		
+		try {
+
+			synchronized(diskSync){
+				ObjectOutputStream out=new ObjectOutputStream(os);
+				out.writeObject(x);
+				close(out);
+			}
+			
+		} catch (FileNotFoundException e) {
+			throw new RuntimeException(e);
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		} catch (OutOfMemoryError e) {
+			KillSwitch.memKill(e);
+		}
+	}
+	
+	public static <X> void writeAsync(X x, String fname, boolean allowSubprocess){
+		if(verbose){System.err.println("writeAsync(x, "+fname+", "+allowSubprocess+")");}
+		
+		OutputStream os=getOutputStream(fname, false, true, allowSubprocess);
+		
+		try {
+
+			ObjectOutputStream out=new ObjectOutputStream(os);
+			out.writeObject(x);
+			close(out);
+
+		} catch (FileNotFoundException e) {
+			throw new RuntimeException(e);
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		} catch (OutOfMemoryError e) {
+			KillSwitch.memKill(e);
+		}
+	}
+	
+	public static final boolean finishReading(InputStream is, String fname, boolean killProcess, Reader...ra){
+		if(verbose){System.err.println("finishReading("+is+", "+fname+", "+killProcess+", "+ra.length+")");}
+		boolean error=false;
+		if(ra!=null){
+			for(Reader r : ra){
+				try {
+					r.close();
+				} catch (IOException e) {
+					error=true;
+					e.printStackTrace();
+				}
+			}
+		}
+		error|=finishReading(is, fname, killProcess);
+		if(verbose){System.err.println("finishReading("+is+", "+fname+", "+killProcess+", "+ra.length+") returned "+error);}
+		return error;
+	}
+	
+	public static final boolean finishReading(InputStream is, String fname, boolean killProcess){
+		if(verbose){System.err.println("finishReading("+is+", "+fname+", "+killProcess+")");}
+		boolean error=false;
+		if(is!=System.in){
+			try {
+				is.close();
+			} catch (IOException e) {
+				error=true;
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+		if(killProcess && fname!=null && is!=System.in){error|=ReadWrite.killProcess(fname);}
+		if(verbose){System.err.println("finishReading("+is+", "+fname+", "+killProcess+") returned "+error);}
+		return error;
+	}
+	
+//	public static final boolean finishWriting(PrintWriter writer, OutputStream outStream, String fname){
+//		return finishWriting(writer, outStream, fname, fname!=null);
+//	}
+	
+	public static final boolean finishWriting(PrintWriter writer, OutputStream outStream, String fname, boolean killProcess){
+		if(verbose){System.err.println("finishWriting("+writer+", "+outStream+" , "+fname+", "+killProcess+")");}
+		boolean error=false;
+		if(writer!=null){writer.flush();}
+		close(outStream);
+		if(writer!=null && outStream!=System.out && outStream!=System.err){writer.close();}
+		if(killProcess && fname!=null && outStream!=System.err && outStream!=System.out){error|=ReadWrite.killProcess(fname);}
+		if(verbose){System.err.println("finishWriting("+writer+", "+outStream+" , "+fname+", "+killProcess+") returned "+error);}
+		return error;
+	}
+	
+	public static final boolean close(OutputStream os, String fname){
+		if(verbose){System.err.println("close("+os+", "+fname+")");}
+		boolean error=false;
+		if(os!=null){error|=close(os);}
+		if(fname!=null && os!=System.err && os!=System.out){error|=killProcess(fname);}
+		if(verbose){System.err.println("close("+os+", "+fname+") returned "+error);}
+		return error;
+	}
+	
+	public static final boolean close(OutputStream os){
+		if(verbose){System.err.println("close("+os+")");}
+		boolean error=false;
+		try {
+			os.flush();
+		} catch (IOException e1) {
+			// TODO Auto-generated catch block
+			e1.printStackTrace();
+			error=true;
+		}
+		if(os.getClass()==ZipOutputStream.class){
+			ZipOutputStream zos=(ZipOutputStream)os;
+			try {
+				zos.closeEntry();
+				zos.finish();
+			} catch (IOException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+				error=true;
+			}
+		}
+//		else if(PROCESS_XZ && os.getClass()==org.tukaani.xz.XZOutputStream.class){
+//			org.tukaani.xz.XZOutputStream zos=(org.tukaani.xz.XZOutputStream)os;
+//			try {
+//				zos.finish();
+//			} catch (IOException e) {
+//				// TODO Auto-generated catch block
+//				e.printStackTrace();
+//			}
+//		}
+		if(os!=System.out && os!=System.err){
+			try {
+				os.close();
+			} catch (IOException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+				error=true;
+			}
+		}
+		if(verbose){System.err.println("close("+os+") returned "+error);}
+		return error;
+	}
+	
+	public static OutputStream getOutputStream(FileFormat ff, boolean buffered){
+		return getOutputStream(ff.name(), ff.append(), buffered, ff.allowSubprocess());
+	}
+
+	public static OutputStream getOutputStream(String fname, boolean append, boolean buffered, boolean allowSubprocess){
+		
+		if(verbose){
+			System.err.println("getOutputStream("+fname+", "+append+", "+buffered+", "+allowSubprocess+")");
+			new Exception().printStackTrace(System.err);
+		}
+		
+//		assert(false) : fname; //TODO: for testing
+//		fname=fname.replaceAll("\\\\", "/");
+		fname=fname.replace('\\', '/');
+		assert(fname.indexOf('\\')<0);
+//		assert(!fname.contains("//"));
+		
+		{//Create directories if needed.
+			final int index=fname.lastIndexOf('/');
+			if(index>0){
+				File f=new File(fname.substring(0, index+1));
+				if(!f.exists()){f.mkdirs();}
+			}
+		}
+		
+		boolean gzipped=fname.endsWith(".gz") || fname.endsWith(".gzip");
+		boolean zipped=fname.endsWith(".zip");
+		boolean bzipped=PROCESS_BZ2 && fname.endsWith(".bz2");
+		boolean xz=PROCESS_XZ && fname.endsWith(".xz");
+		boolean dsrced=fname.endsWith(".dsrc");
+		boolean fqz=USE_FQZ && fname.endsWith(".fqz");
+		boolean alapy=USE_ALAPY && fname.endsWith(".ac");
+		
+//		assert(false) : fname;
+		
+		allowSubprocess=(allowSubprocess && Shared.threads()>1);
+		
+		if(gzipped){
+//			assert(!append);
+			return getGZipOutputStream(fname, append, allowSubprocess);
+		}else if(zipped){
+			assert(!append) : "Append is not allowed for zip archives.";
+			return getZipOutputStream(fname, buffered, allowSubprocess);
+		}else if(bzipped){
+			assert(!append) : "Append is not allowed for bz2 archives.";//TODO: This might be OK; try it.
+			return getBZipOutputStream(fname, buffered, append, allowSubprocess);
+		}else if(xz){
+			assert(!append) : "Append is not allowed for xz archives.";
+			return getXZOutputStream(fname, buffered, allowSubprocess);
+		}else if(dsrced){
+			assert(!append) : "Append is not allowed for dsrc archives.";
+			return getDsrcOutputStream(fname, buffered, allowSubprocess);
+		}else if(fqz){
+			assert(!append) : "Append is not allowed for fqz archives.";
+			return getFqzStream(fname);
+		}else if(alapy){
+			assert(!append) : "Append is not allowed for alapy archives.";
+			return getAlapyStream(fname);
+		}
+		return getRawOutputStream(fname, append, buffered);
+	}
+	
+	public static OutputStream getRawOutputStream(String fname, boolean append, boolean buffered){
+		
+		if(verbose){System.err.println("getRawOutputStream("+fname+", "+append+", "+buffered+")");}
+		
+		if(fname.equals("stdout") || fname.startsWith("stdout.")){
+			return System.out;
+		}else if(fname.equals("stderr") || fname.startsWith("stderr.")){
+			return System.err;
+		}else if(fname.startsWith("/dev/null/")){
+			fname="/dev/null/";
+		}
+		
+		if(fname.indexOf('|')>=0){fname=fname.replace('|', '_');}
+		
+		FileOutputStream fos=null;
+		try {
+			fos = new FileOutputStream(fname, append);
+		} catch (FileNotFoundException e) {
+			synchronized(ReadWrite.class){
+				try {
+					File f=new File(fname);
+					String parent=f.getParent();
+					
+					if(parent!=null){
+						f=new File(parent);
+						if(!f.exists()){
+							boolean b=f.mkdirs();
+							if(!b){System.err.println("Warning - could not create directory "+f.getAbsolutePath());}
+						}
+					}
+					fos = new FileOutputStream(fname, append);
+				} catch (Exception e2) {
+					throw new RuntimeException(e2);
+				}
+			}
+		}
+		assert(fos!=null);
+		if(buffered){return new BufferedOutputStream(fos);}
+		return fos;
+	}
+	
+	public static OutputStream getXZOutputStream(String fname, boolean buffered, boolean allowSubprocess){
+		final OutputStream raw=getRawOutputStream(fname, false, buffered);
+		if(RAWMODE){return raw;}
+		throw new RuntimeException("Unsupported format: XZ");
+//		try {
+//			org.tukaani.xz.LZMA2Options options = new org.tukaani.xz.LZMA2Options();
+//			options.setPreset(ZIPLEVEL);
+//			org.tukaani.xz.XZOutputStream out=new org.tukaani.xz.XZOutputStream(raw, options);
+//			return out;
+//		} catch (IOException e) {
+//			// TODO Auto-generated catch block
+//			e.printStackTrace();
+//		}
+//		assert(false);
+//		return null;
+	}
+	
+	public static OutputStream getBZipOutputStream(String fname, boolean buffered, boolean append, boolean allowSubprocess){
+		if(verbose){System.err.println("getBZipOutputStream("+fname+", "+buffered+", "+append+", "+allowSubprocess+")");}
+//		assert(false) : ReadWrite.ZIPLEVEL+", "+Shared.threads()+", "+MAX_ZIP_THREADS+", "+ZIP_THREAD_MULT+", "+allowSubprocess+", "+USE_PIGZ+", "+Data.PIGZ();
+		
+		if(RAWMODE){
+			final OutputStream raw=getRawOutputStream(fname, false, buffered);
+			return raw;
+		}
+		
+		if(USE_LBZIP2 && Data.LBZIP2()){return getLbzip2Stream(fname, append);}
+		if(USE_PBZIP2 && Data.PBZIP2()){return getPbzip2Stream(fname, append);}
+		if(USE_BZIP2 && Data.BZIP2()){return getBzip2Stream(fname, append);}
+		
+		throw new RuntimeException("bz2 compression not supported in this version, unless lbzip2, pbzip2 or bzip2 is installed.");
+		
+		
+//		getBzip2Stream
+		
+//		{//comment to disable BZip2
+//			try {
+//				raw.write('B');
+//				raw.write('Z');
+//				CBZip2OutputStream out=new CBZip2OutputStream(raw, 8192);
+//				return out;
+//			} catch (IOException e) {
+//				// TODO Auto-generated catch block
+//				e.printStackTrace();
+//			}
+//			assert(false);
+//			return null;
+//		}
+	}
+	
+	public static OutputStream getDsrcOutputStream(String fname, boolean buffered, boolean append){
+		if(verbose){System.err.println("getDsrcOutputStream("+fname+", "+buffered+", "+append+")");}
+		if(RAWMODE){
+			final OutputStream raw=getRawOutputStream(fname, false, buffered);
+			return raw;
+		}
+		
+		if(USE_DSRC && Data.DSRC() /*&& (Data.SH() || fname.equals("stdout") || fname.startsWith("stdout."))*/){return getDsrcOutputStream2(fname, append);}
+		
+		throw new RuntimeException("dsrc compression requires dsrc in the path.");
+	}
+	
+	public static OutputStream getZipOutputStream(String fname, boolean buffered, boolean allowSubprocess){
+		if(verbose){System.err.println("getZipOutputStream("+fname+", "+buffered+", "+allowSubprocess+")");}
+		final OutputStream raw=getRawOutputStream(fname, false, buffered);
+		if(RAWMODE){return raw;}
+		try {
+			ZipOutputStream out=new ZipOutputStream(raw);
+			out.setLevel(Tools.min(ZIPLEVEL, 9));
+			final String basename=basename(fname);
+			out.putNextEntry(new ZipEntry(basename));
+			return out;
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		assert(false);
+		return null;
+	}
+	
+	public static OutputStream getGZipOutputStream(String fname, boolean append, boolean allowSubprocess){
+		if(verbose){System.err.println("getGZipOutputStream("+fname+", "+append+", "+allowSubprocess+"); "+USE_BGZIP+", "+USE_PIGZ+", "+USE_GZIP+", "+RAWMODE);}
+//		assert(false) : ReadWrite.ZIPLEVEL+", "+Shared.threads()+", "+MAX_ZIP_THREADS+", "+ZIP_THREAD_MULT+", "+allowSubprocess+", "+USE_PIGZ+", "+Data.PIGZ();
+		
+		if(FORCE_BGZIP && USE_BGZIP && Data.BGZIP()){return getBgzipStream(fname, append);}
+		
+		if(FORCE_PIGZ || (allowSubprocess && Shared.threads()>=2)){
+			if((fname.endsWith(".vcf.gz") || fname.endsWith(".sam.gz") || (PREFER_BGZIP && ZIPLEVEL<10)) && USE_BGZIP && Data.BGZIP()){return getBgzipStream(fname, append);}
+			if(USE_PIGZ && Data.PIGZ()){return getPigzStream(fname, append);}
+			if(USE_BGZIP && Data.BGZIP()){return getBgzipStream(fname, append);}
+			if(USE_GZIP && Data.GZIP()/* && (Data.SH() /*|| fname.equals("stdout") || fname.startsWith("stdout."))*/){return getGzipStream(fname, append);}
+		}
+		
+		final OutputStream raw=getRawOutputStream(fname, append, false);
+		if(RAWMODE){return raw;}
+		try {
+			final GZIPOutputStream out=new GZIPOutputStream(raw, 8192){
+				{
+					//					        def.setLevel(Deflater.DEFAULT_COMPRESSION);
+					def.setLevel(Tools.min(ZIPLEVEL, 9));
+				}
+			};
+			return out;
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		assert(false);
+		return null;
+	}
+	
+	public static OutputStream getPigzStream(String fname, boolean append){
+		if(verbose){System.err.println("getPigzStream("+fname+")");}
+//		System.err.println(MAX_ZIP_THREADS); //123
+		int threads=Tools.min(MAX_ZIP_THREADS, Tools.max((int)((Shared.threads()+1)*ZIP_THREAD_MULT), 1));
+//		System.err.println(threads); //123
+		threads=Tools.max(1, Tools.min(Shared.threads(), threads));
+//		System.err.println(threads); //123
+		int zl=(ZIPLEVEL<10 ? ZIPLEVEL : Data.PIGZ_VERSION_23plus ? 11 : 9);
+		if(ALLOW_ZIPLEVEL_CHANGE && threads>=4 && zl>0 && zl<4){zl=4;}
+		if(zl<3){threads=Tools.min(threads, 12);}
+		else if(zl<5){threads=Tools.min(threads, 24);}
+		else if(zl<7){threads=Tools.min(threads, 40);}
+//		System.err.println(threads); //123
+		OutputStream out;
+		String command="pigz -c -p "+threads+" -"+zl;
+		if(PIGZ_BLOCKSIZE!=128){
+			command=command+" -b "+PIGZ_BLOCKSIZE;
+		}
+		if(PIGZ_ITERATIONS>0 && Data.PIGZ_VERSION_231plus){
+			command=command+" -I "+PIGZ_ITERATIONS;
+		}
+		
+//		System.err.println("*** "+command);
+		
+		//Sample command on command line, without piping: pigz -11 -k -f -b 256 -I 25000 file.fa
+//		assert(false) : MAX_ZIP_THREADS+", "+Shared.threads()+", "+ZIP_THREAD_MULT+", "+ZIPLEVEL+", "+command;
+		out=getOutputStreamFromProcess(fname, command, true, append, true, true);
+		
+		return out;
+	}
+	
+	public static OutputStream getFqzStream(String fname){
+		if(verbose){System.err.println("getFqzStream("+fname+")");}
+		String command="fqz_comp -s"+Tools.mid(1, ZIPLEVEL, 8)+"+"; //9 gives bad compression
+		if(ZIPLEVEL>5){command=command+" -q3";}
+		//if(ZIPLEVEL>5){command=command+" -b -q3";} //b does not seem to work
+		OutputStream out=getOutputStreamFromProcess(fname, command, true, false, true, true);
+		return out;
+	}
+	
+	public static OutputStream getAlapyStream(String fname){
+		if(verbose){System.err.println("getAlapyStream("+fname+")");}
+		String compression=(ZIPLEVEL>6 ? "-l best" : ZIPLEVEL<4 ? "-l fast" : "-l medium");
+//		String compression="";
+		String command="alapy_arc "+compression+" -n "+fname+" -q -c - ";
+		OutputStream out=getOutputStreamFromProcess(fname, command, true, false, true, false);
+		return out;
+	}
+	
+	public static OutputStream getGzipStream(String fname, boolean append){
+		if(verbose){System.err.println("getGzipStream("+fname+")");}
+		OutputStream out=getOutputStreamFromProcess(fname, "gzip -c -"+Tools.min(ZIPLEVEL, 9), true, append, true, true);
+		return out;
+	}
+	
+	public static OutputStream getBgzipStream(String fname, boolean append){
+		if(verbose){System.err.println("getBgzipStream("+fname+")");}
+		
+		int threads=Tools.min(MAX_ZIP_THREADS, Tools.max((int)((Shared.threads()+1)*ZIP_THREAD_MULT), 1));
+//		System.err.println(threads); //123
+		threads=Tools.max(1, Tools.min(Shared.threads(), threads));
+//		System.err.println(threads); //123
+		int zl=Tools.mid(ZIPLEVEL, 1, 9);
+		if(ALLOW_ZIPLEVEL_CHANGE && threads>=4 && zl>0 && zl<4){zl=4;}
+		if(zl<3){threads=Tools.min(threads, 12);}
+		else if(zl<5){threads=Tools.min(threads, 16);}
+		else if(zl<7){threads=Tools.min(threads, 40);}
+		
+//		assert(false) : Data.BGZIP()+", "+Data.PIGZ();
+		String command="bgzip -c "+(append ? "" : "-f ")+(Data.BGZIP_VERSION_levelFlag ? "-l "+zl+" " : "")+(Data.BGZIP_VERSION_threadsFlag ? "-@ "+threads+" " : "");
+		if(verbose){System.err.println(command);}
+		OutputStream out=getOutputStreamFromProcess(fname, command, true, append, true, true);
+		if(verbose){System.err.println("fetched bgzip stream.");}
+		return out;
+	}
+	
+	public static OutputStream getBzip2Stream(String fname, boolean append){
+		if(verbose){System.err.println("getBzip2Stream("+fname+")");}
+		String command="bzip2 -c -"+Tools.min(BZIPLEVEL, 9);
+		OutputStream out=getOutputStreamFromProcess(fname, command, true, append, true, true);
+		return out;
+	}
+	
+	public static OutputStream getPbzip2Stream(String fname, boolean append){
+		if(verbose){System.err.println("getPbzip2Stream("+fname+")");}
+		int threads=Tools.min(MAX_ZIP_THREADS, Tools.max((int)((Shared.threads()+1)*ZIP_THREAD_MULT), 1));
+		threads=Tools.max(1, Tools.min(Shared.threads(), threads));
+		String command="pbzip2 -c -p"+threads+" -"+Tools.min(BZIPLEVEL, 9);
+		OutputStream out=getOutputStreamFromProcess(fname, command, true, append, true, true);
+		return out;
+	}
+	
+	public static OutputStream getLbzip2Stream(String fname, boolean append){
+		if(verbose){System.err.println("getLbzip2Stream("+fname+")");}
+		String command="lbzip2 -"+Tools.min(BZIPLEVEL, 9);
+		OutputStream out=getOutputStreamFromProcess(fname, command, true, append, true, true);
+		return out;
+	}
+	
+	public static OutputStream getDsrcOutputStream2(String fname, boolean append){
+		if(verbose){System.err.println("getDsrcOutpustream2("+fname+")");}
+		int threads=Tools.min(MAX_ZIP_THREADS, Tools.max((int)((Shared.threads()+1)*ZIP_THREAD_MULT), 1));
+		threads=Tools.max(1, Tools.min(Shared.threads()-1, threads));
+		String params=null;
+		if(ZIPLEVEL<=2){
+			params="-d0 -q0 -b8";
+		}else if(ZIPLEVEL<=4){
+			params="-d1 -q1 -b16";
+		}else if(ZIPLEVEL<=8){
+			params="-d2 -q2 -b32";
+		}else{
+			params="-d3 -q2 -b64";
+		}
+		String command="dsrc c -t"+threads+" "+params+" -s";
+		if(fname.equals("stdout") || fname.startsWith("stdout.")){
+			//???
+			assert(false) : "Undefined dsrc option.";
+		}else{
+			command+=" "+fname;
+		}
+		System.err.println(command);//123
+//		OutputStream out=getOutputStreamFromProcess(fname, command, true, append, true);
+		OutputStream out=getOutputStreamFromProcess(fname, command+" "+fname, true, append, true, false);
+		return out;
+	}
+	
+	public static OutputStream getOutputStreamFromProcess(final String fname, final String command, boolean sh, boolean append, boolean useProcessBuilder, boolean useFname){
+		if(verbose){System.err.println("getOutputStreamFromProcess("+fname+", "+command+", "+sh+", "+useProcessBuilder+")");}
+		
+		OutputStream out=null;
+		Process p=null;
+		if(useProcessBuilder){
+			ProcessBuilder pb=new ProcessBuilder();
+			pb.redirectError(Redirect.INHERIT);
+			
+			if(fname.equals("stdout") || fname.startsWith("stdout.")){
+				pb.redirectOutput(Redirect.INHERIT);
+				pb.command(command.split(" "));
+			}else{
+				
+				if(useFname){
+					if(append){
+						pb.redirectOutput(ProcessBuilder.Redirect.appendTo(new File(fname)));
+					}else{
+						pb.redirectOutput(new File(fname));
+					}
+				}
+				
+				pb.command(command.split(" "));
+			}
+			try {
+				p=pb.start();
+			} catch (IOException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+			assert(p!=null) : "Could not execute "+command;
+			addProcess(fname, p);
+			out=p.getOutputStream();
+			{
+				out=p.getOutputStream();
+				InputStream es=p.getErrorStream();
+				assert(es!=null);
+				PipeThread et=new PipeThread(es, System.err);
+				addPipeThread(fname, et);
+				et.start();
+			}
+			return out;
+		}
+		
+		if(fname.equals("stdout") || fname.startsWith("stdout.")){
+			try {
+				p = Runtime.getRuntime().exec(command);
+			} catch (IOException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+			assert(p!=null) : "Could not execute "+command;
+			InputStream is=p.getInputStream();
+			PipeThread it=new PipeThread(is, System.out);
+			addPipeThread(fname, it);
+			it.start();
+//		}else if(fname.equals("stderr") || fname.startsWith("stderr.")){
+//			try {
+//				p = Runtime.getRuntime().exec(command);
+//			} catch (IOException e) {
+//				// TODO Auto-generated catch block
+//				e.printStackTrace();
+//			}
+//			InputStream is=p.getErrorStream();
+//			PipeThread it=new PipeThread(is, System.err);
+//			it.start();
+		}else{
+			try {
+				if(sh){
+					String[] cmd = {
+							"sh",
+							"-c",
+							command+(useFname ? " 1"+(append ? ">>" : ">")+fname : "")
+					};
+					p=Runtime.getRuntime().exec(cmd);
+				}else{
+					//TODO: append won't work here...
+					assert(false) : command;
+					p=Runtime.getRuntime().exec(command);
+				}
+			} catch (IOException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+		assert(p!=null) : "Could not execute "+command;
+		addProcess(fname, p);
+		out=p.getOutputStream();
+		InputStream es=p.getErrorStream();
+		assert(es!=null);
+		PipeThread et=new PipeThread(es, System.err);
+		addPipeThread(fname, et);
+		et.start();
+
+		return out;
+	}
+	
+	public static String readString(String fname){
+		if(verbose){System.err.println("readString("+fname+")");}
+		String x=null;
+		InputStream is=getInputStream(fname, false, false);
+		
+		try {
+			
+			StringBuilder sb=new StringBuilder();
+			
+//			synchronized(diskSync){
+				BufferedReader in=new BufferedReader(new InputStreamReader(is), INBUF);
+				String temp=in.readLine();
+				while(temp!=null){
+					sb.append(temp).append('\n');
+					temp=in.readLine();
+				}
+				in.close();
+//			}
+			
+			x=sb.toString();
+		} catch (FileNotFoundException e) {
+			throw new RuntimeException(e);
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		} catch (OutOfMemoryError e) {
+			KillSwitch.memKill(e);
+		}
+		
+		return x;
+	}
+	
+	public static Object readObject(String fname, boolean allowSubprocess){
+		if(verbose){System.err.println("readObject("+fname+")");}
+		Object x=null;
+		InputStream is=getInputStream(fname, true, allowSubprocess);
+		
+		try {
+//			synchronized(diskSync){
+				ObjectInputStream in=new ObjectInputStream(is);
+				x=in.readObject();
+				in.close();
+//			}
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		} catch (ClassNotFoundException e) {
+			throw new RuntimeException(e);
+		} catch (OutOfMemoryError e) {
+			KillSwitch.memKill(e);
+		}
+		
+		return x;
+	}
+	
+	public static InputStream getInputStream(String fname, boolean buffer, boolean allowSubprocess){
+		if(verbose){System.err.println("getInputStream("+fname+", "+buffer+", "+allowSubprocess+")");}
+		boolean xz=fname.endsWith(".xz");
+		boolean gzipped=fname.endsWith(".gz") || fname.endsWith(".gzip");
+		boolean zipped=fname.endsWith(".zip");
+		boolean bzipped=PROCESS_BZ2 && fname.endsWith(".bz2");
+		boolean dsrced=fname.endsWith(".dsrc");
+		boolean bam=fname.endsWith(".bam") && (SAMBAMBA() || Data.SAMTOOLS());
+		boolean fqz=fname.endsWith(".fqz");
+		boolean alapy=fname.endsWith(".ac");
+		
+		allowSubprocess=(allowSubprocess && Shared.threads()>1);
+		
+		if(!RAWMODE){
+			if(zipped){return getZipInputStream(fname);}
+			if(gzipped){return getGZipInputStream(fname, allowSubprocess, false);}
+			if(bzipped){return getBZipInputStream(fname, allowSubprocess);}
+			if(dsrced){return getDsrcInputStream(fname);}
+			if(bam){
+				if(SAMBAMBA()){
+					String command="sambamba -q view -h";
+//					new Exception().printStackTrace(); //123
+					if(SAMTOOLS_IGNORE_FLAG!=0){
+						command=command+" --num-filter=0/"+SAMTOOLS_IGNORE_FLAG;
+					}
+					return getInputStreamFromProcess(fname, command, false, true, true);
+				}else{
+					String command="samtools view -h";
+//					new Exception().printStackTrace(); //123
+					if(SAMTOOLS_IGNORE_FLAG!=0){
+						//					command=command+" -F 4";
+						command=command+" -F 0x"+Integer.toHexString(SAMTOOLS_IGNORE_FLAG);
+					}
+					String version=Data.SAMTOOLS_VERSION;
+					if(Shared.threads()>1 && version!=null && version.startsWith("1.") && version.length()>2){
+						try {
+							String[] split=version.split("\\.");
+							int number=-1;
+							try {
+								number=Integer.parseInt(split[1]);
+							} catch (Exception e) {}
+							if(number<0){
+								try {
+									number=Integer.parseInt(split[1].substring(0, 1));
+								} catch (Exception e1) {}
+							}
+							if(number>3){
+								command=command+" -@ 2";
+							}
+						} catch (NumberFormatException e) {
+							// TODO Auto-generated catch block
+							e.printStackTrace();
+						}
+					}
+					//				System.err.println(command);
+					return getInputStreamFromProcess(fname, command, false, true, true);
+				}
+			}
+
+			if(fqz){return getInputStreamFromProcess(fname, "fqz_comp -d ", false, true, true);}
+			if(alapy){
+				return getInputStreamFromProcess(fname, "alapy_arc -q -d "+fname+" -", false, false, true);
+			}
+		}
+		
+		return getRawInputStream(fname, buffer);
+	}
+	
+	public static InputStream getRawInputStream(String fname, boolean buffer){
+		if(verbose){System.err.println("getRawInputStream("+fname+", "+buffer+")");}
+		
+		assert(fname!=null);
+		fname=fname.replace('\\', '/');
+		assert(fname.indexOf('\\')<0);
+		assert(!fname.contains("\\\\"));
+//		assert(!fname.contains("//")) : fname;
+		
+		final boolean jar=fname.startsWith("jar:");
+		
+		if(!jar){
+			boolean failed=false;
+			File f=new File(fname);
+			if(!f.exists()){
+				String f2=fname.toLowerCase();
+				if(f2.equals("stdin") || f2.startsWith("stdin.")){
+					//				System.err.println("Returning stdin: A");
+					return System.in;
+				}
+				
+				if(fname.indexOf('/')<0){
+					f2=Data.ROOT_CURRENT+"/"+fname;
+					if(!new File(f2).exists()){
+						failed=true;
+					}else{
+						fname=f2;
+					}
+				}else{
+					failed=true;
+				}
+			}
+//			if(failed){throw new RuntimeException("Can't find file "+fname);}
+			if(failed){
+				shared.KillSwitch.exceptionKill(new RuntimeException("Can't find file "+fname));
+			}
+		}
+		
+//		System.err.println("Getting input stream for "+fname);
+//		assert(!fname.contains("\\"));
+//		assert(!loadedFiles.contains(fname)) : "Already loaded "+fname;
+//		loadedFiles.add(fname);
+		
+		InputStream in=null;
+		if(jar){
+			try {
+				
+				URL url=new URL(fname);
+				
+				InputStream is=url.openStream();
+
+				if(buffer){
+					BufferedInputStream bis=new BufferedInputStream(is, INBUF);
+					in=bis;
+				}else{
+					in=is;
+				}
+
+			} catch (FileNotFoundException e) {
+				System.err.println("Error when attempting to read "+fname);
+				throw new RuntimeException(e);
+			} catch (MalformedURLException e) {
+				System.err.println("Error when attempting to read "+fname);
+				throw new RuntimeException(e);
+			} catch (IOException e) {
+				System.err.println("Error when attempting to read "+fname);
+				throw new RuntimeException(e);
+			}
+		}else{
+			try {
+
+				FileInputStream fis=new FileInputStream(fname);
+
+				if(buffer){
+					BufferedInputStream bis=new BufferedInputStream(fis, INBUF);
+					in=bis;
+				}else{
+					in=fis;
+				}
+
+			} catch (FileNotFoundException e) {
+				throw new RuntimeException(e);
+			}
+		}
+		
+		return in;
+	}
+	
+	public static InputStream getZipInputStream(String fname){return getZipInputStream(fname, true);}
+	public static InputStream getZipInputStream(String fname, boolean buffer){
+		if(verbose){System.err.println("getZipInputStream("+fname+", "+buffer+")");}
+		InputStream raw=getRawInputStream(fname, buffer);
+		InputStream in=null;
+
+		final String basename=basename(fname);
+
+		try {
+
+			ZipInputStream zis=new ZipInputStream(raw);
+			ZipEntry ze=zis.getNextEntry();
+			assert(ze!=null);
+			assert(basename.equals(ze.getName())) : basename+" != "+ze.getName();
+			in=zis;
+
+		} catch (FileNotFoundException e) {
+			System.err.println("Error when attempting to read "+fname);
+			throw new RuntimeException(e);
+		} catch (IOException e) {
+			System.err.println("Error when attempting to read "+fname);
+			throw new RuntimeException(e);
+		}
+
+		return in;
+	}
+	
+	public static InputStream getGZipInputStream(String fname, boolean allowSubprocess, boolean buffer){
+		if(verbose){
+			System.err.println("getGZipInputStream("+fname+", "+allowSubprocess+")");
+//			new Exception().printStackTrace(System.err);
+		}
+//		assert(!fname.contains("temp")) : fname+", "+USE_UNBGZIP+", "+allowSubprocess;
+		if(allowSubprocess && Shared.threads()>2){
+			if(!fname.startsWith("jar:")){
+				if(verbose){
+					System.err.println("Fetching gzip input stream: "+fname+", allowSubprocess="+allowSubprocess+", USE_UNPIGZ="+USE_UNPIGZ+", Data.PIGZ()="+Data.PIGZ());
+				}
+				if((PREFER_UNBGZIP || fname.endsWith(".vcf.gz")) && USE_UNBGZIP && Data.BGZIP()){
+					if(!fname.contains("stdin") && new File(fname).exists()){
+						int magicNumber=getMagicNumber(fname);
+						if(magicNumber==529205252){return getUnbgzipStream(fname);}
+//						System.err.println(magicNumber);
+					}
+				}
+				if(USE_UNPIGZ && Data.PIGZ()){return getUnpigzStream(fname);}
+//				if(USE_UNBGZIP && Data.BGZIP()){return getUnbgzipStream(fname);}
+				if(USE_GUNZIP && Data.GUNZIP()){return getGunzipStream(fname);}
+			}
+		}
+//		assert(false) : "allowSubprocess="+allowSubprocess+", Shared.threads()="+Shared.threads()+", fname="+fname+"\n"
+//				+"PREFER_UNBGZIP="+PREFER_UNBGZIP+", "+"USE_UNBGZIP="+USE_UNBGZIP+", "+"Data.BGZIP()="+Data.BGZIP()+"\n"
+//				+"USE_UNPIGZ="+USE_UNPIGZ+", "+"Data.PIGZ()="+Data.PIGZ()+"\n";
+		InputStream raw=getRawInputStream(fname, buffer);//123
+		InputStream in=null;
+		try {
+			in=new GZIPInputStream(raw, INBUF);
+		} catch (FileNotFoundException e) {
+			System.err.println("Error when attempting to read "+fname);
+			throw new RuntimeException(e);
+		} catch (IOException e) {
+			System.err.println("Error when attempting to read "+fname);
+			throw new RuntimeException(e);
+		}
+
+		return in;
+	}
+	
+	public static InputStream getGunzipStream(String fname){
+		if(verbose){System.err.println("getGunzipStream("+fname+")");}
+		return getInputStreamFromProcess(fname, "gzip -c -d", false, true, true);
+	}
+	
+	public static InputStream getUnpigzStream(String fname){
+		if(verbose){System.err.println("getUnpigzStream("+fname+")");}
+		return getInputStreamFromProcess(fname, "pigz -c -d", false, true, true);
+	}
+	
+	public static InputStream getUnbgzipStream(String fname){
+		if(verbose){System.err.println("getUnbgzipStream("+fname+")");}
+		int threads=Tools.mid(4, 1, Shared.threads());
+		return getInputStreamFromProcess(fname, "bgzip -c -d"+(Data.BGZIP_VERSION_threadsFlag ? " -@ "+threads : ""), false, true, true);
+	}
+	
+	public static InputStream getUnpbzip2Stream(String fname){
+		if(verbose){System.err.println("getUnpbzip2Stream("+fname+")");}
+		return getInputStreamFromProcess(fname, "pbzip2 -c -d", false, true, true);
+	}
+	
+	public static InputStream getUnlbzip2Stream(String fname){
+		if(verbose){System.err.println("getUnlbzip2Stream("+fname+")");}
+		return getInputStreamFromProcess(fname, "lbzip2 -c -d", false, true, true);
+	}
+	
+	public static InputStream getUnbzip2Stream(String fname){
+		if(verbose){System.err.println("getUnbzip2Stream("+fname+")");}
+		return getInputStreamFromProcess(fname, "bzip2 -c -d", false, true, true);
+	}
+	
+	public static InputStream getUnDsrcStream(String fname){
+		if(verbose){System.err.println("getUnDsrcStream("+fname+")");}
+		int threads=Tools.min(MAX_ZIP_THREADS, Tools.max((int)((Shared.threads()+1)*ZIP_THREAD_MULT), 1));
+		threads=Tools.max(1, Tools.min(Shared.threads()-1, threads));
+		return getInputStreamFromProcess(fname, "dsrc d -s -t"+threads, false, true, true);
+	}
+	
+	
+	public static InputStream getInputStreamFromProcess(final String fname, String command, boolean cat, final boolean appendFname, final boolean useProcessBuilder){
+		if(verbose){System.err.println("getInputStreamFromProcess("+fname+", "+command+", "+cat+")");}
+
+		//InputStream raw=getRawInputStream(fname, false);
+		InputStream in=null;
+		
+		Process p=null;
+		
+		if(useProcessBuilder){
+			ProcessBuilder pb=new ProcessBuilder();
+			pb.redirectError(Redirect.INHERIT);
+			
+			if(fname.equals("stdin") || fname.startsWith("stdin.")){
+				pb.redirectInput(Redirect.INHERIT);
+				pb.command(command.split(" "));
+			}else{
+				if(appendFname){
+					command=command+" "+fname;
+				}else{
+					pb.redirectInput(new File(fname));
+				}
+//				System.err.println(command+", "+appendFname);
+				pb.command(command.split(" "));
+			}
+			try {
+				p=pb.start();
+			} catch (IOException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+			assert(p!=null) : "Could not execute "+command;
+			addProcess(fname, p);
+			in=p.getInputStream();
+//			{
+//				out=p.getOutputStream();
+//				InputStream es=p.getErrorStream();
+//				assert(es!=null);
+//				PipeThread et=new PipeThread(es, System.err);
+//				addPipeThread(fname, et);
+//				et.start();
+//			}
+			return in;
+		}
+		
+		if(!appendFname){
+			try {
+				p=Runtime.getRuntime().exec(command);
+			} catch (IOException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}else if(fname.equals("stdin") || fname.startsWith("stdin.")){
+			try {
+				if(cat){
+					throw new RuntimeException();
+				}else{
+					p=Runtime.getRuntime().exec(command);
+				}
+			} catch (IOException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+			assert(p!=null) : "Could not execute "+command;
+			OutputStream os=p.getOutputStream();
+			PipeThread it=new PipeThread(System.in, os);
+			addPipeThread(fname, it);
+			it.start();
+		}else{
+			try {
+				if(cat){
+					assert(false) : "This mode is untested.";
+					String[] cmd = {
+							"sh","cat "+fname,
+							" | "+command
+					};
+					p=Runtime.getRuntime().exec(cmd);
+				}else{
+					p = Runtime.getRuntime().exec(command+" "+fname);
+				}
+			} catch (IOException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+		assert(p!=null) : "Could not execute "+command;
+		
+		addProcess(fname, p);
+		in=p.getInputStream();
+		InputStream es=p.getErrorStream();
+		assert(es!=null);
+		PipeThread et=new PipeThread(es, System.err);
+		addPipeThread(fname, et);
+		et.start();
+		
+		return in;
+	}
+	
+	
+	public static InputStream getBZipInputStream(String fname, boolean allowSubprocess){
+		if(verbose){System.err.println("getBZipInputStream("+fname+")");}
+		InputStream in=null;
+		
+		try {in=getBZipInputStream2(fname, allowSubprocess);}
+		catch (IOException e) {
+			System.err.println("Error when attempting to read "+fname);
+			throw new RuntimeException(e);
+		}catch (NullPointerException e) {
+			System.err.println("Error when attempting to read "+fname);
+			throw new RuntimeException(e);
+		}
+		
+		assert(in!=null);
+		return in;
+	}
+	
+	private static InputStream getBZipInputStream2(String fname, boolean allowSubprocess) throws IOException{
+		if(verbose){
+			if(verbose){System.err.println("getBZipInputStream("+fname+")");}
+		}
+		
+		if(!fname.startsWith("jar:")){
+			if(verbose){System.err.println("Fetching bz2 input stream: "+fname+", "+USE_PBZIP2+", "+USE_BZIP2+", "+Data.PBZIP2()+Data.BZIP2());}
+			if(USE_LBZIP2 && Data.LBZIP2()){return getUnlbzip2Stream(fname);}
+			if(USE_PBZIP2 && Data.PBZIP2()){return getUnpbzip2Stream(fname);}
+			if(USE_BZIP2 && Data.BZIP2()){return getUnbzip2Stream(fname);}
+		}
+		
+		throw new IOException("\nlbzip2, pbzip2, or bzip2 must be in the path to read bz2 files:\n"+fname+"\n");
+	}
+	
+	public static InputStream getDsrcInputStream(String fname){
+		if(verbose){System.err.println("getDsrcInputStream("+fname+")");}
+		InputStream in=null;
+		
+		try {in=getDsrcInputStream2(fname);}
+		catch (IOException e) {
+			System.err.println("Error when attempting to read "+fname);
+			throw new RuntimeException(e);
+		}catch (NullPointerException e) {
+			System.err.println("Error when attempting to read "+fname);
+			throw new RuntimeException(e);
+		}
+		
+		assert(in!=null);
+		return in;
+	}
+	
+	private static InputStream getDsrcInputStream2(String fname) throws IOException{
+		if(verbose){
+			if(verbose){System.err.println("getDsrcInputStream2("+fname+")");}
+		}
+		
+		if(USE_DSRC && Data.DSRC()){return getUnDsrcStream(fname);}
+		
+		throw new IOException("\nDsrc must be in the path to read Dsrc files:\n"+fname+"\n");
+	}
+	
+	public static InputStream getXZInputStream(String fname){
+		
+		InputStream in=null;
+		
+//		if(PROCESS_XZ){
+//			InputStream raw=getRawInputStream(fname, true);
+//			try {
+//				in=new org.tukaani.xz.XZInputStream(raw);
+//			} catch (FileNotFoundException e) {
+//				throw new RuntimeException(e);
+//			} catch (IOException e) {
+//				throw new RuntimeException(e);
+//			}
+//		}
+
+		return in;
+	}
+
+	public static byte[] readRaw(String fname) throws IOException{
+		InputStream ris=getRawInputStream(fname, false);
+		ByteBuilder bb=new ByteBuilder();
+		byte[] buffer=new byte[16384];
+		int x=ris.read(buffer);
+		while(x>0){
+			bb.append(buffer, x);
+			x=ris.read(buffer);
+		}
+		ris.close();
+		return bb.toBytes();
+	}
+	
+	public static <X> X read(Class<X> cx, String fname, boolean allowSubprocess){
+		X x=(X)readObject(fname, allowSubprocess);
+		return x;
+	}
+	
+	public static <X> X[] readArray(Class<X> cx, String fname, boolean allowSubprocess){
+		X[] x=(X[])readObject(fname, allowSubprocess);
+		return x;
+	}
+	
+	public static <X> X[][] readArray2(Class<X> cx, String fname, boolean allowSubprocess){
+		X[][] x=(X[][])readObject(fname, allowSubprocess);
+		return x;
+	}
+	
+	public static <X> X[][][] readArray3(Class<X> cx, String fname, boolean allowSubprocess){
+		X[][][] x=(X[][][])readObject(fname, allowSubprocess);
+		return x;
+	}
+	
+	
+	public static String basename(String fname){
+		fname=fname.replace('\\', '/');
+		boolean xz=fname.endsWith(".xz");
+		boolean gzipped=fname.endsWith(".gz");
+		boolean zipped=fname.endsWith(".zip");
+		boolean bzipped=PROCESS_BZ2 && fname.endsWith(".bz2");
+		boolean dsrced=fname.endsWith(".dsrc");
+		String basename=fname;
+//		if(basename.contains("\\")){basename=basename.substring(basename.lastIndexOf("\\")+1);}
+		if(basename.contains("/")){basename=basename.substring(basename.lastIndexOf('/')+1);}
+		if(zipped || bzipped){basename=basename.substring(0, basename.length()-4);}
+		else if(gzipped){basename=basename.substring(0, basename.length()-3);}
+		else if(dsrced){basename=basename.substring(0, basename.length()-5);}
+		return basename;
+	}
+	
+	public static String rawName(String fname){
+		for(String s : compressedExtensions){
+			while(fname.endsWith(s)){fname=fname.substring(0, fname.length()-s.length());}
+		}
+		return fname;
+	}
+	
+	/** 
+	 * Returns the path without the file extension.
+	 * Only strips known extensions. */
+	public static String stripExtension(String fname){
+		if(fname==null){return null;}
+		for(String ext : FileFormat.EXTENSION_LIST){
+			String s="."+ext;
+			if(fname.endsWith(s)){return stripExtension(fname.substring(0, fname.length()-s.length()));}
+		}
+		return fname;
+	}
+	
+	/** Returns the whole extension, include compression and raw type */
+	public static String getExtension(String fname){
+		if(fname==null){return null;}
+		String stripped=stripExtension(fname);
+		if(stripped==null){return fname;}
+		if(stripped.length()==fname.length()){return "";}
+		return fname.substring(stripped.length());
+	}
+	
+	public static String stripToCore(String fname){
+		fname=stripPath(fname);
+		return stripExtension(fname);
+	}
+	
+	/**
+	 * Strips the directories, leaving only a filename
+	 * @param fname
+	 * @return File name without directories
+	 */
+	public static String stripPath(String fname){
+		if(fname==null){return null;}
+		fname=fname.replace('\\', '/');
+		int idx=fname.lastIndexOf('/');
+		if(idx>=0){fname=fname.substring(idx+1);}
+		return fname;
+	}
+	
+	public static String getPath(String fname){
+		if(fname==null){return null;}
+		fname=fname.replace('\\', '/');
+		int idx=fname.lastIndexOf('/');
+		if(idx>=0){return fname.substring(0, idx+1);}
+		return "";
+	}
+	
+	public static String compressionType(String fname){
+		fname=fname.toLowerCase(Locale.ENGLISH);
+		for(int i=0; i<compressedExtensions.length; i++){
+			if(fname.endsWith(compressedExtensions[i])){return compressedExtensionMap[i];}
+		}
+		return null;
+	}
+	
+	public static boolean isCompressed(String fname){
+		return compressionType(fname)!=null;
+	}
+	
+	public static boolean isSam(String fname){
+		fname=fname.toLowerCase(Locale.ENGLISH);
+		if(fname.endsWith(".sam")){return true;}
+		String s=compressionType(fname);
+		if(s==null){return false;}
+		return fname.substring(0, fname.lastIndexOf('.')).endsWith(".sam");
+	}
+	
+	/** Returns extension, lower-case, without a period */ 
+	public static String rawExtension(String fname){
+		fname=rawName(fname);
+		int x=fname.lastIndexOf('.');
+		//if(x<0){return "";}
+		return fname.substring(x+1).toLowerCase(Locale.ENGLISH);
+	}
+	
+	public static String parseRoot(String path){
+		File f=new File(path);
+		if(f.isDirectory()){
+			if(!path.endsWith(FILESEP)){
+				path=path+FILESEP;
+			}
+			return path;
+		}else if(f.isFile()){
+			int slash=path.lastIndexOf(FILESEP);
+			if(slash<0){
+				return "";
+			}else{
+				return path.substring(0, slash+1);
+			}
+		}else{
+			throw new RuntimeException("Can't find "+path); //Try using parseRoot2 instead.
+		}
+	}
+	
+	/** This one does not throw an exception for non-existing paths */
+	public static String parseRoot2(String path){
+		File f=new File(path);
+		
+		if(!f.exists()){
+			if(path.endsWith(FILESEP)){return path;}
+			int slash=path.lastIndexOf(FILESEP);
+			if(slash<0){
+				return "";
+			}else{
+				return path.substring(0, slash+1);
+			}
+		}
+		
+		if(f.isDirectory()){
+			if(!path.endsWith(FILESEP)){
+				path=path+FILESEP;
+			}
+			return path;
+		}else if(f.isFile()){
+			int slash=path.lastIndexOf(FILESEP);
+			if(slash<0){
+				return "";
+			}else{
+				return path.substring(0, slash+1);
+			}
+		}else{
+			throw new RuntimeException("Can't find "+path);
+		}
+	}
+	
+	public static String findFileExtension(final String fname){
+
+		File file=new File(fname);
+		if(file.exists()){return fname;}
+
+		String basename=fname, temp;
+		if(fname.endsWith(".zip") || fname.endsWith(".gz") || (PROCESS_BZ2 && fname.endsWith(".bz2")) || (PROCESS_XZ && fname.endsWith(".xz"))){
+			basename=fname.substring(0, fname.lastIndexOf('.'));
+		}
+		temp=basename;
+		file=new File(temp);
+		if(!file.exists()){
+			temp=basename+".gz";
+			file=new File(temp);
+		}
+//		System.err.println(temp+" "+(file.exists() ? " exists" : " does not exist"));
+		if(!file.exists()){
+			temp=basename+".zip";
+			file=new File(temp);
+		}
+//		System.err.println(temp+" "+(file.exists() ? " exists" : " does not exist"));
+		if(!file.exists() && PROCESS_BZ2){
+			temp=basename+".bz2";
+			file=new File(temp);
+		}
+//		System.err.println(temp+" "+(file.exists() ? " exists" : " does not exist"));
+		if(!file.exists() && PROCESS_XZ){
+			temp=basename+".xz";
+			file=new File(temp);
+		}
+//		System.err.println(temp+" "+(file.exists() ? " exists" : " does not exist"));
+		if(!file.exists()){temp=fname;}
+		
+		return temp;
+	}
+	
+	/**
+	 * Delete a file.
+	 */
+	public static boolean delete(String path, boolean verbose){
+		if(path==null){return false;}
+		if(verbose){System.err.println("Trying to delete "+path);}
+		File f=new File(path);
+		if(f.exists()){
+			try {
+				f.delete();
+				return true;
+			} catch (Exception e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+		return false;
+	}
+	
+	public static synchronized void copyFile(String source, String dest){copyFile(source, dest, false);}
+	public static synchronized void copyFile(String source, String dest, boolean createPathIfNeeded){
+		
+		assert(!new File(dest).exists()) : "Destination file already exists: "+dest;
+		if(createPathIfNeeded){
+			File parent=new File(dest).getParentFile();
+			if(parent!=null && !parent.exists()){
+				parent.mkdirs();
+			}
+		}
+		
+		final boolean oldRawmode=RAWMODE;
+		if((source.endsWith(".zip") && dest.endsWith(".zip"))
+				 || (source.endsWith(".gz") && dest.endsWith(".gz")
+						 || (source.endsWith(".bz2") && dest.endsWith(".bz2"))
+						 || (source.endsWith(".xz") && dest.endsWith(".xz")))){
+			RAWMODE=true;
+		}
+		
+		try{
+			InputStream in=getInputStream(source, false, false);
+			OutputStream out=getOutputStream(dest, false, false, true);
+
+			byte[] buffer=new byte[INBUF];
+			int len;
+			
+			while((len = in.read(buffer)) > 0){
+				out.write(buffer, 0, len);
+			}
+			
+			in.close();
+			out.flush();
+			if(out.getClass()==ZipOutputStream.class){
+				ZipOutputStream zos=(ZipOutputStream)out;
+				zos.closeEntry();
+				zos.finish();
+			}
+//			else if(PROCESS_XZ && out.getClass()==org.tukaani.xz.XZOutputStream.class){
+//				org.tukaani.xz.XZOutputStream zos=(org.tukaani.xz.XZOutputStream)out;
+//				zos.finish();
+//			}
+			out.close();
+			
+		}catch(FileNotFoundException e){
+			RAWMODE=oldRawmode;
+			throw new RuntimeException(e);
+		}catch(IOException e){
+			RAWMODE=oldRawmode;
+			throw new RuntimeException(e);
+		}
+		
+		RAWMODE=oldRawmode;
+	}
+	
+	public static void copyDirectoryContents(String from, String to){
+		assert(!from.equalsIgnoreCase(to));
+		
+		if(to.indexOf('\\')>0){to=to.replace('\\', '/');}
+		
+		File d1=new File(from);
+		assert(d1.exists());
+		assert(d1.isDirectory());
+		
+		File d2=new File(to);
+		assert(!d1.equals(d2));
+		if(d2.exists()){
+			assert(d2.isDirectory());
+		}else{
+			d2.mkdirs();
+		}
+		if(!to.endsWith("/")){to=to+"/";}
+		
+		File[] array=d1.listFiles();
+		
+		for(File f : array){
+			String name=f.getName();
+			String dest=to+name;
+			if(f.isFile()){
+				copyFile(f.getAbsolutePath(), dest);
+			}else{
+				assert(f.isDirectory());
+				File f2=new File(dest);
+				if(!f2.exists()){
+					f2.mkdir();
+				}else{
+					assert(f2.isDirectory());
+				}
+				copyDirectoryContents(f.getAbsolutePath(), f2.getAbsolutePath());
+			}
+		}
+		
+	}
+	
+	
+	static final int addThread(int x){
+		if(verbose){System.err.println("addThread("+x+")");}
+		synchronized(activeThreads){
+			assert(x!=0);
+			if(x>0){
+				activeThreads[0]+=x;
+				activeThreads[1]+=x;
+			}else{
+				addRunningThread(x);
+			}
+			assert(activeThreads[0]==(activeThreads[1]+activeThreads[2]) && activeThreads[0]>=0 && activeThreads[1]>=0 &&
+					activeThreads[2]>=0 && activeThreads[2]<=maxWriteThreads) : Arrays.toString(activeThreads);
+					
+			return activeThreads[0];
+		}
+	}
+	
+	static final int addRunningThread(int x){
+		if(verbose){System.err.println("addRunningThread("+x+")");}
+		final int max=(Shared.LOW_MEMORY ? 1 : maxWriteThreads);
+		synchronized(activeThreads){
+			assert(x!=0);
+			if(x>0){
+				assert(activeThreads[1]>=x);
+				while(activeThreads[2]>=max){
+					try {
+						activeThreads.wait();
+					} catch (InterruptedException e) {
+						// TODO Auto-generated catch block
+						e.printStackTrace();
+					}
+				}
+				activeThreads[1]-=x; //Remove from waiting
+			}else{
+				activeThreads[0]+=x; //Remove from active
+			}
+			activeThreads[2]+=x; //Change number running
+			
+			assert(activeThreads[0]==(activeThreads[1]+activeThreads[2]) && activeThreads[0]>=0 && activeThreads[1]>=0 &&
+					activeThreads[2]>=0 && activeThreads[2]<=max) : Arrays.toString(activeThreads);
+			
+			if(activeThreads[2]==0 || (activeThreads[2]<max && activeThreads[1]>0)){activeThreads.notify();}
+			return activeThreads[2];
+		}
+	}
+	
+	public static final int countActiveThreads(){
+		if(verbose){System.err.println("countActiveThreads()");}
+		synchronized(activeThreads){
+			assert(activeThreads[0]==(activeThreads[1]+activeThreads[2]) && activeThreads[0]>=0 && activeThreads[1]>=0 &&
+					activeThreads[2]>=0 && activeThreads[2]<=maxWriteThreads) : Arrays.toString(activeThreads);
+			return activeThreads[0];
+		}
+	}
+	
+	public static final void waitForWritingToFinish(){
+		if(verbose){System.err.println("waitForWritingToFinish()");}
+		synchronized(activeThreads){
+			while(activeThreads[0]>0){
+				assert(activeThreads[0]==(activeThreads[1]+activeThreads[2]) && activeThreads[0]>=0 && activeThreads[1]>=0 &&
+						activeThreads[2]>=0 && activeThreads[2]<=maxWriteThreads) : Arrays.toString(activeThreads);
+				try {
+					activeThreads.wait(8000);
+				} catch (InterruptedException e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+				if(activeThreads[2]==0 || (activeThreads[2]<maxWriteThreads && activeThreads[1]>0)){activeThreads.notify();}
+			}
+		}
+	}
+
+	
+	public static final boolean closeStream(ConcurrentReadStreamInterface cris){return closeStreams(cris, (ConcurrentReadOutputStream[])null);}
+	public static final boolean closeStream(ConcurrentReadOutputStream ross){return closeStreams((ConcurrentReadStreamInterface)null, ross);}
+	public static final boolean closeOutputStreams(ConcurrentReadOutputStream...ross){return closeStreams(null, ross);}
+
+	public static final boolean closeStreams(MultiCros mc){
+		if(mc==null){return false;}
+		return closeStreams(null, mc.streamList.toArray(new ConcurrentReadOutputStream[0]));
+	}
+	
+	/** 
+	 * Close these streams and wait for them to finish.
+	 * @param cris An input stream.  May be null.
+	 * @param ross Zero or more output streams.
+	 * @return True if an error was encountered.
+	 */
+	public static final boolean closeStreams(ConcurrentReadStreamInterface cris, ConcurrentReadOutputStream...ross){
+		if(verbose){
+			System.err.println("closeStreams("+cris+", "+(ross==null ? "null" : ross.length)+")");
+			new Exception().printStackTrace(System.err);
+		}
+		boolean errorState=false;
+		if(cris!=null){
+			if(verbose){System.err.println("Closing cris; error="+errorState);}
+			cris.close();
+			errorState|=cris.errorState();
+//			Object[] prods=cris.producers();
+//			for(Object o : prods){
+//				if(o!=null && o.getClass()==ReadInputStream.class){
+//					ReadInputStream ris=(ReadInputStream)o;
+//					ris.
+//				}
+//			}
+			if(verbose){System.err.println("Closed cris; error="+errorState);}
+		}
+		if(ross!=null){
+			for(ConcurrentReadOutputStream ros : ross){
+				if(ros!=null){
+					if(verbose){System.err.println("Closing ros "+ros+"; error="+errorState);}
+					ros.close();
+					ros.join();
+					errorState|=(ros.errorState() || !ros.finishedSuccessfully());
+					if(verbose){System.err.println("Closed ros; error="+errorState);}
+				}
+			}
+		}
+		return errorState;
+	}
+	
+	public static boolean killProcess(String fname){
+		if(verbose){
+			System.err.println("killProcess("+fname+")");
+			new Exception().printStackTrace(System.err);
+			System.err.println("processMap before: "+processMap.keySet());
+		}
+		if(fname==null || (!isCompressed(fname) && !fname.endsWith(".bam") && !FORCE_KILL)){return false;}
+		
+		boolean error=false;
+		synchronized(processMap){
+			Process p=processMap.remove(fname);
+			if(p!=null){
+				if(verbose){System.err.println("Found Process for "+fname);}
+				int x=-1, tries=0;
+				for(; tries<20; tries++){
+					if(verbose){System.err.println("Trying p.waitFor()");}
+					try {
+//						long t=System.nanoTime();
+//						Thread.sleep(4000);
+						if(verbose){System.err.println("p.isAlive()="+p.isAlive());}
+						x=p.waitFor();
+//						if(verbose){System.err.println(System.nanoTime()-t+" ns");}
+						if(verbose){System.err.println("success; return="+x);}
+						break;
+					} catch (InterruptedException e) {
+						if(verbose){System.err.println("Failed.");}
+						e.printStackTrace();
+					}
+				}
+				error|=(tries>=20 || (x!=0 && x!=141));//141 is sigpipe and appears to be OK when forcibly closing a pipe.
+				if(verbose){System.err.println("killProcess("+fname+") returned "+error+"; tries="+tries+", code="+x);}
+				if(tries>=20){
+					if(verbose){System.err.println("Calling p.destroy because tries=="+tries+"; error="+error);}
+					p.destroy();
+					if(verbose){System.err.println("destroyed");}
+				}
+			}else{
+				if(verbose){System.err.println("WARNING: Could not find process for "+fname);}
+			}
+			if(verbose){
+				System.err.println("processMap after: "+processMap.keySet());
+			}
+		}
+		synchronized(pipeThreadMap){
+			if(verbose){System.err.println("pipeMap before: "+processMap.keySet());}
+			ArrayList<PipeThread> atp=pipeThreadMap.remove(fname);
+			if(atp!=null){
+				for(PipeThread p : atp){
+					if(p!=null){
+						if(verbose){System.err.println("Found PipeThread for "+fname);}
+						p.terminate();
+						if(verbose){System.err.println("Terminated PipeThread");}
+					}else{
+						if(verbose){System.err.println("WARNING: Could not find process for "+fname);}
+					}
+				}
+			}
+			if(verbose){System.err.println("pipeMap after: "+processMap.keySet());}
+		}
+		if(verbose){System.err.println("killProcess("+fname+") returned "+error);}
+		return error;
+	}
+	
+	private static void addProcess(String fname, Process p){
+		if(verbose){
+			System.err.println("addProcess("+fname+", "+p+")");
+			new Exception().printStackTrace();
+		}
+		synchronized(processMap){
+			Process old=processMap.put(fname, p);
+			if(old!=null){
+				old.destroy();
+//				throw new RuntimeException("Duplicate process for file "+fname);
+				KillSwitch.kill("Duplicate process for file "+fname);
+			}
+		}
+	}
+	
+	private static void addPipeThread(String fname, PipeThread pt){
+		if(verbose){System.err.println("addPipeThread("+fname+", "+pt+")");}
+		synchronized(pipeThreadMap){
+//			System.err.println("Adding PipeThread for "+fname);
+			ArrayList<PipeThread> atp=pipeThreadMap.get(fname);
+			if(atp==null){
+				atp=new ArrayList<PipeThread>(2);
+				pipeThreadMap.put(fname, atp);
+			}
+			atp.add(pt);
+		}
+	}
+
+	/** 
+	 * Note:
+	 * Magic number of bgzip files is (first 4 bytes):
+	 * 1f 8b 08 04
+	 * 31 139 8 4
+	 *  = 529205252
+	 * 
+	 * gzip/pigz:
+	 * 1f 8b 08 00
+	 * 31 139 8 0
+	 *  = 529205248
+	 * 
+	 * od --format=x1 --read-bytes=16 names.txt_gzip.gz
+	 */
+	public static int getMagicNumber(String fname) {
+		InputStream is=null;
+		try {
+			FileInputStream fis=new FileInputStream(fname);
+			is=new BufferedInputStream(fis); 
+		} catch (FileNotFoundException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		
+		//This is fine but uses Java11 methods
+//		byte[] array=new byte[4];
+//		int read=0;
+//		try {
+////			read=is.readNBytes(array, 0, 4);
+//			read=is.readNBytes(array, 0, 4);
+//		} catch (IOException e) {
+//			// TODO Auto-generated catch block
+//			e.printStackTrace();
+//		}
+//		assert(read==4) : read;
+//		int x=0;
+//		for(int i=0; i<read; i++){
+//			int b=((int)array[i])&255;
+//			x=(x<<8)|b;
+//		}
+		
+		int x=0;
+		for(int i=0; i<4; i++){
+			try {
+				x=(x<<8)|(is.read()&255);
+			} catch (IOException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+		
+		return x;
+	}
+	
+	/** {active, waiting, running} <br>
+	 * Active means running or waiting.
+	 */
+	public static int[] activeThreads={0, 0, 0};
+	public static int maxWriteThreads=Shared.threads();
+	
+	public static boolean verbose=false;
+	
+	public static boolean RAWMODE=false; //Does not automatically compress and decompress when true
+
+	//For killing subprocesses that are neither compression nor samtools
+	public static boolean FORCE_KILL=false;
+
+	public static boolean USE_GZIP=false;
+	public static boolean USE_BGZIP=true;
+	public static boolean USE_PIGZ=true;
+	public static boolean USE_GUNZIP=false;
+	public static boolean USE_UNBGZIP=true;
+	public static boolean USE_UNPIGZ=true;
+	
+	public static boolean FORCE_PIGZ=false;
+	public static boolean FORCE_BGZIP=false;
+	
+	public static boolean PREFER_BGZIP=true;
+	public static boolean PREFER_UNBGZIP=true;
+	
+	public static boolean USE_BZIP2=true;
+	public static boolean USE_PBZIP2=true;
+	public static boolean USE_LBZIP2=true;
+	public static boolean USE_DSRC=true;
+	public static boolean USE_FQZ=true;
+	public static boolean USE_ALAPY=true;
+	public static boolean USE_SAMBAMBA=true;
+	public static boolean SAMBAMBA(){return USE_SAMBAMBA && Data.SAMBAMBA();}
+	
+//	public static boolean SAMTOOLS_IGNORE_UNMAPPED_INPUT=false;
+	public static int SAMTOOLS_IGNORE_FLAG=0;
+	public static final int SAM_UNMAPPED=0x4;
+	public static final int SAM_DUPLICATE=0x400;
+	public static final int SAM_SUPPLIMENTARY=0x800;
+	public static final int SAM_SECONDARY=0x100;
+	public static final int SAM_QFAIL=0x200;
+	
+	public static boolean PROCESS_BZ2=true;
+	public static final boolean PROCESS_XZ=false;
+	
+	public static final int INBUF=16384;
+	public static final int OUTBUF=16384;
+
+	/** Gzip compression level */
+	public static int ZIPLEVEL=4;
+	/** Bzip2 compression level */
+	public static int BZIPLEVEL=9;
+	public static int MAX_ZIP_THREADS=96;
+	public static int MAX_SAMTOOLS_THREADS=64;
+	public static int PIGZ_BLOCKSIZE=128;
+	public static int PIGZ_ITERATIONS=-1;
+	
+	public static void setZipThreadMult(float x){
+		ZIP_THREAD_MULT=Tools.min(1, Tools.max(0.125f, x));
+	}
+	public static float ZIP_THREAD_MULT=1f;
+	public static boolean ALLOW_ZIPLEVEL_CHANGE=true;
+	
+	public static final String FILESEP=System.getProperty("file.separator");
+
+	private static final String diskSync=new String("DISKSYNC");
+	
+	public static final HashSet<String> loadedFiles=new HashSet<String>();
+
+	private static final String[] compressedExtensions=new String[] {".gz", ".gzip", ".zip", ".bz2", ".xz", ".dsrc", ".fqz", ".ac"};
+	private static final String[] compressedExtensionMap=new String[] {"gz", "gz", "zip", "bz2", "xz", "dsrc", "fqz", "ac"};
+
+//	private static HashMap<String, Process> inputProcesses=new HashMap<String, Process>(8);
+//	private static HashMap<String, Process> outputProcesses=new HashMap<String, Process>(8);
+	private static HashMap<String, Process> processMap=new HashMap<String, Process>(8);
+	private static HashMap<String, ArrayList<PipeThread>> pipeThreadMap=new HashMap<String, ArrayList<PipeThread>>(8);
+	
+}