Commits

Anonymous committed 5c76b53 Draft

saving latest tests may fail

Comments (0)

Files changed (43)

src/main/java/org/xmlcml/svgplus/action/AbstractActionX.java

 	public static final String EXIT = "exit";
 
 	public static final String VARIABLES = "variables";
+
+	public static final String TYPE = "type";
 	
 	protected SemanticDocumentActionX semanticDocumentActionX;
 
 		return expandVariables(value);
 	}
 
+	public String getType() {
+		return getAndExpand(AbstractActionX.TYPE);
+	}
+
 	protected String getValue(String attName, String defaultValue) {
 		String value = this.getAttributeValue(attName);
 		value = (value == null) ? defaultValue : value;
 	}
 
 	public List<String> getVariables() {
-		String s = this.getAttributeValue(PageActionX.VARIABLES);
+		String s = this.getAttributeValue(AbstractActionX.VARIABLES);
 		String[] ss = (s == null) ? null : s.split(CMLConstants.S_WHITEREGEX);
 		return (ss == null) ? null : Arrays.asList(ss);
 	}

src/main/java/org/xmlcml/svgplus/action/AssertActionX.java

 package org.xmlcml.svgplus.action;
 
+import java.io.File;
 import java.io.FileInputStream;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 		if (testValue == null) {
 			throw new RuntimeException("Cannot find name: "+name);
 		}
-		String testString = testValue.toString();
-		if (!testString.equals(refValue)) {
-			throw new RuntimeException("Assert for: ("+name+") expected: "+refValue+"; found: ("+testString+")");
+		if (testValue instanceof File) {
+			File refValueFile = new File(refValue);
+			File testValueFile = (File) testValue;
+			if (!(testValueFile).getAbsolutePath().equals(refValueFile.getAbsolutePath())) {
+				throw new RuntimeException("Assert for: ("+name+") expected: "+refValue+"; found: ("+testValueFile.getAbsolutePath()+")");
+			}
+		} else {
+			String testString = testValue.toString();
+			if (!testString.equals(refValue)) {
+				throw new RuntimeException("Assert for: ("+name+") expected: "+refValue+"; found: ("+testString+")");
+			}
 		}
 	}
 

