src/main/java/edu/isi/bmkeg/lapdf/model/factory/AbstractModelFactory.java
public interface AbstractModelFactory {

	public ChunkBlock createChunkBlock(int topX, int topY, int bottomX,
			int bottomY);

	public WordBlock createWordBlock(int topX, int topY, int bottomX,
			int bottomY, int spaceWidth, String font, String style, String word);

	public PageBlock createPageBlock(int pageNumber, int pageHeight,
			int pageWidth, LapdfDocument document);

}
src/main/java/edu/isi/bmkeg/lapdf/model/Block.java
public interface Block extends Serializable {

	public static final String MIDLINE = "MIDLINE";
	public static final String LEFT = "LEFT";
	public static final String RIGHT = "RIGHT";
	
    public static final String TYPE_TITLE="title"; 
    public static final String TYPE_AUTHORS="authors"; 
	public static final String TYPE_BODY = "body";
	public static final String TYPE_HEADING = "heading";

	public static final String TYPE_ABSTRACT="abstract";
	public static final String TYPE_ABSTRACT_HEADING="abstract.heading";
    public static final String TYPE_ABSTRACT_BODY="abstract.body";	
	
    public static final String TYPE_FIGURE_LEGEND="figureLegend";    
    public static final String TYPE_TABLE="table";
    
	public static final String TYPE_UNCLASSIFIED="unclassified";
	public static final String TYPE_PAGE="page";
	
	public static final String TYPE_METHODS="methods";
	public static final String TYPE_METHODS_HEADING="methods.heading";
	public static final String TYPE_METHODS_BODY="methods.body";
	public static final String TYPE_METHODS_SUBTITLE="methods.subtitle";
	
	public static final String TYPE_RESULTS="results";
	public static final String TYPE_RESULTS_HEADING="results.heading";
	public static final String TYPE_RESULTS_BODY="results.body";
	public static final String TYPE_RESULTS_SUBTITLE="results.subtitle";
	
	public static final String TYPE_REFERENCES="references";
	public static final String TYPE_REFERENCES_HEADING="references.heading";
	public static final String TYPE_REFERENCES_BODY="references.body";
	
	public static final String TYPE_DISCUSSION="discussion";
	public static final String TYPE_DISCUSSION_HEADING="discussion.heading";
	public static final String TYPE_DISCUSSION_BODY="discussion.body";
	public static final String TYPE_DISCUSSION_SUBTITLE="discussion.subtitle";
	
	public static final String TYPE_CONCLUSIONS="conclusions";
	public static final String TYPE_CONCLUSIONS_HEADING="conclusions.heading";
	public static final String TYPE_CONCLUSIONS_BODY="conclusions.body";
	public static final String TYPE_CONCLUSIONS_SUBTITLE="conclusions.subtitle";
	
	public static final String TYPE_ACKNOWLEDGEMENTS="acknowledgements";
	public static final String TYPE_ACKNOWLEDGEMENTS_HEADING="acknowledgements.heading";
	public static final String TYPE_ACKNOWLEDGEMENTS_BODY="acknowledgements.body";
	
    public static final String TYPE_AFFLIATION="affliation";
    public static final String TYPE_HEADER="header";
    public static final String TYPE_FOOTER="footer";
    public static final String TYPE_KEYWORDS="keywords";
    
    public static final String TYPE_INTRODUCTION="introduction";
    public static final String TYPE_INTRODUCTION_HEADING="introduction.heading";
    public static final String TYPE_INTRODUCTION_BODY="introduction.body";
    public static final String TYPE_INTRODUCTION_SUBTITLE="introduction.subtitle";
    
    public static final String TYPE_SUPPORTING_INFORMATION="supportingInformation";
    public static final String TYPE_SUPPORTING_INFORMATION_HEADING="supportingInformation.heading";
    public static final String TYPE_SUPPORTING_INFORMATION_BODY="supportingInformation.body";
    public static final String TYPE_SUPPORTING_INFORMATION_SUBTITLE="supportingInformation.subtitle";
       
    public static final String TYPE_CITATION="citation";
    public static final String META_TYPE_HEADING=".heading";
    public static final String META_TYPE_SUBTITLE=".subtitle";
	
    public Block getContainer();

	public void setContainer(Block block);

	public String readLeftRightMedLine();

	public boolean isFlush(String condition, int value);

	public void setType(String type);
	
	public String getType();

}
src/main/java/edu/isi/bmkeg/utils/IntegerFrequencyCounter.java
public class IntegerFrequencyCounter implements Serializable
{

    Map<Integer, Integer> freq = new HashMap<Integer, Integer>();
    int kernel;
    int max = 0;
    int mp = 0;
    int nmp = 0;

    public String getDebug()
    {
        Object[] oo = this.freq.keySet().toArray();
        Arrays.sort(oo);
        String debug = "";
        for(int i = 0; i < oo.length; i++)
        {
            Integer ii = (Integer) oo[i];
            int c = getCount(ii);
            debug += ii.intValue() + ":" + c + "\n";
        }
        return debug;
    }


    public IntegerFrequencyCounter(int kernel)
    {
        this.kernel = kernel;
    }


    public int[] getOrderdValues()
    {
        Object[] oo = this.freq.keySet().toArray();
        Arrays.sort(oo);
        int[] ii = new int[oo.length];
        for(int i = 0; i < oo.length; i++)
        {
            ii[i] = ((Integer) oo[i]).intValue();
        }

        return ii;
    }


    public void add(Integer ii)
    {
        int i = ii.intValue();

        max = -1;
        mp = -1;

        for(int j = i - kernel; j <= i + kernel; j++)
        {
            Integer jj = new Integer(j);
            int weight = kernel - Math.abs(i - j) + 1;
            this.incrementCount(jj, weight);
        }
    }


    public int getMostPopular()
    {
        if(mp > 0) {
            return mp;
        }
        int max = 0;
        Iterator<Integer> it = this.freq.keySet().iterator();
        while(it.hasNext())
        {
            Integer MP = (Integer) it.next();
            int c = getCount(MP);
            if(c > max)
            {
                mp = MP.intValue();
                max = c;
            }
        }
        return mp;
    }


