// Path: src/org/ohdsi/utilities/RandomUtilities.java
// public class RandomUtilities {
// 	public static <T> List<T> sampleWithoutReplacement(List<T> items, int sampleSize) {
// 		if (sampleSize > items.size()) {
// 			return items;
// 		}
// 		Random random = new Random();
// 		List<T> sample = new ArrayList<T>();
// 		for (int i = 0; i < sampleSize; i++)
// 			sample.add(items.remove(random.nextInt(items.size())));
// 		return sample;
// 	}
// 	
// 	public static int[] sampleWithoutReplacement(int minValue, int maxValue, int sampleSize) {
// 		if (sampleSize > (maxValue - minValue + 1)) {
// 			int[] sample = new int[maxValue - minValue + 1];
// 			for (int i = minValue; i <= maxValue; i++)
// 				sample[i - minValue] = i;
// 			return sample;
// 		} else {
// 			Random random = new Random();
// 			int[] sample = new int[sampleSize];
// 			for (int i = 0; i < sampleSize; i++) {
// 				int number = random.nextInt(maxValue - minValue + 1);
// 				while (contains(sample, number))
// 					number = random.nextInt(maxValue - minValue + 1);
// 				sample[i] = number;
// 			}
// 			return sample;
// 		}
// 		
// 	}
// 	
// 	private static boolean contains(int[] sample, int number) {
// 		for (int i : sample)
// 			if (i == number)
// 				return true;
// 		return false;
// 	}
// 	
// }
// 
// Path: src/org/ohdsi/utilities/concurrency/BatchProcessingThread.java
// public abstract class BatchProcessingThread extends Thread {
// 	private final Semaphore newInputSemaphore = new Semaphore();
// 	private final Semaphore newOutputSemaphore = new Semaphore();
// 	private boolean terminated = false;
// 
// 	public BatchProcessingThread(){
// 		super();
// 		this.start();
// 
// 	}
// 	
// 	public void run(){
// 		while (true){
// 			newInputSemaphore.release();
// 			if (terminated)
// 				break;
// 			process();
// 			newOutputSemaphore.take();
// 		}
// 	}
// 
// 	protected abstract void process();
// 
// 	public void proceed(){ //This method will be run in the other thread!
// 		newInputSemaphore.take();
// 	}
// 
// 	public void waitUntilFinished(){ //Runs in other thread!
// 		newOutputSemaphore.release();
// 	}
// 
// 	public synchronized void terminate(){//Runs in other thread!
// 		terminated = true;
// 		newInputSemaphore.take();
// 	}
// 
// 
// }


import org.ohdsi.utilities.RandomUtilities;
import org.ohdsi.utilities.concurrency.BatchProcessingThread;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.zip.GZIPInputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

			decompressAndParseThread.startProcessing(fileIterator.next());
		else {
			hasNext = false;
			decompressAndParseThread.terminate();
		}
	}
	
	@Override
	public boolean hasNext() {
		return hasNext;
	}
	
	@Override
	public Document next() {
		decompressAndParseThread.waitUntilFinished();
		Document document = decompressAndParseThread.getDocument();
		if (fileIterator.hasNext())
			decompressAndParseThread.startProcessing(fileIterator.next());
		else {
			hasNext = false;
			decompressAndParseThread.terminate();
		}
		return document;
	}
	
	@Override
	public void remove() {
		throw new RuntimeException("Calling unimplemented method remove in " + this.getClass().getName());
	}
	

// Path: src/org/ohdsi/utilities/RandomUtilities.java
// public class RandomUtilities {
// 	public static <T> List<T> sampleWithoutReplacement(List<T> items, int sampleSize) {
// 		if (sampleSize > items.size()) {
// 			return items;
// 		}
// 		Random random = new Random();
// 		List<T> sample = new ArrayList<T>();
// 		for (int i = 0; i < sampleSize; i++)
// 			sample.add(items.remove(random.nextInt(items.size())));
// 		return sample;
// 	}
// 	
// 	public static int[] sampleWithoutReplacement(int minValue, int maxValue, int sampleSize) {
// 		if (sampleSize > (maxValue - minValue + 1)) {
// 			int[] sample = new int[maxValue - minValue + 1];
// 			for (int i = minValue; i <= maxValue; i++)
// 				sample[i - minValue] = i;
// 			return sample;
// 		} else {
// 			Random random = new Random();
// 			int[] sample = new int[sampleSize];
// 			for (int i = 0; i < sampleSize; i++) {
// 				int number = random.nextInt(maxValue - minValue + 1);
// 				while (contains(sample, number))
// 					number = random.nextInt(maxValue - minValue + 1);
// 				sample[i] = number;
// 			}
// 			return sample;
// 		}
// 		
// 	}
// 	
// 	private static boolean contains(int[] sample, int number) {
// 		for (int i : sample)
// 			if (i == number)
// 				return true;
// 		return false;
// 	}
// 	
// }
// 
// Path: src/org/ohdsi/utilities/concurrency/BatchProcessingThread.java
// public abstract class BatchProcessingThread extends Thread {
// 	private final Semaphore newInputSemaphore = new Semaphore();
// 	private final Semaphore newOutputSemaphore = new Semaphore();
// 	private boolean terminated = false;
// 
// 	public BatchProcessingThread(){
// 		super();
// 		this.start();
// 
// 	}
// 	
// 	public void run(){
// 		while (true){
// 			newInputSemaphore.release();
// 			if (terminated)
// 				break;
// 			process();
// 			newOutputSemaphore.take();
// 		}
// 	}
// 
// 	protected abstract void process();
// 
// 	public void proceed(){ //This method will be run in the other thread!
// 		newInputSemaphore.take();
// 	}
// 
// 	public void waitUntilFinished(){ //Runs in other thread!
// 		newOutputSemaphore.release();
// 	}
// 
// 	public synchronized void terminate(){//Runs in other thread!
// 		terminated = true;
// 		newInputSemaphore.take();
// 	}
// 
// 
// }


// Path: src/org/ohdsi/medlineXmlToDatabase/XMLFileIterator.java
import org.ohdsi.utilities.RandomUtilities;
import org.ohdsi.utilities.concurrency.BatchProcessingThread;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.zip.GZIPInputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

			decompressAndParseThread.startProcessing(fileIterator.next());
		else {
			hasNext = false;
			decompressAndParseThread.terminate();
		}
	}
	
	@Override
	public boolean hasNext() {
		return hasNext;
	}
	
	@Override
	public Document next() {
		decompressAndParseThread.waitUntilFinished();
		Document document = decompressAndParseThread.getDocument();
		if (fileIterator.hasNext())
			decompressAndParseThread.startProcessing(fileIterator.next());
		else {
			hasNext = false;
			decompressAndParseThread.terminate();
		}
		return document;
	}
	
	@Override
	public void remove() {
		throw new RuntimeException("Calling unimplemented method remove in " + this.getClass().getName());
	}
	

	private class DecompressAndParseThread extends BatchProcessingThread {