src/main/java/org/xmlcml/svgplus/action/DocumentActionX.java

 
 public abstract class DocumentActionX extends AbstractActionX {
 
+	protected static final String OUTFILE = "outfile";
+
 	public DocumentActionX(AbstractActionX documentActionElement) {
 		super(documentActionElement);
 	}

src/main/java/org/xmlcml/svgplus/action/DocumentIteratorActionX.java

 import org.xmlcml.cml.base.CMLUtil;
 import org.xmlcml.graphics.svg.SVGSVG;
 import org.xmlcml.pdf2svg.util.MenuSystem;
-import org.xmlcml.svgplus.core.SVGPlusConstants;
 
 public class DocumentIteratorActionX extends DocumentActionX {
 
-	private static final String INPUT_DIR = SVGPlusConstants.D_DOT+SVGPlusConstants.ROOT_DIR;
-	static final String INPUT_FILE = SVGPlusConstants.D_DOT+SVGPlusConstants.INPUT_FILE;
-	private static final String OUTPUT_DIR = SVGPlusConstants.D_DOT+SVGPlusConstants.OUTPUT_DIR;
+	private static final String INPUT_DIR = SVGPlusConstantsX.D_DOT+SVGPlusConstantsX.ROOT_DIR;
+	static final String INPUT_FILE = SVGPlusConstantsX.D_DOT+SVGPlusConstantsX.INPUT_FILE;
+	private static final String OUTPUT_DIR = SVGPlusConstantsX.D_DOT+SVGPlusConstantsX.OUTPUT_DIR;
 
 	private final static Logger LOG = Logger.getLogger(DocumentIteratorActionX.class);
 
 	public final static String TAG ="documentIterator";
 
 	private static final List<String> ATTNAMES = new ArrayList<String>();
-
 	static {
 		ATTNAMES.add(FILENAME);
+		ATTNAMES.add(OUTFILE);
 		ATTNAMES.add(FORMAT);
 		ATTNAMES.add(MAX);
 		ATTNAMES.add(REGEX);
 
 	private void createInputFileList() {
 		infileList = new ArrayList<File>();
-		max = getInteger(DocumentIteratorActionX.MAX);
+		max = getInteger(DocumentActionX.MAX);
 		File indir = null;
 		if (!infile.isDirectory()) {
 			String name = infile.getName();
 	private void createOutputDirectory() {
 		// outfile may have been set by commandline
 		if (outfile == null) {
-			outdir = infile.getParentFile();
-		} else if (!infile.isDirectory()) { // single file
-			outdir = outfile != null ? outfile : infile.getParentFile();
+			if (infile != null) {
+				outdir = (infile.isDirectory()) ? infile : infile.getParentFile();
+			}
 		} else {
-			if (outfile != null) {
-				outdir = outfile;
-			}
+			outdir = (outfile.isDirectory()) ? outfile : outfile.getParentFile();
 		}
 	}
 
 	private List<File> getFiles(File indir) {
 		File[] files = indir.listFiles(new FilenameFilter() {
 			public boolean accept(File dir, String path) {
-				return path.endsWith(SVGPlusConstants.PDF); // for test
+				return path.endsWith(SVGPlusConstantsX.PDF); // for test
 			}
 		});
 		return files == null ? new ArrayList<File>() : Arrays.asList(files);
 	}
 
 	private File getOutfile() {
+		// variable set takes precedence
 		outfile = (File) semanticDocumentActionX.getVariable(SemanticDocumentActionX.S_OUTFILE);
-		// no attribute to set directory - yet
-//		if (outfile == null) {
-//			String filename = getFilename();
-//			infile = (filename == null) ? null : new File(filename);
-//		}
+		if (outfile == null) {
+			String outfilename = this.getAndExpand(OUTFILE);
+			if (outfilename != null) {
+				outfile = new File(outfilename);
+				semanticDocumentActionX.setVariable(SemanticDocumentActionX.S_OUTFILE, outfile);
+			}
+		}
 		return outfile;
 	}
 
 	private void createHtmlMenuDisplay() {
 //		LOG.debug("FILES "+rawDirList.size());
 		MenuSystem menuSystem = new MenuSystem(infile);
-		menuSystem.setRoot("/../"+SVGPlusConstants.OUT+CMLConstants.S_SLASH+SVGPlusConstants.INDEX_HTML);
+		menuSystem.setRoot("/../"+SVGPlusConstantsX.OUT+CMLConstants.S_SLASH+SVGPlusConstantsX.INDEX_HTML);
 		menuSystem.setLabel("../../");
 		menuSystem.setRowWidth(100);
 		menuSystem.setAddPdf(false);
 	private File[] listSVGFiles(File rawDir) {
 		File[] svgFiles = rawDir.listFiles(new FilenameFilter() {
 			public boolean accept(File rawDir, String name) {
-				return name.endsWith(SVGPlusConstants.SVG);
+				return name.endsWith(SVGPlusConstantsX.SVG);
 			}
 		});
 		return svgFiles;
 	private void outputSVGsToRawDir(File rawDir, List<SVGSVG> pageList) {
 		int page = 0;
 		for (SVGSVG svgPage :pageList) {
-			CMLUtil.outputQuietly(svgPage, new File(rawDir, SVGPlusConstants.PAGE+(++page)+SVGPlusConstants.SVG), 1);
+			CMLUtil.outputQuietly(svgPage, new File(rawDir, SVGPlusConstantsX.PAGE+(++page)+SVGPlusConstantsX.SVG), 1);
 		}
 	}
 
 
 	private File generateRawFileDirectory(File pdfFile) {
 		String name = pdfFile.getName();
-		String root = name.substring(0, name.length()-SVGPlusConstants.PDF.length());
+		String root = name.substring(0, name.length()-SVGPlusConstantsX.PDF.length());
 		File subRootDir = new File(pdfFile.getParentFile(), root);
 		subRootDir.mkdir();
-		File rawDir = new File(subRootDir, SVGPlusConstants.RAW);
+		File rawDir = new File(subRootDir, SVGPlusConstantsX.RAW);
 		rawDir.mkdir();
 		return rawDir;
 	}
 		File[] pdfFiles = file.listFiles(
 			new FilenameFilter() {
 				public boolean accept(File file, String name) {
-					return name.endsWith(SVGPlusConstants.PDF);
+					return name.endsWith(SVGPlusConstantsX.PDF);
 				}
 			});
 		return pdfFiles;

src/main/java/org/xmlcml/svgplus/action/DocumentWriterActionX.java

 
 import org.apache.log4j.Logger;
 import org.xmlcml.pdf2svg.util.MenuSystem;
-import org.xmlcml.svgplus.core.SVGPlusConstants;
 import org.xmlcml.svgplus.tools.RegexFilenameFilter;
 
 public class DocumentWriterActionX extends DocumentActionX {
 		String outdirName = getFilename();
 		outdir = new File(outdirName);
 		String regex = getRegex();
-		String format = getFormat(SVGPlusConstants.XML_FORMAT);
-		if (SVGPlusConstants.HTML_MENU_FORMAT.equals(format)) {
+		String format = getFormat(SVGPlusConstantsX.XML_FORMAT);
+		if (SVGPlusConstantsX.HTML_MENU_FORMAT.equals(format)) {
 			createHtmlMenu(regex);
 		}
 	}

src/main/java/org/xmlcml/svgplus/action/FigureAnalyzerActionX.java

 import org.xmlcml.graphics.svg.SVGUtil;
 import org.xmlcml.svgplus.analyzer.FigureAnalyzerX;
 import org.xmlcml.svgplus.analyzer.TextAnalyzerX;
-import org.xmlcml.svgplus.core.SVGPlusConstants;
 import org.xmlcml.svgplus.figure.Figure;
 import org.xmlcml.svgplus.figure.FigureFragment;
 import org.xmlcml.svgplus.figure.FigurePanel;
 			figureAnalyzer.createFragmentsInsidePanelsForAllFigures();
 			analyzeFigures(figureList);
 			for (Figure figure : figureList) {
-				CMLUtil.outputQuietly(figure.getFigureAnalysis(), new File(filename+"."+figure.getId()+SVGPlusConstants.XML), 1);
+				CMLUtil.outputQuietly(figure.getFigureAnalysis(), new File(filename+"."+figure.getId()+SVGPlusConstantsX.XML), 1);
 			}
 		}
 		for (Chunk figure : figureList) {
-			GraphUtil.writeFileAsSVGSVGWithMouse(filename+"."+figure.getId()+SVGPlusConstants.SVG, figure);
+			GraphUtil.writeFileAsSVGSVGWithMouse(filename+"."+figure.getId()+SVGPlusConstantsX.SVG, figure);
 		}
 	}
 

src/main/java/org/xmlcml/svgplus/action/PageActionX.java

 	}
 
 	public final static String TAG = "pageAction";
-
+	
 	// private so it can't be modified - have to copy it - is this a good idea?
 	private PageSelector pageSelector;
 	private int pageCount;

src/main/java/org/xmlcml/svgplus/action/PageEditorX.java

 import org.xmlcml.svgplus.analyzer.ChunkAnalyzerX;
 import org.xmlcml.svgplus.analyzer.DocumentAnalyzerX;
 import org.xmlcml.svgplus.analyzer.FigureAnalyzerX;
-import org.xmlcml.svgplus.analyzer.PageChunkSplitterAnalyzerX;
+import org.xmlcml.svgplus.analyzer.WhitespaceChunkerAnalyzerX;
 import org.xmlcml.svgplus.analyzer.PathAnalyzerX;
 import org.xmlcml.svgplus.analyzer.TableAnalyzerX;
 import org.xmlcml.svgplus.analyzer.TextAnalyzerX;
-import org.xmlcml.svgplus.core.SVGPlusConstants;
 import org.xmlcml.svgplus.figure.Figure;
 import org.xmlcml.svgplus.table.Table;
 
 	public static final String LAST = "last";
 	public static final String REPORTED_PAGE_NUMBER = "reportedPageNumber";
 	private static final String BEFORE_TEXT = "beforeText";
-	public static final String NAME_PREFIX = SVGPlusConstants.P;
+	public static final String NAME_PREFIX = SVGPlusConstantsX.P;
 
 	private BiMap<String, String> clipPathByIdMap;
 	
 	private PathAnalyzerX pathAnalyzerX;
 //	private PageClipPathAnalyzer clipPathAnalyzer;
 //	private PageFontSizeAnalyzer fontSizeAnalyzer;
-	private PageChunkSplitterAnalyzerX pageChunkSplitterX;
+	private WhitespaceChunkerAnalyzerX pageChunkSplitterX;
 	private TextAnalyzerX textAnalyzerX;
 	private FigureAnalyzerX figureAnalyzerX;
 	private TableAnalyzerX tableAnalyzerX;
 		}
 	}
 
-	public PageChunkSplitterAnalyzerX ensurePageChunkSplitter() {
+	public WhitespaceChunkerAnalyzerX ensureWhiteSpaceChunker() {
 		if (pageChunkSplitterX == null) {
-			pageChunkSplitterX = new PageChunkSplitterAnalyzerX(semanticDocumentActionX);
+			pageChunkSplitterX = new WhitespaceChunkerAnalyzerX(semanticDocumentActionX);
 		}
 		return pageChunkSplitterX;
 	}
 	}
 
 	private void applyBrowserScale() {
-		List<SVGElement> gList = SVGUtil.getQuerySVGElements(svgPage, ".//svg:g[@id='"+PageChunkSplitterAnalyzerX.TOP_CHUNK+"']");
+		List<SVGElement> gList = SVGUtil.getQuerySVGElements(svgPage, ".//svg:g[@id='"+WhitespaceChunkerAnalyzerX.TOP_CHUNK+"']");
 		if (gList.size() != 1) {
 			LOG.error("should have one topChunk G");
 		} else {
 //		return fontSizeAnalyzer;
 //	}
 
-	public PageChunkSplitterAnalyzerX getPageChunkSplitter() {
+	public WhitespaceChunkerAnalyzerX getPageChunkSplitter() {
 		return pageChunkSplitterX;
 	}
 

src/main/java/org/xmlcml/svgplus/action/PageIteratorActionX.java

 
 import org.apache.log4j.Logger;
 import org.xmlcml.graphics.svg.SVGSVG;
-import org.xmlcml.svgplus.core.SVGPlusConstants;
 
 public class PageIteratorActionX extends PageActionX {
 
 	private final static Logger LOG = Logger.getLogger(PageIteratorActionX.class);
 
-	public static final String PAGE_COUNT = SVGPlusConstants.D_DOT+"pageCount";
-	public static final String PAGE_NUMBER = SVGPlusConstants.P_DOT+"page";
-	private SVGPlusConverterX svgPlusConverterX;
+	public static final String PAGE_COUNT = SVGPlusConstantsX.D_DOT+"pageCount";
+	public static final String PAGE_NUMBER = SVGPlusConstantsX.P_DOT+"page";
 	private List<SVGSVG> svgPageList;
 	boolean convertPages = true; // settable by attributes later
 
 
 	private void getOrCreateSVGPageList() {
 		File infile = (File) semanticDocumentActionX.getVariable(DocumentIteratorActionX.INPUT_FILE);
+		SVGPlusConverterX svgPlusConverterX = semanticDocumentActionX.ensureSVGPlusConverter();
 		if (infile != null) {
-			ensureSVGPlusConverter();
 			svgPageList = svgPlusConverterX.createSVGPageList(infile);
 			semanticDocumentActionX.setVariable(PAGE_COUNT, svgPageList.size());
 			LOG.debug("pages "+svgPageList.size());
 		}
 	}
 	
-	private void ensureSVGPlusConverter() {
-		if (svgPlusConverterX == null) {
-			svgPlusConverterX = semanticDocumentActionX.getSVGPlusConverter();
-		}
-	}
-
 
 }

src/main/java/org/xmlcml/svgplus/action/SVGPlusConstantsX.java

+package org.xmlcml.svgplus.action;
+
+
+
+public class SVGPlusConstantsX {
+	
+	// suffixes
+	public static final String NEXML = ".nexml";
+	public static final String PDF = ".pdf";
+	public static final String SVG = ".svg";
+	public static final String XML = ".xml";
+
+	// directories
+	public static final String OUT = "out";
+	public static final String RAW = "raw";
+	public static final String FINAL = "final";
+
+	// attributes
+	public static final String ID = "id";
+
+	// file root
+	public static final String PAGE = "page";
+	
+	// variables
+	public static final String RAW_DIRECTORY = "rawDirectory";
+	public static final String RAW_DIRECTORY_LIST = "rawDirectoryList";
+	public static final String ROOT_DIR = "rootDirectory";
+	public static final String OUT_DIR = "outDir";
+	public static final String OUT_DIR_VALUE = "{$d.rawDirectory}/../out";
+	
+	// variable prefix
+	public static final String D = "d";
+	public static final String P = "p";
+	public static final String S = "s";
+	public static final String D_DOT = "d.";
+	public static final String P_DOT = "p.";
+	public static final String S_DOT = "s.";
+	public final static String[] PREFIXES = {S, D, P};
+
+	// display
+	public static final String HTML_TARGET = "target";
+	public static final String INDEX_HTML = "index.html";
+	public static final String XML_FORMAT = "xml";
+	public static final String SVG_FORMAT = "svg";
+	public static final String HTML_FORMAT = "html";
+	public static final String HTML_MENU_FORMAT = "htmlMenu";
+	
+	public static final String INPUT_FILE = "inputFile";
+	public static final String OUTPUT_DIR = "outputDir";
+}

src/main/java/org/xmlcml/svgplus/action/SVGPlusConverterX.java

 import org.xmlcml.cml.base.CMLConstants;
 import org.xmlcml.graphics.svg.SVGSVG;
 import org.xmlcml.pdf2svg.PDF2SVGConverter;
-import org.xmlcml.svgplus.core.SVGPlusConstants;
 
 /**
  * Converts raw SVG to structured SVG
 
 	private FilenameFilter pdfFilter = new FilenameFilter() {
 		public boolean accept(File dir, String name) {
-			return name.endsWith(SVGPlusConstants.PDF);
+			return name.endsWith(SVGPlusConstantsX.PDF);
 		}
 	};
 

src/main/java/org/xmlcml/svgplus/action/SemanticDocumentActionX.java

 import nu.xom.Nodes;
 
 import org.apache.log4j.Logger;
-import org.xmlcml.svgplus.command.VariableStore;
-import org.xmlcml.svgplus.core.SVGPlusConstants;
 import org.xmlcml.svgplus.text.SimpleFont;
 
 public class SemanticDocumentActionX extends DocumentActionX {
 	private final static Logger LOG = Logger.getLogger(SemanticDocumentActionX.class);
 
 	public static final String INFILE = "infile";
-	public static final String S_INFILE = SVGPlusConstants.S_DOT+INFILE;
-	public static final String OUTFILE = "outfile";
-	public static final String S_OUTFILE = SVGPlusConstants.S_DOT+OUTFILE;
+	public static final String S_INFILE = SVGPlusConstantsX.S_DOT+INFILE;
+	public static final String S_OUTFILE = SVGPlusConstantsX.S_DOT+OUTFILE;
 	public static final String SEMDOC = "semdoc";
-	public static final String S_SEMDOC = SVGPlusConstants.S_DOT+SEMDOC;
+	public static final String S_SEMDOC = SVGPlusConstantsX.S_DOT+SEMDOC;
 	
 	private String semanticDocumentFilename;
 	private VariableStore variableStore;
 		return DEFAULT_COMMAND_FILENAME;
 	}
 	
-	private DocumentIteratorActionX documentIteratorElement;
+	private DocumentActionX documentIteratorElement;
 //	private AbstractActionX semanticDocumentActionX;
 
 	/** constructor
 		return TAG;
 	}
 
-	public DocumentIteratorActionX getDocumentIteratorElement() {
+	public DocumentActionX getDocumentIteratorElement() {
 		if (documentIteratorElement == null) {
 			Nodes nodes = this.query(DocumentIteratorActionX.TAG);
 			documentIteratorElement =  (nodes.size() == 1) ? (DocumentIteratorActionX) nodes.get(0) : null;
 		return pageEditor;
 	}
 
+	public SVGPlusConverterX ensureSVGPlusConverter() {
+		if (svgPlusConverterX == null) {
+			svgPlusConverterX = new SVGPlusConverterX();
+		}
+		return svgPlusConverterX;
+	}
+
 }
 

src/main/java/org/xmlcml/svgplus/action/VariableActionX.java

 package org.xmlcml.svgplus.action;
 
+import java.io.File;
 import java.util.ArrayList;
-
 import java.util.Arrays;
 import java.util.List;
 import java.util.regex.Matcher;
 	public final static String TAG ="variable";
 	
 	private static final List<String> ATTNAMES = new ArrayList<String>();
+
+	private static final String FILE = "file";
 	
 	static {
 		ATTNAMES.add(AbstractActionX.LOGAT);
 		ATTNAMES.add(AbstractActionX.NAME);
+		ATTNAMES.add(AbstractActionX.TYPE);
 		ATTNAMES.add(PageActionX.VALUE);
 	}
 
 	public void run() {
 		String name = getName();
 		String value = getValueString();
+		Object objectValue = value;
+		String type = getType();
 		if (name == null || value == null) {
 			throw new RuntimeException("must give name and value attributes: "+this.toXML());
 		}
 		checkValidName(name);
+		if (FILE.equalsIgnoreCase(type)) {
+			objectValue = new File(value);
+		}
 		LOG.trace("SD "+semanticDocumentActionX);
-		semanticDocumentActionX.setVariable(name, value);
+		semanticDocumentActionX.setVariable(name, objectValue);
 //		log(getLog());
 	}
 

src/main/java/org/xmlcml/svgplus/action/VariableStore.java

+package org.xmlcml.svgplus.action;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.xmlcml.cml.base.CMLConstants;
+
+/** manages Page and Document lookup
+ *  may not be necessary
+ * 
+ * @author pm286
+ *
+ */
+public class VariableStore {
+
+	private static final Logger LOG = Logger.getLogger(VariableStore.class);
+	
+	private Map<String, Object> variableMap;
+
+	public VariableStore() {
+		
+	}
+	
+	//check name of form <p>.name where p is a 1-letter prefix
+	private static boolean checkName(String name) {
+		boolean ok = false;
+		if (name != null) {
+			String[] names = name.split(CMLConstants.S_BACKSLASH+CMLConstants.S_PERIOD);
+			if (names.length == 2){
+				if (names[0].length() == 1) {
+					for (String prefix : SVGPlusConstantsX.PREFIXES) {
+						if (prefix.equals(names[0])) {
+							ok = true;
+							break;
+						}
+					}
+				}
+			}
+		}
+		return ok;
+	}
+	
+	/** returns keys in sorted order
+	 * 
+	 */
+	public List<String> getVariableNames() {
+		ensureVariableMap();
+		List<String> keyList = new ArrayList<String>();
+		Set<String> keySet = variableMap.keySet();
+		if (keySet != null && keySet.size() > 0) {
+			if (!keyList.addAll(keySet)) {
+				throw new RuntimeException("Cannot add keys");
+			}
+			Collections.sort(keyList);
+		}
+		return keyList;
+	}
+
+	private void ensureVariableMap() {
+		if (variableMap == null) {
+			variableMap = new HashMap<String, Object>();
+		}
+	}
+
+	public Object getVariable(String name) {
+		ensureVariableMap();
+		Object obj = null;
+		if (checkName(name)) {
+			obj = variableMap.get(name);
+		}
+		return obj;
+	}
+
+	public void setVariable(String name, Object value) {
+		ensureVariableMap();
+		if (checkName(name)) {
+			variableMap.put(name, value);
+		} else {
+			throw new RuntimeException("Bad variable name: "+name);
+		}
+	}
+
+	public int size() {
+		ensureVariableMap();
+		return variableMap.size();
+	}
+
+	public String debugString(String title) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("\n"+title+"\n");
+		if (variableMap != null) {
+			sb.append("values: "+this.size()+"\n");
+			String[] keys = variableMap.keySet().toArray(new String[0]);
+			Arrays.sort(keys);
+			for (String key : keys) {
+				sb.append("  "+key+" = "+variableMap.get(key)+"\n");
+			}
+		}
+		return sb.toString();
+	}
+
+	public Set<String> keySet() {
+		ensureVariableMap();
+		return variableMap.keySet();
+	}
+
+	public void deleteKey(String name) {
+		ensureVariableMap();
+		variableMap.remove(name);
+//		Object obj = variableMap.get(name);
+//		if (obj != null) {
+//			variableMap.remove(obj);
+//		}
+	}
+	
+}

src/main/java/org/xmlcml/svgplus/action/WhitespaceChunkerActionX.java

 import nu.xom.Node;
 
 import org.apache.log4j.Logger;
-import org.xmlcml.svgplus.analyzer.PageChunkSplitterAnalyzerX;
+import org.xmlcml.svgplus.analyzer.WhitespaceChunkerAnalyzerX;
 import org.xmlcml.svgplus.tools.Chunk;
 /**
 	<pageAction action="createWhitespaceChunks" depth="3"/>
 	
 	@Override
 	public void run() {
-		PageChunkSplitterAnalyzerX pageChunkSplitterX = getPageEditor().ensurePageChunkSplitter();
+		WhitespaceChunkerAnalyzerX whiteSpaceChunkerAnalyzer = getPageEditor().ensureWhiteSpaceChunker();
 		Integer depth = getDepth();
 		if (depth != null) {
 			LOG.trace("DEPTH cannot yet be set");
 		}
-		List<Chunk> finalChunkList = pageChunkSplitterX.splitByWhitespace();
-		pageChunkSplitterX.labelLeafNodes(finalChunkList);
+		List<Chunk> finalChunkList = whiteSpaceChunkerAnalyzer.splitByWhitespace();
+		whiteSpaceChunkerAnalyzer.labelLeafNodes(finalChunkList);
 	}
 
 }

src/main/java/org/xmlcml/svgplus/analyzer/PageChunkSplitterAnalyzerX.java

-package org.xmlcml.svgplus.analyzer;
-
-import java.util.ArrayList;
-
-import java.util.Arrays;
-import java.util.List;
-
-import nu.xom.Attribute;
-
-import org.apache.log4j.Logger;
-import org.xmlcml.graphics.svg.SVGElement;
-import org.xmlcml.graphics.svg.SVGUtil;
-import org.xmlcml.svgplus.action.SemanticDocumentActionX;
-import org.xmlcml.svgplus.tools.BoundingBoxManager.BoxEdge;
-import org.xmlcml.svgplus.tools.Chunk;
-import org.xmlcml.svgplus.tools.SplitterParams;
-
-/**
- * page-oriented
- * 
- * slices the page up into chunks using continuous whitespace. 
- * Can then recurse. Most obvious strategy is:
- * 1 slice Y (i.e. horizontal borders)
- * 2 slice X on results of 1
- * 3 slice Y on results of 2
- * 
- * determine types of chunk after this and apply different strategies
- * 
- * analyze(control) is the only meaningful public routine and by default will analyze
- * * text
- * * paths (transforming to rect, line, polyline, circle)
- * * figures
- * * tables
- * 
- * each of these has a special analyzer (TextAnalyzer, etc.)
- * 
- * pageChunkSplitter communicates upwards through currentPage
- * @author pm286
- *
- */
-public class PageChunkSplitterAnalyzerX extends AbstractPageAnalyzerX {
-	private static final Logger LOG = Logger.getLogger(PageChunkSplitterAnalyzerX.class);
-
-	public static final String CLIP = "CLIP";
-	public static final String WHITE = "WHITE";
-
-	public static final String YMIN_XMIN_YMIN = ".//svg:g[@edge='YMIN']/svg:g[@edge='XMIN']/svg:g[@edge='YMIN']";
-
-	private static final String LEAF = "LEAF";
-	public static final String TOP_CHUNK = "topChunk";
-
-	
-	private List<SplitterParams> splitterParams = null;
-	
-	
-	// empirical borderwidths
-	// Y0, X0, Y1, X1...
-	private static double YSEP_0 = 10.;
-	private static Double YSEP_1 = 5.;
-	private static Double XSEP_0 = 10.0;
-	
-	private List<Chunk> finalChunkList;
-
-	public PageChunkSplitterAnalyzerX(SemanticDocumentActionX semanticDocumentActionX) {
-		super(semanticDocumentActionX);
-		init();
-	}
-	
-	private void init() {
-		setSplitterParams(
-				new SplitterParams[] {
-				new SplitterParams(BoxEdge.YMIN, YSEP_0),
-				new SplitterParams(BoxEdge.XMIN, XSEP_0),
-				new SplitterParams(BoxEdge.YMIN, YSEP_1)
-				}
-		);
-	}
-
-	public void setSplitterParams(SplitterParams[] spParams) {
-		this.splitterParams = Arrays.asList(spParams);
-	}
-	
-	/** the main analysis routine
-	 * includes text, paths, figures, tables
-	 */
-	public void splitByWhitespaceAndLabelLeafNodes() {
-		finalChunkList = splitByWhitespace();
-		labelLeafNodes(finalChunkList);
-	}
-	
-	public void labelLeafNodes(List<Chunk> finalChunkList) {
-		for (Chunk chunk : finalChunkList) {
-			if (SVGUtil.getQuerySVGElements(chunk, "self::svg:g[@edge='YMIN' and parent::svg:g[@edge='XMIN' and parent::svg:g[@edge='YMIN']]]").size() >0) {
-				chunk.addAttribute(new Attribute(LEAF, "3"));
-			} else if (SVGUtil.getQuerySVGElements(chunk, "self::svg:g[@edge='XMIN' and parent::svg:g[@edge='YMIN']]").size() >0) {
-				chunk.addAttribute(new Attribute(LEAF, "2"));
-			} else if (SVGUtil.getQuerySVGElements(chunk, "self::svg:g[@edge='YMIN']").size() >0) {
-				chunk.addAttribute(new Attribute(LEAF, "1"));
-			}
-		}
-		List<SVGElement> topChunks = SVGUtil.getQuerySVGElements(pageEditorX.getSVGPage(), "svg:g[@id='"+TOP_CHUNK+"']");
-		if (topChunks.size() != 1) {
-			throw new RuntimeException("Should be ONE top chunk");
-		}
-		labelXYMINDescendants((Chunk)topChunks.get(0), "chunk0");
-	}
-	
-	private void labelXYMINDescendants(Chunk chunk, String idRoot) {
-		List<SVGElement> childChunkList = SVGUtil.getQuerySVGElements(chunk, "./svg:g[contains(@edge, 'MIN')]");
-		for (int i = 0; i < childChunkList.size(); i++) {
-			Chunk childChunk = (Chunk) childChunkList.get(i);
-			String id = idRoot+"."+i;
-			childChunk.setId(id);
-			labelXYMINDescendants(childChunk, id);
-		}
-	}
-
-	// FIXME add variable levels
-	public List<Chunk> splitByWhitespace() {
-		Long time0 = System.currentTimeMillis();
-		// I could recurse, but we only have 3 levels...
-		Chunk topChunk = new Chunk(pageEditorX.getSVGPage());
-		LOG.debug("descendants0: "+topChunk.getDescendantSVGElementList().size()+"/"+(System.currentTimeMillis()-time0));
-		topChunk.setBoundingBoxCacheForSelfAndDescendants(true);
-		LOG.debug("descendants: "+topChunk.getDescendantSVGElementList().size()+"/"+(System.currentTimeMillis()-time0));
-		pageEditorX.getSVGPage().appendChild(topChunk);
-		topChunk.setId(TOP_CHUNK);
-		List<Chunk> subChunkList = topChunk.splitIntoChunks(splitterParams.get(0).width, splitterParams.get(0).boxEdge);
-		List<Chunk> subSubChunkList = new ArrayList<Chunk>();
-		List<Chunk> subSubSubChunkList = null;
-		for (Chunk subChunk : subChunkList) {
-			List<Chunk> cc = subChunk.splitIntoChunks(splitterParams.get(1).width, splitterParams.get(1).boxEdge);
-			subSubChunkList.addAll(cc);
-			subSubSubChunkList = new ArrayList<Chunk>();
-			for (Chunk subSubChunk : subSubChunkList) {
-				cc = subSubChunk.splitIntoChunks(splitterParams.get(2).width, splitterParams.get(2).boxEdge);
-				subSubSubChunkList.addAll(cc);
-			}
-		}
-		removeEmptyChunks(topChunk);
-		return subSubSubChunkList;
-	}
-
-	private void removeEmptyChunks(Chunk topChunk) {
-		List<SVGElement> emptyGList = SVGUtil.getQuerySVGElements(topChunk, "//svg:g[count(*)=0]");
-		for (SVGElement g : emptyGList) {
-			g.detach();
-		}
-	}
-	
-}

src/main/java/org/xmlcml/svgplus/analyzer/WhitespaceChunkerAnalyzerX.java

+package org.xmlcml.svgplus.analyzer;
+
+import java.util.ArrayList;
+
+import java.util.Arrays;
+import java.util.List;
+
+import nu.xom.Attribute;
+
+import org.apache.log4j.Logger;
+import org.xmlcml.graphics.svg.SVGElement;
+import org.xmlcml.graphics.svg.SVGUtil;
+import org.xmlcml.svgplus.action.SemanticDocumentActionX;
+import org.xmlcml.svgplus.tools.BoundingBoxManager.BoxEdge;
+import org.xmlcml.svgplus.tools.Chunk;
+import org.xmlcml.svgplus.tools.SplitterParams;
+
+/**
+ * page-oriented
+ * 
+ * slices the page up into chunks using continuous whitespace. 
+ * Can then recurse. Most obvious strategy is:
+ * 1 slice Y (i.e. horizontal borders)
+ * 2 slice X on results of 1
+ * 3 slice Y on results of 2
+ * 
+ * determine types of chunk after this and apply different strategies
+ * 
+ * analyze(control) is the only meaningful public routine and by default will analyze
+ * * text
+ * * paths (transforming to rect, line, polyline, circle)
+ * * figures
+ * * tables
+ * 
+ * each of these has a special analyzer (TextAnalyzer, etc.)
+ * 
+ * pageChunkSplitter communicates upwards through currentPage
+ * @author pm286
+ *
+ */
+public class WhitespaceChunkerAnalyzerX extends AbstractPageAnalyzerX {
+	private static final Logger LOG = Logger.getLogger(WhitespaceChunkerAnalyzerX.class);
+
+	public static final String CLIP = "CLIP";
+	public static final String WHITE = "WHITE";
+
+	public static final String YMIN_XMIN_YMIN = ".//svg:g[@edge='YMIN']/svg:g[@edge='XMIN']/svg:g[@edge='YMIN']";
+
+	private static final String LEAF = "LEAF";
+	public static final String TOP_CHUNK = "topChunk";
+
+	
+	private List<SplitterParams> splitterParams = null;
+	
+	
+	// empirical borderwidths
+	// Y0, X0, Y1, X1...
+	private static double YSEP_0 = 10.;
+	private static Double YSEP_1 = 5.;
+	private static Double XSEP_0 = 10.0;
+	
+	private List<Chunk> finalChunkList;
+
+	public WhitespaceChunkerAnalyzerX(SemanticDocumentActionX semanticDocumentActionX) {
+		super(semanticDocumentActionX);
+		init();
+	}
+	
+	private void init() {
+		setSplitterParams(
+				new SplitterParams[] {
+				new SplitterParams(BoxEdge.YMIN, YSEP_0),
+				new SplitterParams(BoxEdge.XMIN, XSEP_0),
+				new SplitterParams(BoxEdge.YMIN, YSEP_1)
+				}
+		);
+	}
+
+	public void setSplitterParams(SplitterParams[] spParams) {
+		this.splitterParams = Arrays.asList(spParams);
+	}
+	
+	/** the main analysis routine
+	 * includes text, paths, figures, tables
+	 */
+	public void splitByWhitespaceAndLabelLeafNodes() {
+		finalChunkList = splitByWhitespace();
+		labelLeafNodes(finalChunkList);
+	}
+	
+	public void labelLeafNodes(List<Chunk> finalChunkList) {
+		for (Chunk chunk : finalChunkList) {
+			if (SVGUtil.getQuerySVGElements(chunk, "self::svg:g[@edge='YMIN' and parent::svg:g[@edge='XMIN' and parent::svg:g[@edge='YMIN']]]").size() >0) {
+				chunk.addAttribute(new Attribute(LEAF, "3"));
+			} else if (SVGUtil.getQuerySVGElements(chunk, "self::svg:g[@edge='XMIN' and parent::svg:g[@edge='YMIN']]").size() >0) {
+				chunk.addAttribute(new Attribute(LEAF, "2"));
+			} else if (SVGUtil.getQuerySVGElements(chunk, "self::svg:g[@edge='YMIN']").size() >0) {
+				chunk.addAttribute(new Attribute(LEAF, "1"));
+			}
+		}
+		List<SVGElement> topChunks = SVGUtil.getQuerySVGElements(pageEditorX.getSVGPage(), "svg:g[@id='"+TOP_CHUNK+"']");
+		if (topChunks.size() != 1) {
+			throw new RuntimeException("Should be ONE top chunk");
+		}
+		labelXYMINDescendants((Chunk)topChunks.get(0), "chunk0");
+	}
+	
+	private void labelXYMINDescendants(Chunk chunk, String idRoot) {
+		List<SVGElement> childChunkList = SVGUtil.getQuerySVGElements(chunk, "./svg:g[contains(@edge, 'MIN')]");
+		for (int i = 0; i < childChunkList.size(); i++) {
+			Chunk childChunk = (Chunk) childChunkList.get(i);
+			String id = idRoot+"."+i;
+			childChunk.setId(id);
+			labelXYMINDescendants(childChunk, id);
+		}
+	}
+
+	// FIXME add variable levels
+	public List<Chunk> splitByWhitespace() {
+		Long time0 = System.currentTimeMillis();
+		// I could recurse, but we only have 3 levels...
+		Chunk topChunk = new Chunk(pageEditorX.getSVGPage());
+		LOG.debug("descendants0: "+topChunk.getDescendantSVGElementList().size()+"/"+(System.currentTimeMillis()-time0));
+		topChunk.setBoundingBoxCacheForSelfAndDescendants(true);
+		LOG.debug("descendants: "+topChunk.getDescendantSVGElementList().size()+"/"+(System.currentTimeMillis()-time0));
+		pageEditorX.getSVGPage().appendChild(topChunk);
+		topChunk.setId(TOP_CHUNK);
+		List<Chunk> subChunkList = topChunk.splitIntoChunks(splitterParams.get(0).width, splitterParams.get(0).boxEdge);
+		List<Chunk> subSubChunkList = new ArrayList<Chunk>();
+		List<Chunk> subSubSubChunkList = null;
+		for (Chunk subChunk : subChunkList) {
+			List<Chunk> cc = subChunk.splitIntoChunks(splitterParams.get(1).width, splitterParams.get(1).boxEdge);
+			subSubChunkList.addAll(cc);
+			subSubSubChunkList = new ArrayList<Chunk>();
+			for (Chunk subSubChunk : subSubChunkList) {
+				cc = subSubChunk.splitIntoChunks(splitterParams.get(2).width, splitterParams.get(2).boxEdge);
+				subSubSubChunkList.addAll(cc);
+			}
+		}
+		removeEmptyChunks(topChunk);
+		return subSubSubChunkList;
+	}
+
+	private void removeEmptyChunks(Chunk topChunk) {
+		List<SVGElement> emptyGList = SVGUtil.getQuerySVGElements(topChunk, "//svg:g[count(*)=0]");
+		for (SVGElement g : emptyGList) {
+			g.detach();
+		}
+	}
+	
+}

src/main/java/org/xmlcml/svgplus/command/VariableStore.java

-package org.xmlcml.svgplus.command;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.log4j.Logger;
-import org.xmlcml.cml.base.CMLConstants;
-import org.xmlcml.svgplus.core.SVGPlusConstants;
-
-/** manages Page and Document lookup
- *  may not be necessary
- * 
- * @author pm286
- *
- */
-public class VariableStore {
-
-	private static final Logger LOG = Logger.getLogger(VariableStore.class);
-	
-	private Map<String, Object> variableMap;
-
-	public VariableStore() {
-		
-	}
-	
-	//check name of form <p>.name where p is a 1-letter prefix
-	private static boolean checkName(String name) {
-		boolean ok = false;
-		if (name != null) {
-			String[] names = name.split(CMLConstants.S_BACKSLASH+CMLConstants.S_PERIOD);
-			if (names.length == 2){
-				if (names[0].length() == 1) {
-					for (String prefix : SVGPlusConstants.PREFIXES) {
-						if (prefix.equals(names[0])) {
-							ok = true;
-							break;
-						}
-					}
-				}
-			}
-		}
-		return ok;
-	}
-	
-	/** returns keys in sorted order
-	 * 
-	 */
-	public List<String> getVariableNames() {
-		ensureVariableMap();
-		List<String> keyList = new ArrayList<String>();
-		Set<String> keySet = variableMap.keySet();
-		if (keySet != null && keySet.size() > 0) {
-			if (!keyList.addAll(keySet)) {
-				throw new RuntimeException("Cannot add keys");
-			}
-			Collections.sort(keyList);
-		}
-		return keyList;
-	}
-
-	private void ensureVariableMap() {
-		if (variableMap == null) {
-			variableMap = new HashMap<String, Object>();
-		}
-	}
-
-	public Object getVariable(String name) {
-		ensureVariableMap();
-		Object obj = null;
-		if (checkName(name)) {
-			obj = variableMap.get(name);
-		}
-		return obj;
-	}
-
-	public void setVariable(String name, Object value) {
-		ensureVariableMap();
-		if (checkName(name)) {
-			variableMap.put(name, value);
-		} else {
-			throw new RuntimeException("Bad variable name: "+name);
-		}
-	}
-
-	public int size() {
-		ensureVariableMap();
-		return variableMap.size();
-	}
-
-	public String debugString(String title) {
-		StringBuilder sb = new StringBuilder();
-		sb.append("\n"+title+"\n");
-		if (variableMap != null) {
-			sb.append("values: "+this.size()+"\n");
-			String[] keys = variableMap.keySet().toArray(new String[0]);
-			Arrays.sort(keys);
-			for (String key : keys) {
-				sb.append("  "+key+" = "+variableMap.get(key)+"\n");
-			}
-		}
-		return sb.toString();
-	}
-
-	public Set<String> keySet() {
-		ensureVariableMap();
-		return variableMap.keySet();
-	}
-
-	public void deleteKey(String name) {
-		ensureVariableMap();
-		variableMap.remove(name);
-//		Object obj = variableMap.get(name);
-//		if (obj != null) {
-//			variableMap.remove(obj);
-//		}
-	}
-	
-}

src/main/java/org/xmlcml/svgplus/core/SVGPlusConstants.java

-package org.xmlcml.svgplus.core;
-
-
-
-public class SVGPlusConstants {
-	
-	// suffixes
-	public static final String NEXML = ".nexml";
-	public static final String PDF = ".pdf";
-	public static final String SVG = ".svg";
-	public static final String XML = ".xml";
-
-	// directories
-	public static final String OUT = "out";
-	public static final String RAW = "raw";
-	public static final String FINAL = "final";
-
-	// attributes
-	public static final String ID = "id";
-
-	// file root
-	public static final String PAGE = "page";
-	
-	// variables
-	public static final String RAW_DIRECTORY = "rawDirectory";
-	public static final String RAW_DIRECTORY_LIST = "rawDirectoryList";
-	public static final String ROOT_DIR = "rootDirectory";
-	public static final String OUT_DIR = "outDir";
-	public static final String OUT_DIR_VALUE = "{$d.rawDirectory}/../out";
-	
-	// variable prefix
-	public static final String D = "d";
-	public static final String P = "p";
-	public static final String S = "s";
-	public static final String D_DOT = "d.";
-	public static final String P_DOT = "p.";
-	public static final String S_DOT = "s.";
-	public final static String[] PREFIXES = {S, D, P};
-
-	// display
-	public static final String HTML_TARGET = "target";
-	public static final String INDEX_HTML = "index.html";
-	public static final String XML_FORMAT = "xml";
-	public static final String SVG_FORMAT = "svg";
-	public static final String HTML_FORMAT = "html";
-	public static final String HTML_MENU_FORMAT = "htmlMenu";
-	
-	public static final String INPUT_FILE = "inputFile";
-	public static final String OUTPUT_DIR = "outputDir";
-}

src/main/java/org/xmlcml/svgplus/figure/Figure.java

 import org.apache.log4j.Logger;
 import org.xmlcml.graphics.svg.SVGElement;
 import org.xmlcml.graphics.svg.SVGUtil;
+import org.xmlcml.svgplus.action.SVGPlusConstantsX;
 import org.xmlcml.svgplus.analyzer.FigureAnalyzerX;
-import org.xmlcml.svgplus.core.SVGPlusConstants;
 import org.xmlcml.svgplus.tools.BoundingBoxManager.BoxEdge;
 import org.xmlcml.svgplus.tools.Caption;
 import org.xmlcml.svgplus.tools.Chunk;
 		figureAnalysis = new Element(FIGURE_TAG);
 		String id = this.getId();
 		if (id != null) {
-			figureAnalysis.addAttribute(new Attribute(SVGPlusConstants.ID, id));
+			figureAnalysis.addAttribute(new Attribute(SVGPlusConstantsX.ID, id));
 		}
 		if (figureBody.getBodyAnalysis() != null) {
 			figureAnalysis.appendChild(figureBody.getBodyAnalysis().copy());

src/main/java/org/xmlcml/svgplus/figure/FigureBody.java

 import org.xmlcml.euclid.Real2;
 import org.xmlcml.graphics.svg.SVGElement;
 import org.xmlcml.graphics.svg.SVGG;
+import org.xmlcml.svgplus.action.SVGPlusConstantsX;
 import org.xmlcml.svgplus.analyzer.FigureAnalyzerX;
-import org.xmlcml.svgplus.core.SVGPlusConstants;
 import org.xmlcml.svgplus.tools.Chunk;
 
 /** FigureBody consists of the non-caption part of the figure
 			bodyAnalysis = new Element(BODY_TAG);
 			String id = this.getId();
 			if (id != null) {
-				bodyAnalysis.addAttribute(new Attribute(SVGPlusConstants.ID, id));
+				bodyAnalysis.addAttribute(new Attribute(SVGPlusConstantsX.ID, id));
 			}
 			FigureAnalyzerX figureAnalyzer = figure.getFigureAnalyzer();
 			Real2 margins = figureAnalyzer.getClusterWhitespaceBoxMargins();

src/main/java/org/xmlcml/svgplus/figure/FigureFragment.java

 import org.xmlcml.graphics.svg.SVGRect;
 import org.xmlcml.graphics.svg.SVGText;
 import org.xmlcml.graphics.svg.SVGUtil;
-import org.xmlcml.svgplus.core.SVGPlusConstants;
+import org.xmlcml.svgplus.action.SVGPlusConstantsX;
 import org.xmlcml.svgplus.paths.ComplexLine;
 import org.xmlcml.svgplus.paths.ComplexLine.LineOrientation;
 import org.xmlcml.svgplus.util.GraphUtil;
 		extractPrimitives();
 		LOG.trace(toString());
 		primitivesElement = new Element(FRAGMENT_TAG);
-		primitivesElement.addAttribute(new Attribute(SVGPlusConstants.ID, id));
+		primitivesElement.addAttribute(new Attribute(SVGPlusConstantsX.ID, id));
 		analyzeCircles();
 		analyzeImages();
 		analyzeLines();

src/main/java/org/xmlcml/svgplus/figure/FigurePanel.java

 import org.xmlcml.euclid.Real2;
 import org.xmlcml.graphics.svg.SVGElement;
 import org.xmlcml.graphics.svg.SVGUtil;
-import org.xmlcml.svgplus.core.SVGPlusConstants;
+import org.xmlcml.svgplus.action.SVGPlusConstantsX;
 import org.xmlcml.svgplus.tools.Chunk;
 
 /** FigurePanels are logical subunits of the FigureBody
 
 	private void makeAggregateAnalysis() {
 		panelAnalysis = new Element(PANEL_TAG);
-		panelAnalysis.addAttribute(new Attribute(SVGPlusConstants.ID, this.getId()));
+		panelAnalysis.addAttribute(new Attribute(SVGPlusConstantsX.ID, this.getId()));
 		for (FigureFragment fragment : fragmentList) {
 			Element primitives = fragment.getPrimitivesElement();
 			if (primitives != null) {

src/main/java/org/xmlcml/svgplus/tools/Chunk.java

 			}
 		}
 		LOG.trace("emptyBoxCount "+emptyBoxList.size());
-		for (Real2Range r2r : emptyBoxList) {
-			LOG.trace("EmptyBox "+r2r);
-			if (r2r.getXRange() == null || r2r.getYRange() == null) {
-				throw new RuntimeException("Null empty box");
-			}
-		}
+		checkAndDebugEmptyBoxes();
 		LOG.trace("======");
 		LOG.trace("iterations: "+count+" loop count time: "+(System.currentTimeMillis()-time0));
 		for (Chunk chunk0 : chunkList) {
 		LOG.trace("reformat chunkList: "+chunkList.size()+"/"+(System.currentTimeMillis()-time0));
 		return chunkList;
 	}
+
+	private void checkAndDebugEmptyBoxes() {
+		for (Real2Range r2r : emptyBoxList) {
+			LOG.trace("EmptyBox "+r2r);
+			if (r2r.getXRange() == null || r2r.getYRange() == null) {
+				throw new RuntimeException("Null empty box");
+			}
+		}
+	}
 	
 	private Real2Range addTerminatingEmptyBox(double chunkWidth, BoxEdge edge) {
 		Real2Range bbox = null;

src/test/java/org/xmlcml/svgplus/Fixtures.java

 package org.xmlcml.svgplus;
 
 import java.io.File;
+import java.util.List;
 
 import nu.xom.Builder;
 import nu.xom.Element;
 
 import org.xmlcml.graphics.svg.SVGElement;
+import org.xmlcml.graphics.svg.SVGRect;
 import org.xmlcml.graphics.svg.SVGSVG;
 import org.xmlcml.svgplus.action.SemanticDocumentActionX;
+import org.xmlcml.svgplus.tools.Chunk;
 
 public class Fixtures {
 
 	public static final String ACTION_DIR = SVGPLUS_DIR+"action/";
 	
 	public static final String AJC_PAGE6_PDF = CORE_DIR+"ajc-page6.pdf";
+	
 	public final static File NOOP_FILE = new File(CORE_DIR+"noopTst.xml");
 	public final static File BASIC_FILE = new File(CORE_DIR+"basicTst.xml");
 	public static final File INCLUDE_TEST_FILE = new File(CORE_DIR+"includeTst.xml");
 	public static final File AJC6_SVG = new File(Fixtures.COMMAND_DIR+"ajc6.svg");
 	public static final File POLICIES_SVG = new File(Fixtures.COMMAND_DIR+"policies.svg");
 	public static final File CHUNK_ANALYZE = new File(Fixtures.ACTION_DIR+"chunkAnalyzeTst.xml");
+	public static final File CHUNK_ANALYZE0 = new File(Fixtures.ACTION_DIR+"chunkAnalyzeTst0.xml");
+	public static final File CHUNK_ANALYZE_POLICIES = new File(Fixtures.ACTION_DIR+"chunkAnalyzePolicies.xml");
 	
 	public static SemanticDocumentActionX getSemanticDocumentAction(File commandFile) {
 		SemanticDocumentActionX semanticDocumentAction = null;
 		return semanticDocumentAction;
 	}
 
+	public static void drawChunkBoxes(SemanticDocumentActionX semanticDocumentAction,
+			List<Chunk> finalChunkList) {
+		for (Chunk chunk : finalChunkList) {
+			SVGRect bbox = chunk.createGraphicalBoundingBox();
+			if (bbox != null) {
+				chunk.appendChild(bbox);
+			}
+		}
+	}
 }

src/test/java/org/xmlcml/svgplus/action/ChunkAnalyzerTest.java

+package org.xmlcml.svgplus.action;
+
+import java.io.FileOutputStream;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.junit.Assert;
+import org.junit.Test;
+import org.xmlcml.cml.base.CMLUtil;
+import org.xmlcml.graphics.svg.SVGSVG;
+import org.xmlcml.svgplus.Fixtures;
+import org.xmlcml.svgplus.analyzer.WhitespaceChunkerAnalyzerX;
+import org.xmlcml.svgplus.tools.Chunk;
+
+public class ChunkAnalyzerTest {
+
+	private final static Logger LOG = Logger.getLogger(ChunkAnalyzerTest.class);
+	
+	@Test
+	public void testChunkAnalyze() throws Exception {
+		SemanticDocumentActionX semanticDocumentAction = SemanticDocumentActionX.createSemanticDocument(Fixtures.CHUNK_ANALYZE);
+		semanticDocumentAction.run();
+	}
+
+	@Test
+	public void testChunkAnalyze0() throws Exception {
+		SemanticDocumentActionX semanticDocumentAction = SemanticDocumentActionX.createSemanticDocument(Fixtures.CHUNK_ANALYZE0);
+		semanticDocumentAction.run();
+	}
+
+
+}

src/test/java/org/xmlcml/svgplus/action/WhitespaceChunkerXTest.java

 import org.xmlcml.graphics.svg.SVGRect;
 import org.xmlcml.graphics.svg.SVGSVG;
 import org.xmlcml.svgplus.Fixtures;
-import org.xmlcml.svgplus.analyzer.PageChunkSplitterAnalyzerX;
+import org.xmlcml.svgplus.analyzer.WhitespaceChunkerAnalyzerX;
 import org.xmlcml.svgplus.tools.Chunk;
 
 public class WhitespaceChunkerXTest {
 	public void testPageSplitter0() throws Exception {
 		SemanticDocumentActionX semanticDocumentAction = Fixtures.createSemanticDocumentActionWithSVGPage(Fixtures.PAGE0_SVG);
 		SVGSVG svgPage = semanticDocumentAction.getSVGPage();
-		PageChunkSplitterAnalyzerX pageChunkSplitterAnalyzer = new PageChunkSplitterAnalyzerX(semanticDocumentAction);
+		WhitespaceChunkerAnalyzerX pageChunkSplitterAnalyzer = new WhitespaceChunkerAnalyzerX(semanticDocumentAction);
 		List<Chunk> finalChunkList = pageChunkSplitterAnalyzer.splitByWhitespace();
 		Assert.assertNotNull(finalChunkList);
 		Assert.assertEquals("chunks", 15, finalChunkList.size());
-		drawChunkBoxes(semanticDocumentAction, finalChunkList);
+		Fixtures.drawChunkBoxes(semanticDocumentAction, finalChunkList);
 		CMLUtil.debug(semanticDocumentAction.getSVGPage(), new FileOutputStream("target/pageSplitter0.svg"), 1);
 	}
 
 	public void testHarter3() throws Exception {
 		SemanticDocumentActionX semanticDocumentAction = Fixtures.createSemanticDocumentActionWithSVGPage(Fixtures.HARTER3_SVG);
 		SVGSVG svgPage = semanticDocumentAction.getSVGPage();
-		PageChunkSplitterAnalyzerX pageChunkSplitterAnalyzer = new PageChunkSplitterAnalyzerX(semanticDocumentAction);
+		WhitespaceChunkerAnalyzerX pageChunkSplitterAnalyzer = new WhitespaceChunkerAnalyzerX(semanticDocumentAction);
 		List<Chunk> finalChunkList = pageChunkSplitterAnalyzer.splitByWhitespace();
 		Assert.assertNotNull(finalChunkList);
 		Assert.assertEquals("chunks", 29, finalChunkList.size());
-		drawChunkBoxes(semanticDocumentAction, finalChunkList);
+		Fixtures.drawChunkBoxes(semanticDocumentAction, finalChunkList);
 		CMLUtil.debug(semanticDocumentAction.getSVGPage(), new FileOutputStream("target/testHarter3.svg"), 1);
 	}
 
 	public void testHarter3small() throws Exception {
 		SemanticDocumentActionX semanticDocumentAction = Fixtures.createSemanticDocumentActionWithSVGPage(Fixtures.HARTER3SMALL_SVG);
 		SVGSVG svgPage = semanticDocumentAction.getSVGPage();
-		PageChunkSplitterAnalyzerX pageChunkSplitterAnalyzer = new PageChunkSplitterAnalyzerX(semanticDocumentAction);
+		WhitespaceChunkerAnalyzerX pageChunkSplitterAnalyzer = new WhitespaceChunkerAnalyzerX(semanticDocumentAction);
 		List<Chunk> finalChunkList = pageChunkSplitterAnalyzer.splitByWhitespace();
 		Assert.assertNotNull(finalChunkList);
 		Assert.assertEquals("chunks", 29, finalChunkList.size());
-		drawChunkBoxes(semanticDocumentAction, finalChunkList);
+		Fixtures.drawChunkBoxes(semanticDocumentAction, finalChunkList);
 		CMLUtil.debug(semanticDocumentAction.getSVGPage(), new FileOutputStream("target/testHarter3small.svg"), 1);
 	}
 
 		testSplit(Fixtures.AJC6_SVG, 14, new File("target/page6.svg"));
 	}
 	
-	private static void drawChunkBoxes(SemanticDocumentActionX semanticDocumentAction,
-			List<Chunk> finalChunkList) {
-		for (Chunk chunk : finalChunkList) {
-			SVGRect bbox = chunk.createGraphicalBoundingBox();
-			if (bbox != null) {
-				chunk.appendChild(bbox);
-			}
-		}
-	}
 
 	private static void testSplit(File svgFile, int chunkCount, File outputFile) {
 		try {
 			SemanticDocumentActionX semanticDocumentAction = Fixtures.createSemanticDocumentActionWithSVGPage(svgFile);
 			SVGSVG svgPage = semanticDocumentAction.getSVGPage();
-			PageChunkSplitterAnalyzerX pageChunkSplitterAnalyzer = new PageChunkSplitterAnalyzerX(semanticDocumentAction);
+			WhitespaceChunkerAnalyzerX pageChunkSplitterAnalyzer = new WhitespaceChunkerAnalyzerX(semanticDocumentAction);
 			List<Chunk> finalChunkList = pageChunkSplitterAnalyzer.splitByWhitespace();
 			Assert.assertNotNull(finalChunkList);
 			Assert.assertEquals("chunks", chunkCount, finalChunkList.size());
-			drawChunkBoxes(semanticDocumentAction, finalChunkList);
+			Fixtures.drawChunkBoxes(semanticDocumentAction, finalChunkList);
 			CMLUtil.debug(semanticDocumentAction.getSVGPage(), new FileOutputStream(outputFile), 1);
 		} catch (Exception e){
 			throw new RuntimeException("Cannot test", e);

src/test/resources/org/xmlcml/svgplus/action/chunkAnalyzePolicies.xml

+<semanticDocument xmlns="http://www.xml-cml.org/schema/ami2">
+  <documentIterator filename="src/test/resources/org/xmlcml/svgplus/action/svg/policies.svg">
+    <pageIterator>
+      <assert name="d.outputDir" value="target" fail="true"/>
+      <variable name="p.root" value="${d.outputDir}/whitespace_${p.page}" />
+      <assert name="p.root" value="target/whitespace_1" fail="true"/>
+      <whitespaceChunker depth="3" />
+      <chunkAnalyzer/>
+      <pageWriter filename="${p.root}_end.svg" />
+    </pageIterator>
+  </documentIterator>
+</semanticDocument>
+
+
+

src/test/resources/org/xmlcml/svgplus/action/chunkAnalyzeTst.xml

 <semanticDocument xmlns="http://www.xml-cml.org/schema/ami2">
-  <documentIterator filename="src/test/resources/org/xmlcml/svgplus/command/policies.pdf">
+  <documentIterator filename="src/test/resources/org/xmlcml/svgplus/action/pdf/policies.pdf" outfile="target/chunkAnalyzer">
     <pageIterator>
-      <assert name="d.outputDir" value="target" fail="true"/>
-      <variable name="p.root" value="${d.outputDir}/whitespace_${p.page}" />
-      <assert name="p.root" value="target/whitespace_1" fail="true"/>
+      <assert name="d.outputDir" value="target/chunkAnalyzer" fail="true"/>
+      <variable name="p.root" value="${d.outputDir}/whitespace_${p.page}" type="file"/>
+      <assert name="p.root" value="target/chunkAnalyzer/whitespace_1" fail="true"/>
       <whitespaceChunker depth="3" />
+      <pageWriter filename="target/chunked.svg" />
       <chunkAnalyzer/>
       <pageWriter filename="${p.root}_end.svg" />
     </pageIterator>

src/test/resources/org/xmlcml/svgplus/action/chunkAnalyzeTst0.xml

+<semanticDocument xmlns="http://www.xml-cml.org/schema/ami2">
+  <documentIterator filename="src/test/resources/org/xmlcml/svgplus/action/pdf/twoChunks.pdf" outfile="target/chunkAnalyzer">
+    <pageIterator>
+      <assert name="d.outputDir" value="target/chunkAnalyzer" fail="true"/>
+      <variable name="p.root" value="${d.outputDir}/whitespace_${p.page}" type="file"/>
+      <assert name="p.root" value="target/chunkAnalyzer/whitespace_1" fail="true"/>
+      <whitespaceChunker depth="3" />
+      <pageWriter filename="target/chunked.svg" />
+      <chunkAnalyzer/>
+      <pageWriter filename="${p.root}_end.svg" />
+    </pageIterator>
+  </documentIterator>
+</semanticDocument>
+
+
+

src/test/resources/org/xmlcml/svgplus/action/pdf/chunk0.docx

Binary file added.

src/test/resources/org/xmlcml/svgplus/action/pdf/twoChunks.docx

Binary file added.

src/test/resources/org/xmlcml/svgplus/action/pdf/twoChunks.pdf

Binary file added.

src/test/resources/org/xmlcml/svgplus/action/pdf/~$oChunks.docx

Binary file added.

src/test/resources/org/xmlcml/svgplus/core/page_2.svg

+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="800.0" stroke="none" stroke-width="0.0" xmlns="http://www.w3.org/2000/svg" xmlns:svgx="http://www.xml-cml.org/schema/svgx">
+ <text stroke="#000000" font-family="Verdana" x="93.624" y="82.0" font-size="12.0"> </text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="93.624" y="112.98" font-size="12.0" font-style="bold">1</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="100.34" y="112.98" font-size="12.0" font-style="bold"> </text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="115.22" y="112.98" font-size="12.0" font-style="bold">E</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="123.248" y="112.98" font-size="12.0" font-style="bold">x</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="129.956" y="112.98" font-size="12.0" font-style="bold">p</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="137.288" y="112.98" font-size="12.0" font-style="bold">e</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="143.96" y="112.98" font-size="12.0" font-style="bold">r</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="148.664" y="112.98" font-size="12.0" font-style="bold">i</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="152.0" y="112.98" font-size="12.0" font-style="bold">m</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="162.584" y="112.98" font-size="12.0" font-style="bold">e</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="169.292" y="112.98" font-size="12.0" font-style="bold">n</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="176.624" y="112.98" font-size="12.0" font-style="bold">t</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="180.572" y="112.98" font-size="12.0" font-style="bold">a</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="187.28" y="112.98" font-size="12.0" font-style="bold">l</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="190.616" y="112.98" font-size="12.0" font-style="bold"> </text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="193.88" y="112.98" font-size="12.0" font-style="bold">s</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="200.588" y="112.98" font-size="12.0" font-style="bold">e</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="207.296" y="112.98" font-size="12.0" font-style="bold">c</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="214.004" y="112.98" font-size="12.0" font-style="bold">t</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="218.0" y="112.98" font-size="12.0" font-style="bold">i</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="221.336" y="112.98" font-size="12.0" font-style="bold">o</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="228.668" y="112.98" font-size="12.0" font-style="bold">n</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="235.97" y="112.98" font-size="12.0" font-style="bold"> </text>
+ <path stroke="black" stroke-width="0.5" fill="#000000" d="M115.22 115.5 L235.96 115.5 L235.96 114.3 L115.22 114.3 L115.22 115.5 "/>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="93.624" y="143.7" font-size="12.0" font-style="bold">1</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="100.332" y="143.7" font-size="12.0" font-style="bold">.</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="103.668" y="143.7" font-size="12.0" font-style="bold">1</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="110.3" y="143.7" font-size="12.0" font-style="bold"> </text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="122.42" y="143.7" font-size="12.0" font-style="bold">G</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="131.756" y="143.7" font-size="12.0" font-style="bold">e</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="138.488" y="143.7" font-size="12.0" font-style="bold">n</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="145.82" y="143.7" font-size="12.0" font-style="bold">e</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="152.492" y="143.7" font-size="12.0" font-style="bold">r</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="157.196" y="143.7" font-size="12.0" font-style="bold">a</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="163.796" y="143.7" font-size="12.0" font-style="bold">l</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="167.132" y="143.7" font-size="12.0" font-style="bold"> </text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="170.504" y="143.7" font-size="12.0" font-style="bold">e</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="177.104" y="143.7" font-size="12.0" font-style="bold">x</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="183.812" y="143.7" font-size="12.0" font-style="bold">p</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="191.144" y="143.7" font-size="12.0" font-style="bold">e</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="197.816" y="143.7" font-size="12.0" font-style="bold">r</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="202.52" y="143.7" font-size="12.0" font-style="bold">i</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="205.856" y="143.7" font-size="12.0" font-style="bold">m</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="216.44" y="143.7" font-size="12.0" font-style="bold">e</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="223.148" y="143.7" font-size="12.0" font-style="bold">n</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="230.48" y="143.7" font-size="12.0" font-style="bold">t</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="234.428" y="143.7" font-size="12.0" font-style="bold">a</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="241.136" y="143.7" font-size="12.0" font-style="bold">l</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="244.376" y="143.7" font-size="12.0" font-style="bold"> </text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="247.712" y="143.7" font-size="12.0" font-style="bold">t</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="251.708" y="143.7" font-size="12.0" font-style="bold">e</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="258.38" y="143.7" font-size="12.0" font-style="bold">c</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="265.124" y="143.7" font-size="12.0" font-style="bold">h</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="272.456" y="143.7" font-size="12.0" font-style="bold">n</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="279.788" y="143.7" font-size="12.0" font-style="bold">i</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="283.124" y="143.7" font-size="12.0" font-style="bold">q</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="290.456" y="143.7" font-size="12.0" font-style="bold">u</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="297.788" y="143.7" font-size="12.0" font-style="bold">e</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="304.46" y="143.7" font-size="12.0" font-style="bold">s</text>
+ <text font-weight="bold" stroke="#000000" font-family="Arial,old" x="311.21" y="143.7" font-size="12.0" font-style="bold"> </text>
+ <path stroke="black" stroke-width="0.5" fill="#000000" d="M122.42 146.22 L311.2 146.22 L311.2 145.02 L122.42 145.02 L122.42 146.22 "/>
+ <text stroke="#000000" font-family="Verdana" x="93.624" y="175.26" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="93.624" y="201.66" font-size="8.04">1</text>
+ <text stroke="#000000" font-family="Verdana" x="98.784" y="207.18" font-size="12.0">H</text>
+ <text stroke="#000000" font-family="Verdana" x="107.796" y="207.18" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="112.452" y="207.18" font-size="12.0">N</text>
+ <text stroke="#000000" font-family="Verdana" x="121.428" y="207.18" font-size="12.0">M</text>
+ <text stroke="#000000" font-family="Verdana" x="131.544" y="207.18" font-size="12.0">R</text>
+ <text stroke="#000000" font-family="Verdana" x="139.92" y="207.18" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="144.588" y="207.18" font-size="12.0">s</text>
+ <text stroke="#000000" font-family="Verdana" x="150.84" y="207.18" font-size="12.0">p</text>
+ <text stroke="#000000" font-family="Verdana" x="158.268" y="207.18" font-size="12.0">e</text>
+ <text stroke="#000000" font-family="Verdana" x="165.456" y="207.18" font-size="12.0">c</text>
+ <text stroke="#000000" font-family="Verdana" x="171.708" y="207.18" font-size="12.0">t</text>
+ <text stroke="#000000" font-family="Verdana" x="176.376" y="207.18" font-size="12.0">r</text>
+ <text stroke="#000000" font-family="Verdana" x="181.5" y="207.18" font-size="12.0">a</text>
+ <text stroke="#000000" font-family="Verdana" x="188.712" y="207.18" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="193.404" y="207.18" font-size="12.0">w</text>
+ <text stroke="#000000" font-family="Verdana" x="203.22" y="207.18" font-size="12.0">e</text>
+ <text stroke="#000000" font-family="Verdana" x="210.432" y="207.18" font-size="12.0">r</text>
+ <text stroke="#000000" font-family="Verdana" x="215.556" y="207.18" font-size="12.0">e</text>
+ <text stroke="#000000" font-family="Verdana" x="222.78" y="207.18" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="227.448" y="207.18" font-size="12.0">r</text>
+ <text stroke="#000000" font-family="Verdana" x="232.572" y="207.18" font-size="12.0">e</text>
+ <text stroke="#000000" font-family="Verdana" x="239.796" y="207.18" font-size="12.0">c</text>
+ <text stroke="#000000" font-family="Verdana" x="246.048" y="207.18" font-size="12.0">o</text>
+ <text stroke="#000000" font-family="Verdana" x="253.332" y="207.18" font-size="12.0">r</text>
+ <text stroke="#000000" font-family="Verdana" x="258.504" y="207.18" font-size="12.0">d</text>
+ <text stroke="#000000" font-family="Verdana" x="265.944" y="207.18" font-size="12.0">e</text>
+ <text stroke="#000000" font-family="Verdana" x="273.132" y="207.18" font-size="12.0">d</text>
+ <text stroke="#000000" font-family="Verdana" x="280.572" y="207.18" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="285.24" y="207.18" font-size="12.0">i</text>
+ <text stroke="#000000" font-family="Verdana" x="288.48" y="207.18" font-size="12.0">n</text>
+ <text stroke="#000000" font-family="Verdana" x="296.04" y="207.18" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="300.708" y="207.18" font-size="12.0">C</text>
+ <text stroke="#000000" font-family="Verdana" x="309.084" y="207.18" font-size="12.0">D</text>
+ <text stroke="#000000" font-family="Verdana" x="318.336" y="207.18" font-size="12.0">C</text>
+ <text stroke="#000000" font-family="Verdana" x="326.736" y="207.18" font-size="12.0">l</text>
+ <text stroke="#000000" font-family="Verdana" x="330.17" y="208.74" font-size="8.04">3</text>
+ <text stroke="#000000" font-family="Verdana" x="335.35" y="207.18" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="340.03" y="207.18" font-size="12.0">o</text>
+ <text stroke="#000000" font-family="Verdana" x="347.338" y="207.18" font-size="12.0">r</text>
+ <text stroke="#000000" font-family="Verdana" x="352.462" y="207.18" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="357.166" y="207.18" font-size="12.0">C</text>
+ <text stroke="#000000" font-family="Verdana" x="365.59" y="208.74" font-size="8.04">6</text>
+ <text stroke="#000000" font-family="Verdana" x="370.75" y="207.18" font-size="12.0">D</text>
+ <text stroke="#000000" font-family="Verdana" x="379.99" y="208.74" font-size="8.04">6</text>
+ <text stroke="#000000" font-family="Verdana" x="385.15" y="207.18" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="389.83" y="207.18" font-size="12.0">a</text>
+ <text stroke="#000000" font-family="Verdana" x="397.042" y="207.18" font-size="12.0">t</text>
+ <text stroke="#000000" font-family="Verdana" x="401.71" y="207.18" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="406.378" y="207.18" font-size="12.0">2</text>
+ <text stroke="#000000" font-family="Verdana" x="414.046" y="207.18" font-size="12.0">0</text>
+ <text stroke="#000000" font-family="Verdana" x="421.714" y="207.18" font-size="12.0">0</text>
+ <text stroke="#000000" font-family="Verdana" x="429.382" y="207.18" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="434.05" y="207.18" font-size="12.0">M</text>
+ <text stroke="#000000" font-family="Verdana" x="444.13" y="207.18" font-size="12.0">H</text>
+ <text stroke="#000000" font-family="Verdana" x="453.142" y="207.18" font-size="12.0">z</text>
+ <text stroke="#000000" font-family="Verdana" x="459.478" y="207.18" font-size="12.0">,</text>
+ <text stroke="#000000" font-family="Verdana" x="463.798" y="207.18" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="468.466" y="207.18" font-size="12.0">4</text>
+ <text stroke="#000000" font-family="Verdana" x="476.134" y="207.18" font-size="12.0">0</text>
+ <text stroke="#000000" font-family="Verdana" x="483.802" y="207.18" font-size="12.0">0</text>
+ <text stroke="#000000" font-family="Verdana" x="491.47" y="207.18" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="496.138" y="207.18" font-size="12.0">M</text>
+ <text stroke="#000000" font-family="Verdana" x="506.218" y="207.18" font-size="12.0">H</text>
+ <text stroke="#000000" font-family="Verdana" x="515.23" y="207.18" font-size="12.0">z</text>
+ <text stroke="#000000" font-family="Verdana" x="521.566" y="207.18" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="526.234" y="207.18" font-size="12.0">o</text>
+ <text stroke="#000000" font-family="Verdana" x="533.542" y="207.18" font-size="12.0">r</text>
+ <text stroke="#000000" font-family="Verdana" x="538.582" y="207.18" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="93.624" y="229.02" font-size="12.0">6</text>
+ <text stroke="#000000" font-family="Verdana" x="101.292" y="229.02" font-size="12.0">0</text>
+ <text stroke="#000000" font-family="Verdana" x="108.96" y="229.02" font-size="12.0">0</text>
+ <text stroke="#000000" font-family="Verdana" x="116.52" y="229.02" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="122.508" y="229.02" font-size="12.0">M</text>
+ <text stroke="#000000" font-family="Verdana" x="132.588" y="229.02" font-size="12.0">H</text>
+ <text stroke="#000000" font-family="Verdana" x="141.6" y="229.02" font-size="12.0">z</text>
+ <text stroke="#000000" font-family="Verdana" x="147.936" y="229.02" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="153.924" y="229.02" font-size="12.0">o</text>
+ <text stroke="#000000" font-family="Verdana" x="161.232" y="229.02" font-size="12.0">n</text>
+ <text stroke="#000000" font-family="Verdana" x="168.792" y="229.02" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="174.66" y="229.02" font-size="12.0">B</text>
+ <text stroke="#000000" font-family="Verdana" x="182.928" y="229.02" font-size="12.0">r</text>
+ <text stroke="#000000" font-family="Verdana" x="188.052" y="229.02" font-size="12.0">u</text>
+ <text stroke="#000000" font-family="Verdana" x="195.648" y="229.02" font-size="12.0">k</text>
+ <text stroke="#000000" font-family="Verdana" x="202.752" y="229.02" font-size="12.0">e</text>
+ <text stroke="#000000" font-family="Verdana" x="209.904" y="229.02" font-size="12.0">r</text>
+ <text stroke="#000000" font-family="Verdana" x="214.968" y="229.02" font-size="12.0"> </text>
+ <text stroke="#000000" font-family="Verdana" x="220.956" y="229.02" font-size="12.0">D</text>
+ <text stroke="#000000" font-family="Verdana" x="230.208" y="229.02" font-size="12.0">R</text>
+ <text stroke="#000000" font-family="Verdana" x="238.584" y="229.02" font-size="12.0">X</text>
+ <text stroke="#000000" font-family="Verdana" x="247.01" y="229.02" font-size="12.0">-</text>
+ <text stroke="#000000" font-family="Verdana" x="252.41" y="229.02" font-size="12.0">2</text>
+ <text stroke="#000000" font-family="Verdana" x="259.97" y="229.02" font-size="12.0">0</text>
+ <text stroke="#000000" font-family="Verdana" x="267.638" y="229.02" font-size="12.0">0</text>