    public int getNextMostPopular() {
    	
        if(nmp > 0) {
            return nmp;
        }
        int mp = this.getMostPopular();
        int mpCount = this.getCount(new Integer(mp));

        int max = 0;
        Iterator<Integer> it = this.freq.keySet().iterator();
        while(it.hasNext()) {
            Integer NMP = (Integer) it.next();
            int c = getCount(NMP);
            if(c > max && c < mpCount)
            {
                nmp = NMP.intValue();
                max = c;
            }
        }
        return nmp;
    }


    public void incrementCount(Integer o, int d)
    {
        int c = this.getCount(o);
        Integer count = new Integer(c + d);
        this.freq.put(o, count);
    }


    public int getCount(Object o)
    {
        int c = 0;
        if(this.freq.containsKey(o))
        {
            Integer count = (Integer) this.freq.get(o);
            c = count.intValue();
        }
        return c;
    }


    public int getMax()
    {
        Object[] oo = this.freq.keySet().toArray();
        Arrays.sort(oo);
        max = ((Integer) oo[oo.length - 1]).intValue();
        return max;
    }


    public int getMin()
    {
        Object[] oo = this.freq.keySet().toArray();
        Arrays.sort(oo);
        max = ((Integer) oo[0]).intValue();
        return max;
    }


    public int sumKeys()
    {
        int c = 0;
        Iterator<Integer> it = this.freq.keySet().iterator();
        while(it.hasNext())
        {
            Integer cc = (Integer) it.next();
            c += cc.intValue();
        }
        return c;
    }

    public void reset(){
    	this.freq.clear();
    	this.max=0;
    	this.mp=0;
    	this.nmp=0;
    }

}
src/main/java/edu/isi/bmkeg/lapdf/utils/PageImageOutlineRenderer.java
public class PageImageOutlineRenderer {
	
	private static TreeMap<Integer, String> colorMap = new TreeMap<Integer, String>();
	private static TreeMap<String, Integer> countMap = new TreeMap<String, Integer>();
	private static final int TYPE_UNCLASSIFIED_COLOR_CODE = 0xFBF5EF;

	public static void createPageImage(PageBlock page, File outputFile, String label, int mode) throws IOException {

		int width = page.getPageBoxWidth();
		int height = page.getPageBoxHeight();

		BufferedImage image = new BufferedImage(width, height,
				BufferedImage.TYPE_INT_ARGB);
		image.getGraphics().setColor(Color.white);
		image.getGraphics().fillRect(0, 0, width, height);
		image.getGraphics().setColor(Color.red);

		drawWord(width / 2 - 50, 10, image, Color.black,
				label + ":" + page.getPageNumber(), 10);

		List<ChunkBlock> cbList = page.getAllChunkBlocks(SpatialOrdering.MIXED_MODE);
		List<Block> list = new ArrayList<Block>(cbList);
		
		// renderBlockPerImage(list, image, fileName);
		renderBlockByColor(list, image, mode);

		List<WordBlock> wbList = page.getAllWordBlocks(SpatialOrdering.MIXED_MODE);
		list = new ArrayList<Block>(wbList);
		renderBlockByColor(list, image, mode);

		ImageIO.write(image, "png", outputFile);

	}

	private static void renderBlockByColor(
			List<Block> entityList,
			BufferedImage image, int mode) {

		for (Block block : entityList) {
			if (block instanceof ChunkBlock) {

				ChunkBlock chunky = (ChunkBlock) block;
				Integer colorCode = colorDecider(chunky.getType());

				if (colorMap.get(colorCode) == null) {
					if (colorCode == TYPE_UNCLASSIFIED_COLOR_CODE)
						colorMap.put(colorCode, Block.TYPE_UNCLASSIFIED);
					else
						colorMap.put(colorCode, chunky.getType());
				}

				if (colorCode == TYPE_UNCLASSIFIED_COLOR_CODE) {
					if (countMap.get(Block.TYPE_UNCLASSIFIED) == null) {
						countMap.put(Block.TYPE_UNCLASSIFIED, 1);
					} else {
						countMap.put(Block.TYPE_UNCLASSIFIED,
								countMap.get(Block.TYPE_UNCLASSIFIED) + 1);
					}
				} else {
					if (countMap.get(chunky.getType()) == null) {
						countMap.put(chunky.getType(), 1);
					} else {
						countMap.put(chunky.getType(),
								countMap.get(chunky.getType()) + 1);
					}
				}
				
				drawRectangle(chunky.getX1(), chunky.getY1(),
						chunky.getWidth(), chunky.getHeight(), image,
						Color.red, chunky, mode);
				
				String text = chunky.getMostPopularWordFont() + ";" + chunky.getMostPopularWordStyle();
				if( mode != LapdfMode.BLOCK_ONLY )
					text = chunky.getType();
				
				drawWord( chunky.getX1() - 20, 
						chunky.getY1() , 
						image, 
						Color.black,
						text, 12);
				
			} else if (block != null) {

				WordBlock wordBlock = (WordBlock) block;
				ChunkBlock chunky = (ChunkBlock) wordBlock.getContainer();

				Integer colorCode = (mode == 1) ? colorDecider(chunky.getType())
						: 0x000000;

				drawRectangle(wordBlock.getX1() + 2, wordBlock.getY1() + 2,
						wordBlock.getWidth() - 4, wordBlock.getHeight() - 4,
						image, new Color(colorCode), block, mode);


				if( wordBlock.getFontStyle() != null) {
				
					String text = wordBlock.getFontStyle();
				
					text = text.substring(10, text.length()-2);

					drawWord( wordBlock.getX1(), 
							wordBlock.getY1() + wordBlock.getHeight(), 
							image, 
							Color.black,
							text, 6);
				}

			}

		}

	}

	private static int colorDecider(String type) {
		
		if (Block.TYPE_METHODS_HEADING.equals(type)) {
			return 0x0000ff;
		} else if (Block.TYPE_METHODS_BODY.equals(type)) {
			return 0x008000;
		} else if (Block.TYPE_METHODS_SUBTITLE.equals(type)) {
			return 0x00bfff;
		} else if (Block.TYPE_RESULTS_HEADING.equals(type)) {
			return 0x800080;
		} else if (Block.TYPE_RESULTS_BODY.equals(type)) {
			return 0x800000;
		} else if (Block.TYPE_RESULTS_SUBTITLE.equals(type)) {
			return 0x7cfc00;
		} else if (Block.TYPE_REFERENCES_HEADING.equals(type)) {
			return 0xffff00;
		} else if (Block.TYPE_REFERENCES_BODY.equals(type)) {
			return 0xff69b4;
		} else if (Block.TYPE_DISCUSSION_HEADING.equals(type)) {
			return 0xff0000;
		} else if (Block.TYPE_DISCUSSION_BODY.equals(type)) {
			return 0xfa8072;
		} else if (Block.TYPE_DISCUSSION_SUBTITLE.equals(type)) {
			return 0xff4500;
		} else if (Block.TYPE_CONCLUSIONS_HEADING.equals(type)) {
			return 0xb8860b;
		} else if (Block.TYPE_CONCLUSIONS_BODY.equals(type)) {
			return 0xbc8f8f;
		} else if (Block.TYPE_CONCLUSIONS_SUBTITLE.equals(type)) {
			return 0xbdb76b;
		} else if (Block.TYPE_ACKNOWLEDGEMENTS_HEADING.equals(type)) {
			return 0x4b0082;
		} else if (Block.TYPE_ACKNOWLEDGEMENTS_BODY.equals(type)) {
			return 0x556b2f;
		} else if (Block.TYPE_ABSTRACT_HEADING.equals(type)) {
			return 0xA9D0F5;
		} else if (Block.TYPE_ABSTRACT_BODY.equals(type)) {
			return 0x00FFFF;
		} else if (Block.TYPE_TITLE.equals(type)) {
			return 0xdc143c;
		} else if (Block.TYPE_AUTHORS.equals(type)) {
			return 0xffa500;
		} else if (Block.TYPE_INTRODUCTION_HEADING.equals(type)) {
			return 0xcd853f;
		} else if (Block.TYPE_INTRODUCTION_BODY.equals(type)) {
			return 0xd2691e;
		} else if (Block.TYPE_INTRODUCTION_SUBTITLE.equals(type)) {
			return 0xd2b48c;
		} else if (Block.TYPE_SUPPORTING_INFORMATION_HEADING.equals(type)) {
			return 0x8b4513;
		} else if (Block.TYPE_SUPPORTING_INFORMATION_BODY.equals(type)) {
			return 0x8fbc8f;
		} else if (Block.TYPE_SUPPORTING_INFORMATION_SUBTITLE.equals(type)) {
			return 0x90ee90;
		} else if (Block.TYPE_FIGURE_LEGEND.equals(type)) {
			return 0x000000;
		} else if (Block.TYPE_AFFLIATION.equals(type)) {
			return TYPE_UNCLASSIFIED_COLOR_CODE;
		} else if (Block.TYPE_HEADER.equals(type)) {
			return TYPE_UNCLASSIFIED_COLOR_CODE;
		} else if (Block.TYPE_FOOTER.equals(type)) {
			return TYPE_UNCLASSIFIED_COLOR_CODE;
		} else if (Block.TYPE_KEYWORDS.equals(type)) {
			return TYPE_UNCLASSIFIED_COLOR_CODE;
		} else if (Block.TYPE_TABLE.equals(type)) {
			return TYPE_UNCLASSIFIED_COLOR_CODE;
		} else if (Block.TYPE_CITATION.equals(type)) {
			return TYPE_UNCLASSIFIED_COLOR_CODE;
		} else {
			return TYPE_UNCLASSIFIED_COLOR_CODE;
		}

	}

	private static void drawRectangle(int x, int y, int width, int height,
			BufferedImage image, Color color, Block block, int mode) {

		Graphics2D graphics = image.createGraphics();

		graphics.setPaint(color);

		Rectangle rect = new Rectangle(x, y, width, height);
		if ( block instanceof WordBlock && mode == LapdfMode.BLOCK_ONLY ) {

			graphics.draw(rect);
			graphics.fill(rect);
			
		} else {

			graphics.draw(rect);

		}

	}

	private static void drawWord(int x, int y, int width, int height,
			BufferedImage image, Color color, WordBlock word) {
		Graphics2D graphics = image.createGraphics();
		Font plainFont = new Font(word.getFont(), Font.PLAIN, word.getHeight());

		AttributedString as = new AttributedString(word.getWord());
		as.addAttribute(TextAttribute.FONT, plainFont);

		graphics.setPaint(color);
		graphics.drawString(as.getIterator(), x, y);

	}

	private static void drawWord(
			int x, int y, 
			BufferedImage image,
			Color color, 
			String word,
			int size) {
		
		Graphics2D graphics = image.createGraphics();
		Font plainFont = new Font(Font.SANS_SERIF, Font.PLAIN, size);
		AttributedString as = new AttributedString(word);
		as.addAttribute(TextAttribute.FONT, plainFont);
		graphics.setPaint(color);
		graphics.drawString(as.getIterator(), x, y);

	}

	public static void createReport(String fileName) {

		if (colorMap.size() == 0 || countMap.size() == 0) {
			throw new IllegalStateException(
					"Before calling this method you should use createPageImage to draw the individual pages");
		}

		BufferedImage image = new BufferedImage(500, 800,
				BufferedImage.TYPE_INT_ARGB);
		Graphics2D graphics = image.createGraphics();
		image.getGraphics().setColor(Color.white);
		image.getGraphics().fillRect(0, 0, 500, 800);
		String sectionType;
		int x = 20;
		int y = 20;
		Font plainFont = new Font(Font.SANS_SERIF, Font.PLAIN, 20);
		for (Integer color : colorMap.keySet()) {
			sectionType = colorMap.get(color);
			Shape circle = new Ellipse2D.Float(x, y, 20, 20);
			graphics.setPaint(new Color(color));
			graphics.draw(circle);
			graphics.fill(circle);
			graphics.setColor(Color.black);
			AttributedString as = new AttributedString(sectionType);
			as.addAttribute(TextAttribute.FONT, plainFont);
			graphics.drawString(as.getIterator(), x + 22, y + 20);
			as = new AttributedString(countMap.get(sectionType) + "");

			graphics.drawString(as.getIterator(), 380, y + 20);

			x = 20;
			y = y + 24;
		}

		try {

			File outputfile = new File(fileName);
			ImageIO.write(image, "png", outputfile);
		} catch (IOException e) {

		}
		colorMap.clear();
		countMap.clear();
	
	}

}
src/main/java/edu/isi/bmkeg/utils/FrequencyCounter.java
public class FrequencyCounter implements Serializable {

	private Map<Object, Integer> freq = new HashMap<Object, Integer>();

	public void add(FrequencyCounter fc) {
		Iterator<Object> it = this.freq.keySet().iterator();
		while (it.hasNext()) {
			Object o = it.next();
			int c1 = fc.getCount(o);
			int c2 = this.getCount(o);
			this.freq.put(o, new Integer(c1 + c2));
		}
	}

	public void add(Object o) {
		int c = this.getCount(o);
		Integer count = new Integer(c + 1);
		this.freq.put(o, count);
	}

	public Object getMostPopular() {
		int max = 0;
		Object mp = null;
		Iterator<Object> it = this.freq.keySet().iterator();
		while (it.hasNext()) {
			Object MP = it.next();
			int c = getCount(MP);
			if (c > max) {
				mp = MP;
				max = c;
			}
		}

		return mp;
	}

	public Object getNextMostPopular() {
		
		int max = 0;
		
		Object nmp = null;
		
		Object mp = this.getMostPopular();
		int mpCount = this.getCount(mp);
		
		Iterator<Object> it = this.freq.keySet().iterator();
		while (it.hasNext()) {
			Object NMP = it.next();
			int c = getCount(NMP);
			if (c > max && c < mpCount) {
				nmp = NMP;
				max = c;
			}
		}

		return nmp;
	}

	public Object getThirdMostPopular() {
		
		int max = 0;

		Object nnmp = null;

		Object nmp = this.getNextMostPopular();
		int nmpCount = this.getCount(nmp);
		
		Iterator<Object> it = this.freq.keySet().iterator();
		while (it.hasNext()) {
			Object NNMP = it.next();
			int c = getCount(NNMP);
			if (c > max && c < nmpCount) {
				nnmp = NNMP;
				max = c;
			}
		}

		return nnmp;
	}
	
	public int getCount(Object o) {
		int c = 0;
		if (this.freq.containsKey(o)) {
			Integer count = this.freq.get(o);
			c = count.intValue();
		}

		return c;
	}

	public int countOptions() {
		return this.freq.size();
	}

	public void reset() {
		this.freq.clear();

	}
}
src/main/java/edu/isi/bmkeg/lapdf/model/ChunkBlock.java
public interface ChunkBlock extends Block, SpatialEntity {

	public int getMostPopularWordHeight();

	public int getMostPopularWordSpaceWidth();

	public String getMostPopularWordFont();

	public String getMostPopularWordStyle();

	public void setMostPopularWordHeight(int height);

	public void setMostPopularWordSpaceWidth(int spaceWidth);

	public void setMostPopularWordStyle(String style);

	public void setMostPopularWordFont(String font);

	public int readNumberOfLine();

	public String readChunkText();

	public Boolean isHeaderOrFooter();

	public void setHeaderOrFooter(boolean headerOrFooter);

	public ChunkBlock readLastChunkBlock();

	boolean isMatchingRegularExpression(String regex);

	boolean isUnderOneLineFlushNeighboursOfType(String type);

	boolean hasNeighboursOfType(String type, int nsew);
	
}
src/main/java/edu/isi/bmkeg/lapdf/model/PageBlock.java
public interface PageBlock extends Block, SpatialRepresentation {

	public int getPageNumber();

	public int initialize(List<WordBlock> list, int startId);

	public int getPageBoxHeight();

	public int getPageBoxWidth();

	public LapdfDocument getDocument();

}
src/main/java/edu/isi/bmkeg/lapdf/extraction/JPedalExtractor.java
public class JPedalExtractor implements Extractor {

	Set<WordBlock> wordListPerPage = null;
	PdfDecoder PDFDecoder = null;
	int currentPage = 1;
	int pageCount;
	private static Document xmlDocument;
	private static DocumentBuilder docBuilder;

	private static int pageHeight;
	private static int pageWidth;
	private AbstractModelFactory modelFactory;

	public JPedalExtractor(AbstractModelFactory modelFactory)
			throws Exception {

		DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
		docBuilder = dbfac.newDocumentBuilder();
		
		this.modelFactory = modelFactory;
		this.PDFDecoder = new PdfDecoder(false);

		PDFDecoder.setExtractionMode(PdfDecoder.TEXT); // extract just text
		PDFDecoder.init(true);
		PdfGroupingAlgorithms.useUnrotatedCoords = true;
		// if you do not require XML content, pure text extraction is much
		// faster.
		PDFDecoder.useXMLExtraction();

		System.setProperty("hacked", "true");

	}

	public void init(File file) throws Exception {
		
		if (PDFDecoder.isOpen()) {
			PDFDecoder.flushObjectValues(true);
			PDFDecoder.closePdfFile();

		}

		PDFDecoder.openPdfFile(file.getPath());
		currentPage = 1;
		pageCount = PDFDecoder.getPageCount();
		if (!PDFDecoder.isExtractionAllowed()) {
			throw new AccessException(file.getPath());
		} else if (PDFDecoder.isEncrypted()) {
			throw new EncryptionException(file.getPath());
		}

	}

	private int[] generatePageBoundaries(PdfPageData currentPageData) {
		
		// 0:TLX, 1:TLY, 2:BRX, 3:BRY
		int[] dimensions = new int[4];

		// Using just cropbox
		if( currentPageData.getCropBoxHeight(currentPage) 
				!= currentPageData.getMediaBoxHeight(currentPage) ) {
			
			dimensions[0] = currentPageData.getCropBoxX(currentPage);
			dimensions[2] = currentPageData.getCropBoxWidth(currentPage)
					+ dimensions[0];

			dimensions[3] = currentPageData.getCropBoxY(currentPage);
			dimensions[1] = currentPageData.getCropBoxHeight(currentPage)
					+ dimensions[3];
		} else {
			dimensions[0] = currentPageData.getMediaBoxX(currentPage);
			dimensions[2] = currentPageData.getMediaBoxWidth(currentPage)
					+ dimensions[0];

			dimensions[3] = currentPageData.getMediaBoxY(currentPage);
			dimensions[1] = currentPageData.getMediaBoxHeight(currentPage)
					+ dimensions[3];
		}
		return dimensions;

	}

	private String getFontData(String xml, String item)
			throws UnsupportedEncodingException, IOException {
		xml = "<root>" + xml + "</root>";

		try {
			xmlDocument = docBuilder.parse(new ByteArrayInputStream(xml
					.getBytes("UTF-8")));
		} catch (SAXException e) {

			// e.printStackTrace();
			return null;
		}

		Element font = (Element) xmlDocument.getElementsByTagName("font").item(
				0);
		return font.getAttribute(item);

	}

	private void decodeFile() throws Exception {

		String font = null;
		String currentWord;
		String style = null;

		PDFDecoder.decodePage(currentPage);
		
		PdfGroupingAlgorithms currentGrouping = PDFDecoder.getGroupingObject();

		PdfPageData currentPageData = PDFDecoder.getPdfPageData();
		int[] dimensions;

		// pageHeight.add(currentPageData.getCropBoxHeight(page));
		// pageWidth.add(currentPageData.getCropBoxWidth(page));

		dimensions = generatePageBoundaries(currentPageData);
		pageWidth = Math.abs(dimensions[2] - dimensions[0]);
		pageHeight = Math.abs(dimensions[1] - dimensions[3]);
		
		//currentGrouping.extractTextAsWordlist(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
		List words = currentGrouping.extractTextAsWordlist(
				dimensions[0], dimensions[1], dimensions[2], dimensions[3], 
				currentPage,
				true, 
				"&:=()!;\\/\"\"\'\'"
				);

		Iterator<String> wordIterator = words.iterator();

		if (wordListPerPage == null)
			wordListPerPage = new TreeSet<WordBlock>(new SpatialOrdering(SpatialOrdering.MIXED_MODE_ABSOLUTE));
		else {
			wordListPerPage.clear();
		}

		while (wordIterator.hasNext()) {

			currentWord = wordIterator.next();

			font = getFontData(currentWord, "face");
			style = getFontData(currentWord, "style");
			currentWord = Strip.convertToText(currentWord, true);
			
			int wx1 = roundUp(Float.parseFloat((wordIterator.next() + "")));
			int wy1 = roundUp(Float.parseFloat((wordIterator.next() + "")));
			int wx2 = roundUp(Float.parseFloat((wordIterator.next() + "")));
			int wy2 = roundUp(Float.parseFloat((wordIterator.next() + "")));

			wy1 = dimensions[1] - wy1;
			wy2 = dimensions[1] - wy2;

			WordBlock wordBlock = modelFactory.createWordBlock(wx1, wy1, wx2,
					wy2, 1, font, style, currentWord);

			wordListPerPage.add(wordBlock);
		
		}
		
		currentPage++;
		PDFDecoder.flushObjectValues(false);
	
	}

	@Override
	public boolean hasNext() {
		
		if (currentPage <= pageCount) {

			try {
		
				decodeFile();

			} catch (EmptyPDFException e) {
			
				return false;

			} catch (Exception e) {
			
				return false;
			
			}

			return true;
		
		} else {
		
			PDFDecoder.flushObjectValues(true);
			PDFDecoder.closePdfFile();
			return false;
		
		}

	}

	@Override
	public List<WordBlock> next() {
		return new ArrayList<WordBlock>(wordListPerPage);
	}

	@Override
	public void remove() {
	}

	@Override
	public int getCurrentPageBoxHeight() {

		return pageHeight;
	}

	@Override
	public int getCurrentPageBoxWidth() {

		return pageWidth;
	}

	private int roundUp(double value) {
		
		value = Math.floor(value);

		return (int) value;
	}

}
src/main/java/edu/isi/bmkeg/lapdf/model/spatial/SpatialEntity.java
public interface SpatialEntity {

	public SpatialEntity union(SpatialEntity entity);

	public void resize(int X1,int Y1,int width,int height);

	public int getY1();

	public int getY2();

	public int getX1();

	public int getX2();

	public int getHeight();

	public int getWidth();

	public double getRelativeOverlap(SpatialEntity entity);
	
	public SpatialEntity getIntersectingRectangle(SpatialEntity entity);
	
	public int getId();
	
	public void setId(int id);

}
src/main/java/edu/isi/bmkeg/lapdf/model/WordBlock.java
public interface WordBlock extends Block, SpatialEntity {

	public String getWord();

	public String getFont();

	public String getFontStyle();

	public int getSpaceWidth();

}
src/main/java/edu/isi/bmkeg/lapdf/model/LapdfDocument.java
public class LapdfDocument implements Serializable {

	private File pdfFile;
	
	private ArrayList<PageBlock> pageList;
	
	private IntegerFrequencyCounter avgHeightFrequencyCounter;
	private FrequencyCounter fontFrequencyCounter;
	
	private int mostPopularWordHeight = -1;
	private String mostPopularFontStyle = "";
	private String nextMostPopularFontStyle = "";
	private String mostPopularFontStyleOnLastPage = "";
	
	// This the rectangle that holds the text of the main 'panel' 
	// across the whole document (excluding footers and headers)
	private SpatialEntity bodyTextFrame;

	private boolean jPedalDecodeFailed;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	public LapdfDocument(File pdfFile) {
		this.setPdfFile(pdfFile);
		this.setAvgHeightFrequencyCounter(new IntegerFrequencyCounter(1));
		this.setFontFrequencyCounter(new FrequencyCounter());
	}

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	public boolean hasjPedalDecodeFailed() {
		return jPedalDecodeFailed;
	}

	public void setjPedalDecodeFailed(boolean jPedalDecodeFailed) {
		this.jPedalDecodeFailed = jPedalDecodeFailed;
	}

	public int getTotalNumberOfPages() {
		return this.pageList.size();
	}

	public File getPdfFile() {
		return pdfFile;
	}

	public void setPdfFile(File pdfFile) {
		this.pdfFile = pdfFile;
	}

	public IntegerFrequencyCounter getAvgHeightFrequencyCounter() {
		return avgHeightFrequencyCounter;
	}

	public void setAvgHeightFrequencyCounter(IntegerFrequencyCounter avgHeightFrequencyCounter) {
		this.avgHeightFrequencyCounter = avgHeightFrequencyCounter;
	}
	
	public FrequencyCounter getFontFrequencyCounter() {
		return fontFrequencyCounter;
	}

	public void setFontFrequencyCounter(FrequencyCounter fontFrequencyCounter) {
		this.fontFrequencyCounter = fontFrequencyCounter;
	}

	public SpatialEntity getBodyTextFrame() {
		return bodyTextFrame;
	}

	public void setBodyTextFrame(SpatialEntity bodyTextFrame) {
		this.bodyTextFrame = bodyTextFrame;
	}

	public String getMostPopularFontStyle() {
		return mostPopularFontStyle;
	}

	public void setMostPopularFontStyle(String mostPopularFontStyle) {
		this.mostPopularFontStyle = mostPopularFontStyle;
	}

	public String getNextMostPopularFontStyle() {
		return nextMostPopularFontStyle;
	}

	public void setNextMostPopularFontStyle(String nextMostPopularFontStyle) {
		this.nextMostPopularFontStyle = nextMostPopularFontStyle;
	}

	public String getMostPopularFontStyleOnLastPage() {
		return mostPopularFontStyleOnLastPage;
	}

	public void setMostPopularFontStyleOnLastPage(
			String mostPopularFontStyleOnLastPage) {
		this.mostPopularFontStyleOnLastPage = mostPopularFontStyleOnLastPage;
	}

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	public void addPages(List<PageBlock> pageList) {
		this.pageList = new ArrayList<PageBlock>(pageList);
	}

	public PageBlock getPage(int pageNumber) {

		return pageList.get(pageNumber - 1);
	}

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	public ChunkBlock getLastChunkBlock(ChunkBlock chunk)
			throws InvalidPopularSpaceValueException {
		
		int pageNumber = ((PageBlock) chunk.getContainer()).getPageNumber();
		PageBlock page = this.getPage(pageNumber);
		
		if (page.getMostPopularVerticalSpaceBetweenWordsPage() < 0
				&& page.getMostPopularWordHeightPage() > page
						.getMostPopularWordWidthPage() * 2) {
			// page.getMostPopularWordHeightPage()>page.getMostPopularWordWidthPage()*2
			
			System.err.println(
					"Possible page with vertical text flow at page number +"
					+ pageNumber);

			// throw new
			// InvalidPopularSpaceValueException("Possible page with vertical text flow at page number +"+pageNumber);
		}

		if (chunk.readLastChunkBlock() != null) {
			// System.out.println("Same page");
			return chunk.readLastChunkBlock();
		} else {
			pageNumber = ((PageBlock) chunk.getContainer()).getPageNumber() - 1;

			if (pageNumber == 0) {
				return null;
			}

			page = this.getPage(pageNumber);
			List<ChunkBlock> sortedChunkBlockList = page
					.getAllChunkBlocks(SpatialOrdering.COLUMN_AWARE_MIXED_MODE);
			// System.out.println("Page:"+ pageNumber);
			return sortedChunkBlockList.get(sortedChunkBlockList.size() - 1);
		}

	}

	public int readMostPopularWordHeight() {
		
		if( this.mostPopularWordHeight != -1 )
			return this.mostPopularWordHeight;
		
		int mp = this.avgHeightFrequencyCounter.getMostPopular();
		double mpCount = this.avgHeightFrequencyCounter.getCount(mp);
		int nmp = this.avgHeightFrequencyCounter.getNextMostPopular();
		double nmpCount = this.avgHeightFrequencyCounter.getCount(nmp);
		double ratio = nmpCount / mpCount;

		// Sneaky check for long reference sections
		if (nmp > mp && ratio > 0.8) {
			mostPopularWordHeight = nmp;
		} else {
			mostPopularWordHeight = mp;
		}

		return mostPopularWordHeight;
	}	
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	public void packForSerialization() {

		this.setBodyTextFrame(null);
		for (int i = 1; i <= this.getTotalNumberOfPages(); i++) {	
			RTPageBlock page = (RTPageBlock) this.getPage(i);
			page.packForSerialization();
		}	
	
	}
	
	public void unpackFromSerialization() {
	
		for (int i = 1; i <= this.getTotalNumberOfPages(); i++) {	
			RTPageBlock page = (RTPageBlock) this.getPage(i);
			page.unpackFromSerialization();
		}	
		this.calculateBodyTextFrame();
		
	}

	public void calculateBodyTextFrame() {

		String mp = (String) this.fontFrequencyCounter.getMostPopular();
		String[] mpArray = mp.split(";");
		
		int x_min = 10000;
		int y_min = 10000;
		int x_max = -1;
		int y_max = -1;
		
		Iterator<PageBlock> pgIt = this.pageList.iterator();
		while( pgIt.hasNext() ) {
			PageBlock pg = pgIt.next();
			
			Iterator<WordBlock> wdIt = pg.getAllWordBlocks(SpatialOrdering.MIXED_MODE).iterator();
			while( wdIt.hasNext() ) {
				WordBlock wd = wdIt.next();

				if( wd.getFont() == null || wd.getFontStyle() == null) 
					continue;
				
				if( wd.getFont().equals(mpArray[0]) && 
						wd.getFontStyle().equals(mpArray[1]) ) {
				
					if( wd.getX1() < x_min )
						 x_min = wd.getX1();
					if( wd.getX2() > x_max )
						 x_max = wd.getX2();
					if( wd.getY1() < y_min )
						 y_min = wd.getY1();
					if( wd.getY2() > y_max )
						 y_max = wd.getY2();
					
				}
			
			}
		
		}
		
		this.setBodyTextFrame(new RTSpatialEntity(
				(float) x_min, (float) y_min, (float) x_max, (float) y_max
				));
		
	}

	public void calculateMostPopularFontStyles() {

		String lastPage = this.readMostPopularFontStyleOnLastPage();

		String mp = (String) this.fontFrequencyCounter.getMostPopular();
		String nmp = (String) this.fontFrequencyCounter.getNextMostPopular();
		String nnmp = (String) this.fontFrequencyCounter.getThirdMostPopular();

		if( mp.equals( lastPage ) ) {
			
			this.setMostPopularFontStyle(nmp);
			this.setNextMostPopularFontStyle(nnmp);
			
		} else if( nmp.equals( lastPage ) ) {

			this.setMostPopularFontStyle(mp);
			this.setNextMostPopularFontStyle(nnmp);
			
		} else {

			this.setMostPopularFontStyle(mp);
			this.setNextMostPopularFontStyle(nmp);

		}
		
	}

	public String readMostPopularFontStyleOnLastPage() {

		if( this.getMostPopularFontStyleOnLastPage() != null &&
				this.getMostPopularFontStyleOnLastPage().length() > 0 ) {

			return this.getMostPopularFontStyleOnLastPage();
		
		}
		
		this.setMostPopularFontStyle((String) this.fontFrequencyCounter.getMostPopular() );
	
		FrequencyCounter freq = new FrequencyCounter ();
		
		Iterator<PageBlock> pgIt = this.pageList.iterator();
		while( pgIt.hasNext() ) {
			PageBlock pg = pgIt.next();
			
			if( pg.getPageNumber() < this.pageList.size() ) {
				continue;
			}

			
			Iterator<WordBlock> wdIt = pg.getAllWordBlocks(SpatialOrdering.MIXED_MODE).iterator();
			while( wdIt.hasNext() ) {
				WordBlock wd = wdIt.next();

				if( wd.getFont() == null || wd.getFontStyle() == null) 
					continue;
				
				freq.add( wd.getFont() + ";" + wd.getFontStyle() );
								
			}
		
		}
		
		this.setMostPopularFontStyleOnLastPage((String) freq.getMostPopular() );
		
		return this.getMostPopularFontStyleOnLastPage();
				
	}
	
	
}
src/main/java/edu/isi/bmkeg/lapdf/model/ordering/SpatialOrdering.java
public class SpatialOrdering implements Comparator<SpatialEntity> {

	public static final String HORIZONTAL_MODE = "horizontal";
	public static final String VERTICAL_MODE = "vertical";
	public static final String MIXED_MODE = "mixed";
	public static final String MIXED_MODE_ABSOLUTE="mixedAbs";
	public static final String COLUMN_AWARE_MIXED_MODE = "camd";
	public static final String PAGE_COLUMN_AWARE_MIXED_MODE = "pcamd";
	public String mode;

	public SpatialOrdering(String mode) {
		this.mode = mode;
	}

	@Override
	public int compare(SpatialEntity o1, SpatialEntity o2) {

		if (HORIZONTAL_MODE.equalsIgnoreCase(mode)) {
			return horizontalOrdering(o1, o2);
		} else if (VERTICAL_MODE.equalsIgnoreCase(mode)) {
			return verticalOrdering(o1, o2);
		} else if (MIXED_MODE.equalsIgnoreCase(mode)) {
			return mixedOrdering(o1, o2);
		}else if (MIXED_MODE_ABSOLUTE.equalsIgnoreCase(mode)) {
			return mixedOrderingAbsolute(o1, o2);
		} 
		else if (COLUMN_AWARE_MIXED_MODE.equalsIgnoreCase(mode)) {
			return camdOrdering(o1, o2);
		} else if (PAGE_COLUMN_AWARE_MIXED_MODE.equalsIgnoreCase(mode)) {
			return pcamdOrdering(o1, o2);
		} else {
			return 0;
		}

	}

	private int camdOrdering(SpatialEntity o1, SpatialEntity o2) {

		String o1Allignment = ((Block) o1).readLeftRightMedLine();
		String o2Allignment = ((Block) o2).readLeftRightMedLine();
		int pageNumber = ((PageBlock) ((Block) o1).getContainer())
				.getPageNumber();
		int o1y1 = o1.getY1();
		int o2y1 = o2.getY1();
		int pageHeight = ((PageBlock) ((Block) o1).getContainer())
				.getPageBoxHeight();

		if (pageNumber == 1 && Math.abs(o1y1 - o2y1) >= .5 * pageHeight) {
			return mixedOrdering(o1, o2);
		} else if (executeHeaderFooterCheck((ChunkBlock) o1, (ChunkBlock) o2)) {
			return mixedOrdering(o1, o2);
		}

		if (o1Allignment.equals(o2Allignment)) {
			return mixedOrdering(o1, o2);
		} else if (Block.MIDLINE.equalsIgnoreCase(o1Allignment)
				|| Block.MIDLINE.equalsIgnoreCase(o2Allignment)) {
			return mixedOrdering(o1, o2);

		} else if (Block.LEFT.equalsIgnoreCase(o1Allignment)) {

			return -1;
		} else if (Block.RIGHT.equalsIgnoreCase(o1Allignment)) {
			return 1;
		}
		return 0;
	}

	private int pcamdOrdering(SpatialEntity o1, SpatialEntity o2) {

		int pageNumbero1 = ((PageBlock) ((Block) o1).getContainer())
				.getPageNumber();
		int pageNumbero2 = ((PageBlock) ((Block) o2).getContainer())
				.getPageNumber();
		return (pageNumbero1 == pageNumbero2) ? camdOrdering(o1, o2)
				: pageNumbero1 - pageNumbero2;

	}

	private int horizontalOrdering(SpatialEntity o1, SpatialEntity o2) {
		int x1Diff = o1.getX1() - o2.getX1();
		if (x1Diff == 0)
			return o1.getX2() - o2.getX2();
		return x1Diff;
	}

	private int verticalOrdering(SpatialEntity o1, SpatialEntity o2) {
		Block block = (Block) o1;
		PageBlock page = (PageBlock) ((block.getContainer() instanceof PageBlock) ? block
				.getContainer()
				: block.getContainer().getContainer());
		int y1Diff = o1.getY1() - o2.getY1();
		
		if (Math.abs(y1Diff) < page.getMostPopularWordHeightPage()/2)
			return (Math.abs(o1.getY2() - o2.getY2()) < page
					.getMostPopularWordHeightPage()) ? 0 : o1.getY2()
					- o2.getY2();
		return y1Diff;
		/*int y1Diff = o1.getY1() - o2.getY1();
		if (y1Diff==0)
			return o1.getY2()
					- o2.getY2();
		return y1Diff;*/
	}

	
	private int verticalOrderingAbsolute(SpatialEntity o1, SpatialEntity o2) {
		
		int y1Diff = o1.getY1() - o2.getY1();
		if (y1Diff==0)
			return o1.getY2()
					- o2.getY2();
		return y1Diff;
	}
	/**
	 * Note: in order to implement the fix for the superscript subscript induced bug (fix implemented by Abhishek November 10th)
	 * replace the return mixedOrderingAbsolute with other commented code. 
	 * @param o1
	 * @param o2
	 * @return
	 */
	private int mixedOrdering(SpatialEntity o1, SpatialEntity o2) {
		//return mixedOrderingAbsolute(o1, o2);
		int y = verticalOrdering(o1, o2);
		if (y == 0) {
			return horizontalOrdering(o1, o2);
		} else {
			return y;
		}
	}
	
	private int mixedOrderingAbsolute(SpatialEntity o1, SpatialEntity o2) {
		int y = verticalOrderingAbsolute(o1, o2);
		if (y == 0) {
			return horizontalOrdering(o1, o2);

		} else {
			return y;
		}
	}

	// GULLY TODO: THIS IS VERY IMPORTANT
	private boolean executeHeaderFooterCheck(ChunkBlock o1, ChunkBlock o2) {

		if (o1.isHeaderOrFooter() != null && o1.isHeaderOrFooter())
			return true;

		if (o2.isHeaderOrFooter() != null && o2.isHeaderOrFooter())
			return true;

		if ((o1.isHeaderOrFooter() != null && !o1.isHeaderOrFooter())
				&& (o2.isHeaderOrFooter() != null && !o2.isHeaderOrFooter()))
			return false;

		boolean containsFirstLine1 = false;
		boolean containsFirstLine2 = false;
		boolean numberOfLineOne1 = false;
		boolean numberofLineOne2 = false;
		boolean containsLastLine1 = false;
		boolean containsLastLine2 = false;

		PageBlock p1 = (PageBlock) o1.getContainer();
		PageBlock p2 = (PageBlock) o1.getContainer();
		numberOfLineOne1 = o1.readNumberOfLine() == 1;
		numberofLineOne2 = o2.readNumberOfLine() == 1;

		if (!numberOfLineOne1 && !numberofLineOne2) {
			o1.setHeaderOrFooter(false);
			o2.setHeaderOrFooter(false);
			return false;
		}

		if (numberOfLineOne1) {
			containsFirstLine1 = Math.abs(o1.getY1() - p1.getMargin()[1]) < p1
					.getDocument().readMostPopularWordHeight();
			if (containsFirstLine1) {
				o1.setHeaderOrFooter(true);
				return true;
			}
			containsLastLine1 = Math.abs(o1.getY2() - p1.getMargin()[3]) < p1
					.getDocument().readMostPopularWordHeight();
			if (containsLastLine1) {
				o1.setHeaderOrFooter(true);
				return true;
			}
			o1.setHeaderOrFooter(false);
		}

		if (numberofLineOne2) {
			containsFirstLine2 = Math.abs(o2.getY1() - p2.getMargin()[1]) < p2
					.getDocument().readMostPopularWordHeight();
			if (containsFirstLine2) {
				o2.setHeaderOrFooter(true);
				return true;
			}
			containsLastLine2 = Math.abs(o2.getY2() - p2.getMargin()[3]) < p2
					.getDocument().readMostPopularWordHeight();
			if (containsLastLine2) {
				o2.setHeaderOrFooter(true);
				return true;
			}
			o2.setHeaderOrFooter(false);
		}

		return false;

	}

	public static void main(String argsd[]) {
		Boolean value = null;
		if (value != null)
			System.out.println("bklusd");
	}
}


Question: package edu.isi.bmkeg.lapdf.parser;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TreeSet;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;
import edu.isi.bmkeg.lapdf.extraction.JPedalExtractor;
import edu.isi.bmkeg.lapdf.extraction.exceptions.InvalidPopularSpaceValueException;
import edu.isi.bmkeg.lapdf.features.HorizontalSplitFeature;
import edu.isi.bmkeg.lapdf.model.Block;
import edu.isi.bmkeg.lapdf.model.ChunkBlock;
import edu.isi.bmkeg.lapdf.model.LapdfDocument;
import edu.isi.bmkeg.lapdf.model.PageBlock;
import edu.isi.bmkeg.lapdf.model.WordBlock;
import edu.isi.bmkeg.lapdf.model.factory.AbstractModelFactory;
import edu.isi.bmkeg.lapdf.model.ordering.SpatialOrdering;
import edu.isi.bmkeg.lapdf.model.spatial.SpatialEntity;
import edu.isi.bmkeg.lapdf.utils.PageImageOutlineRenderer;
import edu.isi.bmkeg.utils.FrequencyCounter;
import edu.isi.bmkeg.utils.IntegerFrequencyCounter;




public class RuleBasedParser implements Parser {

	private static Logger logger = Logger.getLogger(RuleBasedParser.class);

	private boolean debugImages = false;

Answer: 	private ArrayList<PageBlock> pageList;