Index: trunk/src/org/expeditee/encryption/Actions.java
===================================================================
--- trunk/src/org/expeditee/encryption/Actions.java	(revision 1407)
+++ trunk/src/org/expeditee/encryption/Actions.java	(revision 1408)
@@ -23,4 +23,5 @@
 import org.expeditee.gui.Frame;
 import org.expeditee.gui.FrameIO;
+import org.expeditee.items.Item;
 import org.expeditee.items.Text;
 import org.expeditee.settings.UserSettings;
@@ -29,4 +30,8 @@
 
 public class Actions implements CryptographyConstants {
+	
+	public static void TestSurrogate(Item classic) {
+		System.out.println("Test surrogates: ");
+	}
 	
 	public static Text GenerateSecret(String label) {
Index: trunk/src/org/expeditee/encryption/io/EncryptedExpReader.java
===================================================================
--- trunk/src/org/expeditee/encryption/io/EncryptedExpReader.java	(revision 1407)
+++ trunk/src/org/expeditee/encryption/io/EncryptedExpReader.java	(revision 1408)
@@ -7,10 +7,12 @@
 import java.io.InputStreamReader;
 import java.io.Reader;
-import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Method;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Base64;
-import java.util.Collection;
+import java.util.List;
+import java.util.function.Predicate;
 
 import javax.crypto.BadPaddingException;
@@ -24,5 +26,9 @@
 import org.expeditee.encryption.Label;
 import org.expeditee.encryption.Label.LabelResult;
+import org.expeditee.encryption.items.surrogates.EncryptionDetail;
+import org.expeditee.encryption.items.surrogates.Surrogate;
 import org.expeditee.gui.Frame;
+import org.expeditee.gui.FrameIO;
+import org.expeditee.io.Conversion;
 import org.expeditee.io.ExpReader;
 import org.expeditee.items.Item;
@@ -31,12 +37,14 @@
 
 public class EncryptedExpReader extends ExpReader implements CryptographyConstants {
-	static final String ENCRYPTED_EXP_FLAG = "EncryptedExp";
+	private static final String ENCRYPTED_EXP_FLAG = "EncryptedExp";
+	private static final String labelProfile = "Profile";
+	private static final String labelNone = "None";
 	private SecretKey personalKey;
 	private boolean accessDenied = false;
 
-	public EncryptedExpReader(final String frameName) throws UnsupportedEncodingException {
+	public EncryptedExpReader(String frameName) {
 		super(frameName);
 	}
-	
+
 	public static boolean isEncryptedExpediteeFile(final String path) throws IOException {
 		final BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(path), "UTF-8"));
@@ -74,30 +82,177 @@
 	
 	@Override
-	public Frame readFrame(final BufferedReader reader) throws IOException {
+	public Frame readFrame(BufferedReader reader) throws IOException {
 		if (accessDenied) { return null; }
-		else {
-			Frame unencryptedFrame = super.readFrame(reader);
-			individualItemDecryption(unencryptedFrame);
-			return unencryptedFrame;
-		}
-	}
-	
-	private void individualItemDecryption(Frame frame) {
-		// Find items with their own encryption label.
-		Collection<Item> itemsWithEncryptionLabel = frame.getAllItems();
-		itemsWithEncryptionLabel.removeIf(i -> i.getEncryptionLabel() == null || i.getEncryptionLabel().isEmpty());
-		
-		for (Item i: itemsWithEncryptionLabel) {
-			// Decrypt the Text Items
-			if (i instanceof Text) {
-				LabelResult res = Label.resolveKey(i.getEncryptionLabel());
-				if (res == LabelResult.SuccessResolveLabelToKey) {
-					byte[] keyBytes = res.key;
-					if (keyBytes == null) { continue; }
-					SecretKeySpec key = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
-					byte[] decryptedBytes = DecryptSymmetric(Base64.getDecoder().decode(i.getText()), key);
-					i.setText(new String(decryptedBytes));
-				}
-			}
+		
+		_reader = reader;
+		String next = "";
+		Frame newFrame = new Frame();
+		List<DelayedAction> delayedActions = new ArrayList<DelayedAction>();
+		newFrame.setName(_frameName);
+		
+		try {
+			// First read all the header lines
+			next = readTheHeader(newFrame);
+			
+			// Now read all the items
+			next = readTheItems(newFrame, delayedActions);
+			
+			// Read the lines
+			next = readTheLines(newFrame);
+
+			// Read the constraints
+			next = readTheConstraints();
+			
+			for(DelayedAction action: delayedActions) {
+				action.exec();
+			}
+
+			// Read the stats
+			next = readTheStats(newFrame);
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.out.println("Error reading frame file line: " + next + " " + e.getMessage());
+		}
+		
+		_reader.close();
+		FrameIO.setSavedProperties(newFrame);
+		newFrame.setChanged(false);
+
+		return newFrame;
+	}
+	
+	@Override
+	protected String readTheItems(Frame newFrame, List<DelayedAction> delayedActions) throws IOException {
+		String next = null;
+		Item currentItem = null;
+		
+		Predicate<String> endOfSection = s -> s.equals("Z") || s.equals("Z...");
+		while (_reader.ready() && !endOfSection.test(next = _reader.readLine())) {
+			if (!isValidLine(next)) {
+				continue;
+			}
+			String tag = getTagEnc(next);
+			if (tag.equals("S")) {
+				currentItem = newItem(next);
+				_linePoints.put(currentItem.getID(), currentItem);
+				newFrame.addItem(currentItem);
+				currentItem.setEncryptionDetailForTag(tag + "", EncryptionDetail.UnencryptedOnSave);
+			} else if (currentItem != null && actionShouldBeDelayed(tag.charAt(0))) { 
+				delayedActions.add(new DelayedAction(currentItem, next));
+			} else if (currentItem != null) {
+				processBodyLine(currentItem, next);
+			} else {
+				System.err.println("Error while reading in frame (ExpReader): Found body line but no current item to apply it to.");
+			}
+		}
+		
+		if (next.equals("Z...")) {
+			next = readTheSurrogateItems(newFrame, delayedActions);
+		}
+		
+		return next;
+	}
+	
+	@Override
+	protected void processBodyLine(Item item, String line) {
+		// separate the tag from the value
+		String tag = getTagEnc(line);
+		String value = getValue(line);
+		
+		// Attempt to decrypt the line if necessary.
+		if (isEncryptedLine(line)) {
+			LabelResult res = Label.resolveKey(item.getEncryptionLabel());
+			if (res == LabelResult.SuccessResolveLabelToKey) {
+				item.setEncryptionDetailForTag(tag, EncryptionDetail.ReencryptOnSave);
+				SecretKey key = new SecretKeySpec(res.key, SymmetricAlgorithm);
+				byte[] decryptedBytes = DecryptSymmetric(Base64.getDecoder().decode(value), key);
+				value = new String(decryptedBytes);				
+			} else {
+				EncryptionDetail encryptionDetail = EncryptionDetail.UseUndecipheredValueOnSave.setUndecipheredValue(getValue(line));
+				item.setEncryptionDetailForTag(tag, encryptionDetail);
+				return;
+			}
+		} else {
+			item.setEncryptionDetailForTag(tag, EncryptionDetail.UnencryptedOnSave);
+		}
+		
+		// Process the line
+		Method toRun = tag.startsWith("_") ? _ItemTagsExt.get(tag) : _ItemTags.get(tag.charAt(0));
+		if (toRun == null) {
+			System.out.println("Error accessing tag method: " + tag);
+		}
+		Object[] vals = Conversion.Convert(toRun, value);
+		try {
+			if (vals != null) {
+				toRun.invoke(item, vals);
+			}
+		} catch (Exception e) {
+			System.out.println("Error running tag method: " + tag);
+			e.printStackTrace();
+		}
+	}
+		
+	private String readTheSurrogateItems(Frame newFrame, List<DelayedAction> delayedActions) throws IOException {
+		String next = null;
+		Item currentItem = null;
+		
+		Predicate<String> endOfSection = s -> s.equals("Z") || s.equals("Z...");
+		while (_reader.ready() && !endOfSection.test(next = _reader.readLine())) {
+			if (!isValidLine(next)) {
+				continue;
+			}
+			
+			String tag = getTagEnc(next);
+			if (tag.equals("S") && !next.startsWith("SurrogateFor")) {
+				currentItem = newItem(next);
+				currentItem.setEncryptionDetailForTag(tag + "", EncryptionDetail.UnencryptedOnSave);
+			} else if (next.startsWith("SurrogateFor")) {
+				String id = next.split(" ")[1];
+				Item classic = newFrame.getItemWithID(Integer.parseInt(id));
+				if (id == null) {
+					System.err.println("WARNING: Attempted to create surrogate for classic ID " + 
+							id + " but was no item on frame " + newFrame.getName() + " exists.");
+					continue;
+				}
+				currentItem.setAsSurrogateFor(classic);
+				classic.addToSurrogates(new Surrogate(currentItem));
+			} else if (currentItem != null && actionShouldBeDelayed(getTag(next))) { 
+				delayedActions.add(new DelayedAction(currentItem, next));
+			} else if (currentItem != null) {
+				processBodyLine(currentItem, next);
+			} else {
+				System.err.println("Error while reading in frame (ExpReader): Found body line but no current item to apply it to.");
+			}
+		}
+
+		return next;
+	}
+	
+	protected static String getTagEnc(String line) {
+		char charAtZero = line.charAt(0);
+		if (charAtZero == '_') {
+			return line.split(" ")[0];
+		} else {
+			return charAtZero + "";
+		}
+	}
+	
+	protected static String getValue(String line) {
+		String[] split = line.split(" ");
+		if (split.length >= 2) {
+			return line.substring(split[0].length()).trim();
+		} else {
+			return null;
+		}
+	}
+	
+	protected static boolean isEncryptedLine(String line) {
+		if (line.startsWith("S") || line.startsWith("_el")) {
+			return false;
+		}		
+		if (line.length() > 2) {
+			return line.charAt(1) == 'E';
+		} else {
+			return false;
 		}
 	}
@@ -125,4 +280,6 @@
 	
 	private class EncryptedLineReader extends BufferedReader {
+		private boolean noneMode = false;
+		
 		public EncryptedLineReader(Reader in) {
 			super(in);
@@ -140,11 +297,19 @@
 				return "";
 			}
+			
+			if (noneMode) {
+				return line;
+			}
+			
 			if (line.startsWith(ENCRYPTED_EXP_FLAG)) {
 				String label = line.replace(ENCRYPTED_EXP_FLAG, "");
 				// if using Profile label, use personal key
-				if (label.startsWith("Profile")) {
+				if (label.equals(labelProfile)) {
 					Text text = KeyList.PersonalKey.get();
 					byte[] keyBytes = Base64.getDecoder().decode(text.getData().get(0));
 					personalKey = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
+					return readLine();
+				} else if (label.equals(labelNone)) {
+					noneMode = true;
 					return readLine();
 				} else {
Index: trunk/src/org/expeditee/encryption/io/EncryptedExpWriter.java
===================================================================
--- trunk/src/org/expeditee/encryption/io/EncryptedExpWriter.java	(revision 1407)
+++ trunk/src/org/expeditee/encryption/io/EncryptedExpWriter.java	(revision 1408)
@@ -2,10 +2,14 @@
 
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Base64;
-import java.util.Collection;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.function.Consumer;
 
 import javax.crypto.BadPaddingException;
@@ -19,18 +23,34 @@
 import org.expeditee.encryption.Label;
 import org.expeditee.encryption.Label.LabelResult;
+import org.expeditee.encryption.items.surrogates.EncryptionDetail;
+import org.expeditee.encryption.items.surrogates.Surrogate;
 import org.expeditee.gui.Frame;
 import org.expeditee.gui.MessageBay;
+import org.expeditee.io.Conversion;
 import org.expeditee.io.ExpWriter;
 import org.expeditee.items.Item;
+import org.expeditee.items.Line;
 import org.expeditee.items.Text;
 import org.expeditee.settings.identity.secrets.KeyList;
+import org.expeditee.stats.SessionStats;
 
 public class EncryptedExpWriter extends ExpWriter implements CryptographyConstants {
 	private SecretKey key;
-	private String label;
+	
+	private final String label;
+	
+	private static final String ENCRYPTED_EXP_FLAG = "EncryptedExp";
 	private static final String nl = "\n";
-	
-	public EncryptedExpWriter(String encryptionLabel) throws IOException {
-		if (encryptionLabel.compareTo("Profile") == 0) {
+	private static final String labelProfile = "Profile";
+	private static final String labelNone = "None";
+	protected static final String SURROGATE_TERMINATOR = TERMINATOR + "...";
+
+	public EncryptedExpWriter(String encryptionLabel) {
+		label = encryptionLabel;
+		if (label.equals(labelNone)) {
+			return;
+		}
+		
+		if (label.equals(labelProfile)) {
 			// obtain personal key
 			Text text = KeyList.PersonalKey.get();
@@ -40,13 +60,12 @@
 				key = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
 			}
-			label = "Profile";
 		} else {
-			LabelResult res = Label.resolveKey(encryptionLabel);
+			LabelResult res = Label.resolveKey(label);
 			if (res == LabelResult.SuccessResolveLabelToKey) {
 				byte[] keyBytes = res.key;
 				key = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
-				label = encryptionLabel;
 			} else if (res == LabelResult.ErrorUnableToFindLabel) {
 				MessageBay.errorMessage(res.toString() + encryptionLabel);
+				key = null;
 			} else {
 				MessageBay.errorMessage(res.toString());
@@ -54,9 +73,29 @@
 		}
 	}
-
+	
+	@Override
+	public void outputFrame(Frame frame) throws IOException {
+		if (_writer == null) { return; }
+		
+		preOutputFrame();
+		writeHeader(frame);
+		
+		// write item
+		writeItemData(frame);
+		writeTerminator();
+		
+		// write lines and constraints
+		writeLineData();
+		writeTerminator();
+		writeConstraintData();
+		writeTerminator();
+		
+		writeLine(SessionStats.getFrameEventList(frame));
+	}
+	
 	@Override
 	protected void preOutputFrame() {
 		try {
-			String line = EncryptedExpReader.ENCRYPTED_EXP_FLAG + label + nl;
+			String line = ENCRYPTED_EXP_FLAG + label + nl;
 			_writer.write(line);
 			_stringWriter.append(line);
@@ -67,18 +106,17 @@
 	
 	@Override
-	public void outputFrame(Frame frame) throws IOException {
-		individualItemEncryption(frame);
-		super.outputFrame(frame);
-	}
-	
-	@Override
 	protected void writeLine(String line) throws IOException {
 		// do not write empty lines
 		if (line == null) { return; }
 		
-		// prepare line to write out
-		byte[] encrypted = EncryptSymmetric(line.getBytes(), key);
-		String toWrite = Base64.getEncoder().encodeToString(encrypted) + nl;
-		
+		String toWrite;
+		if (key == null && label.equals(labelNone)) {
+			toWrite = line + nl;
+		} else {
+			// prepare line to write out
+			byte[] encrypted = EncryptSymmetric(line.getBytes(), key);
+			toWrite = Base64.getEncoder().encodeToString(encrypted) + nl;
+		}
+				
 		// output
 		_writer.write(toWrite);
@@ -86,59 +124,129 @@
 	}
 	
-	private void individualItemEncryption(Frame frame) {
-		// Find items with their own encryption label.
-		Collection<Item> itemsWithEncryptionLabel = frame.getAllItems();
-		itemsWithEncryptionLabel.removeIf(i -> i.getEncryptionLabel() == null || i.getEncryptionLabel().isEmpty());
-		
-		for (Item i: itemsWithEncryptionLabel) {
-			// Encrypt the Text Items
-			if (i instanceof Text) {
-				LabelResult res = Label.resolveKey(i.getEncryptionLabel());
-				if (res == LabelResult.SuccessResolveLabelToKey) {
-					byte[] keyBytes = res.key;
-					if (keyBytes == null) { continue; } 
-					SecretKeySpec key = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
-					byte[] encryptedBytes = EncryptSymmetric(i.getText().getBytes(), key);
-					i.setText(Base64.getEncoder().encodeToString(encryptedBytes));
+	@Override
+	protected void writeLineData() throws IOException {
+		super.writeLineData();
+		
+		writeSurrogateLineData();
+	}
+	
+	@Override
+	protected void writeClass(Item toWrite) throws IOException {
+		LinkedHashMap<Character,Method> itemTags = new LinkedHashMap<Character, Method>(getItemTags());
+		LinkedHashMap<String,Method> itemTagsExt = new LinkedHashMap<String, Method>(getItemTagsExt());
+		
+		writeTag(toWrite, new Object[] {}, itemTags, 'S');
+		writeTag(toWrite, new Object[] {}, itemTagsExt, "_el");
+		
+		itemTags.remove('S');
+		itemTagsExt.remove("_el");
+		
+		writeTags(toWrite, new Object[] {}, itemTags);
+		writeTags(toWrite, new Object[] {}, itemTagsExt);
+	}
+	
+	@Override
+	protected <T> void writeTag(Item toWrite, Object[] param, LinkedHashMap<T, Method> tags, T tag) {
+		EncryptionDetail encryptionDetail = toWrite.getEncryptionDetailForTag(tag + "");
+		switch (encryptionDetail) {
+		case UnencryptedOnSave:
+			super.writeTag(toWrite, param, tags, tag);
+			break;
+		case ReencryptOnSave:
+			Method toRun = tags.get(tag);
+			Class<?> declarer = toRun.getDeclaringClass();
+			LabelResult res = Label.resolveKey(toWrite.getEncryptionLabel());
+			if (declarer.isAssignableFrom(toWrite.getClass()) && res == LabelResult.SuccessResolveLabelToKey) {
+				SecretKey key = new SecretKeySpec(res.key, SymmetricAlgorithm);
+				try {
+					Object o = toRun.invoke(toWrite, new Object[] {});
+					o = Conversion.ConvertToExpeditee(toRun, o);
+					if (o != null) {
+						if (o instanceof List) {
+							for (Object line: (List<?>)o) {
+								byte[] encryptedBytes = EncryptSymmetric(line.toString().getBytes(), key);
+								writeLine(tag + "E", Base64.getEncoder().encodeToString(encryptedBytes));
+							}
+						} else {
+							byte[] encryptedBytes = EncryptSymmetric(o.toString().getBytes(), key);
+							writeLine(tag + "E", Base64.getEncoder().encodeToString(encryptedBytes));
+						}
+					}
+				} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+					e.printStackTrace();
+				} catch (IOException e) {
+					e.printStackTrace();
 				}
 			}
-		}
-	}
-	
-//	protected static byte[] resolveKeyFromLabel(String label, String framename) {
-//		String credentialsFrameName = UserSettings.ProfileName.get() + AuthenticatorBrowser.CREDENTIALS_FRAME;
-//		Frame credentialsFrame = FrameIO.LoadFrame(credentialsFrameName);
-//		Collection<Text> textItems = credentialsFrame.getTextItems();
-//		textItems.removeIf(t -> !t.getText().equals("Secrets"));
-//		textItems.removeIf(t -> !t.hasLink());
-//		if (textItems.isEmpty()) {
-//			MessageBay.errorMessage("Unable to find label " + label + " to encrypt frame " + framename + ".");
-//			return null;
-//		} else {
-//			Text linkToSecretsFrame = textItems.iterator().next();
-//			Frame secretsFrame = FrameIO.LoadFrame(linkToSecretsFrame.getParent().getFramesetName() + linkToSecretsFrame.getLink());
-//			Collection<Text> labels = secretsFrame.getTextItems();
-//			labels.removeIf(lbl -> !lbl.getText().equals(label));
-//			labels.removeIf(lbl -> lbl.getData() == null || lbl.getData().size() == 0);
-//			if (labels.isEmpty()) {
-//				MessageBay.errorMessage("Unable to find label " + label + " to encrypt frame " + framename + ".");
-//				return null;
-//			}
-//			
-//			Text labelItem = labels.iterator().next();
-//			String data = labelItem.getData().get(0);
-//			if (data.contains("{")) {
-//				MessageBay.errorMessage("You only have a fraction of the required key to access " + framename + ".");
-//				return null;
-//			} else {
-//				try {
-//					return Base64.getDecoder().decode(data);
-//				} catch (IllegalArgumentException e) {
-//					MessageBay.errorMessage("Unable to create key out of data stored in label " + label + ".");
-//					return null;
-//				}
-//			}
-//		}
-//	}
+			break;
+		case UseUndecipheredValueOnSave:
+			try {
+				writeLine(tag + "E", encryptionDetail.getUndecipheredValue());
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+			break;
+		}
+	}
+	
+	private void writeItemData(Frame frame) throws IOException {
+		// write each item in the frame
+		for (Item i : frame.getItemsToSave()) {
+			assert (!(i instanceof Line));
+			writeItem(i);
+		}
+		
+		for (final Item i: frame.getBodyItemsWithInsufficientPermissions()) {
+			assert (!(i instanceof Line));
+			writeItem(i);
+		}
+		
+		writeSurrogateItemsData(frame);
+	}
+	
+	private void writeSurrogateItemsData(Frame frame) throws IOException {
+		List<Surrogate> surrogates = new ArrayList<Surrogate>();
+		
+		Consumer<? super Item> store = item -> surrogates.addAll(item.getSurrogates());
+		frame.getItemsToSave().forEach(store);
+		frame.getBodyItemsWithInsufficientPermissions().forEach(store);
+		
+		if (!surrogates.isEmpty()) {
+			// If there is some surrogates, write the surrogate 
+			// terminator, then write out the surrogates.
+			writeSurrogateTerminator();
+			
+			for (Surrogate surrogate: surrogates) {
+				String output = surrogate.toString();
+				writeLine(output);
+			}
+		}
+	}
+
+	private void writeSurrogateLineData() throws IOException {
+		List<Surrogate> surrogateLines = new ArrayList<Surrogate>();
+		
+		for(Item lineEnd: _lineEnds) {
+			List<Line> lines = lineEnd.getLines();
+			for (Line line: lines) {
+				surrogateLines.addAll(line.getSurrogates());
+			}
+		}
+		
+		if (!surrogateLines.isEmpty()) {
+			// If there is some surrogates, write the surrogate 
+			// terminator, then write out the surrogates.
+			writeSurrogateTerminator();
+			
+			for (Surrogate surrogate: surrogateLines) {
+				String output = surrogate.toString();
+				writeLine(output);
+			}
+		}
+	}
+	
+	private void writeSurrogateTerminator() throws IOException {
+		writeLine(SURROGATE_TERMINATOR + nl);
+	}
 	
 	private static byte[] EncryptSymmetric(byte[] toEncrypt, SecretKey key) {
@@ -156,4 +264,4 @@
 			return null;
 		}
-	}
+	}	
 }
Index: trunk/src/org/expeditee/encryption/items/surrogates/EncryptionDetail.java
===================================================================
--- trunk/src/org/expeditee/encryption/items/surrogates/EncryptionDetail.java	(revision 1408)
+++ trunk/src/org/expeditee/encryption/items/surrogates/EncryptionDetail.java	(revision 1408)
@@ -0,0 +1,16 @@
+package org.expeditee.encryption.items.surrogates;
+
+public enum EncryptionDetail {
+	UnencryptedOnSave, ReencryptOnSave, UseUndecipheredValueOnSave;
+	
+	private String undecipheredValue = null;
+	
+	public EncryptionDetail setUndecipheredValue(String undecipheredValue) {
+		this.undecipheredValue = undecipheredValue;
+		return this;
+	}
+	
+	public String getUndecipheredValue() {
+		return this.undecipheredValue;
+	}
+}
Index: trunk/src/org/expeditee/encryption/items/surrogates/Surrogate.java
===================================================================
--- trunk/src/org/expeditee/encryption/items/surrogates/Surrogate.java	(revision 1408)
+++ trunk/src/org/expeditee/encryption/items/surrogates/Surrogate.java	(revision 1408)
@@ -0,0 +1,184 @@
+package org.expeditee.encryption.items.surrogates;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.expeditee.io.Conversion;
+import org.expeditee.io.DefaultFrameWriter;
+import org.expeditee.items.Item;
+import org.expeditee.items.Line;
+import org.expeditee.items.Text;
+
+public class Surrogate {
+	
+	private static Map<String, Boolean> propertyInheritanceDefault = new HashMap<String, Boolean>();
+	
+	{
+		for (Character tag: DefaultFrameWriter.getItemTags().keySet()) {
+			if (tag == 'T') {
+				propertyInheritanceDefault.put(tag + "", false);
+			} else {
+				propertyInheritanceDefault.put(tag + "", true);
+			}
+		}
+		
+		for (String tag: DefaultFrameWriter.getItemTagsExt().keySet()) {
+			propertyInheritanceDefault.put(tag, true);
+		}
+	}
+	
+	private Item surrogateItem = null;
+	private Map<String, Boolean> propertyInheritance;
+		
+	public Surrogate(Item surrogateItem) {
+		this.surrogateItem = surrogateItem;
+		this.propertyInheritance = new HashMap<String, Boolean>(propertyInheritanceDefault);
+	}
+	
+	public String toString() {
+		String nl = System.getProperty("line.separator");
+		List<String> lines = toStringList();
+		return lines.stream().map(l -> l + nl).reduce("", (acc, l) -> acc + l);
+	}
+	
+	public List<String> toStringList() {
+		List<String> lines = new ArrayList<String>();
+		Map<Character,Method> itemTags = new LinkedHashMap<Character, Method>(DefaultFrameWriter.getItemTags());
+		Map<String,Method> itemTagsExt = new LinkedHashMap<String, Method>(DefaultFrameWriter.getItemTagsExt());
+		
+		try {
+			Method methodS = itemTags.get('S');
+			Object o = methodS.invoke(surrogateItem);
+			o = Conversion.ConvertToExpeditee(methodS, o);
+			lines.add("S " + o);
+			lines.add("SurrogateFor " + surrogateItem.getClassic().getID());
+		} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+			e.printStackTrace();
+		}
+		itemTags.remove('S');
+		itemTagsExt.remove("_el");
+		
+		
+		for(Character itemTag: itemTags.keySet()) {
+			boolean propertyIsInherited = isPropertyIsInherited(itemTag + "");
+			if (propertyIsInherited) {
+				continue;
+			}
+			
+			Object value = null;
+			if (itemTag == 'T') {
+				value = "REDACTED";
+			} else {
+				try {
+					Method method = itemTags.get(itemTag);
+					Object o = method.invoke(surrogateItem);
+					value = Conversion.ConvertToExpeditee(method, o); 
+				} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+					e.printStackTrace();
+				}
+			}
+			lines.add(itemTag + " " + value);
+		}
+		for (String itemTag: itemTagsExt.keySet()) {
+			boolean propertyIsInherited = isPropertyIsInherited(itemTag);
+			if (propertyIsInherited) {
+				continue;
+			}
+			try {
+				Method method = itemTagsExt.get(itemTag);
+				Object o = method.invoke(surrogateItem);
+				o = Conversion.ConvertToExpeditee(method, o);
+				lines.add(itemTag + " " + o);
+			} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+				e.printStackTrace();
+			}
+		}
+		
+		return lines;
+	}
+	
+	public Item getSurrogateItem() {
+		return surrogateItem;
+	}
+	
+	public boolean isPropertyIsInherited(String tag) {
+		if (this.propertyInheritance.containsKey(tag)) {
+			return this.propertyInheritance.get(tag);
+		} else {
+			return false;
+		}
+	}
+	
+	public void setPropertyIsInherited(String tag, boolean value) {
+		this.propertyInheritance.put(tag, value);
+	}
+	
+	public static Surrogate forItem(Item item) {
+		Item surrogateItem = item.copy();
+		surrogateItem.setID(item.getParent().getNextItemID());
+		surrogateItem.setAsSurrogateFor(item);
+		
+		if (item.isLineEnd()) {
+			handleLineEnd(surrogateItem);
+		}
+		
+		if (surrogateItem instanceof Text && !surrogateItem.isAnnotation()) {
+			surrogateItem.setText("REDACTED");
+		}
+		
+		Surrogate surrogate = new Surrogate(surrogateItem);
+		item.addToSurrogates(surrogate);
+		return surrogate;
+	}
+	
+	private static Surrogate forItem(Line line) {
+		Item startItem = line.getStartItem();
+		Item endItem = line.getEndItem();
+		
+		if (!startItem.isSurrogate()) {
+			Set<Surrogate> surrogates = startItem.getSurrogates();
+			surrogates.removeIf(surrogate -> !surrogate.surrogateItem.isLineEnd());
+			if (surrogates.isEmpty()) {
+				Surrogate surrogate = Surrogate.forItem(startItem);
+				startItem.addToSurrogates(surrogate);
+				startItem = surrogate.surrogateItem;
+			} else {
+				startItem = surrogates.stream().findFirst().get().surrogateItem;
+			}
+		}
+		
+		if (!endItem.isSurrogate()) {
+			Set<Surrogate> surrogates = endItem.getSurrogates();
+			surrogates.removeIf(surrogate -> !surrogate.surrogateItem.isLineEnd());
+			if (endItem.getSurrogates().isEmpty()) {
+				Surrogate surrogate = Surrogate.forItem(endItem);
+				endItem.addToSurrogates(surrogate);
+				endItem = surrogate.surrogateItem;
+			} else {
+				endItem = endItem.getSurrogates().stream().findFirst().get().surrogateItem;
+			}
+		}
+		
+		Line ret = new Line(startItem, endItem, line.getParent().getNextItemID());
+		ret.setAsSurrogateFor(line);
+		Surrogate surrogate = new Surrogate(ret);
+		line.addToSurrogates(surrogate);
+		return surrogate;
+	}
+		
+	private static void handleLineEnd(Item lineEndSurrogate) {
+		Item lineEndClassic = lineEndSurrogate.getClassic();
+		List<Item> lines = new ArrayList<Item>(lineEndClassic.getLines());
+		lines.removeIf(line -> !line.getSurrogates().isEmpty());
+		
+		for(Item line: lines) {
+			Surrogate.forItem((Line) line);
+		}		
+	}
+}
Index: trunk/src/org/expeditee/gui/Frame.java
===================================================================
--- trunk/src/org/expeditee/gui/Frame.java	(revision 1407)
+++ trunk/src/org/expeditee/gui/Frame.java	(revision 1408)
@@ -77,5 +77,5 @@
  * 
  */
-public class Frame {
+public class Frame /*implements Cloneable*/ {
 	
 	/** The frame number to indicate this is a virtual frame. */
@@ -187,4 +187,63 @@
 	public Frame() {
 	}
+	
+//	public Frame clone() {
+//		Frame clone = new Frame();
+//		for (Item i: this._body) { 
+//			Item copy = i.copy();
+//			copy.setID(i.getID());	
+//			clone._body.add(copy);
+//		}
+//		for(Item i: this._bodyHiddenDueToPermissions) { 
+//			Item copy = i.copy();
+//			copy.setID(i.getID());
+//			clone._bodyHiddenDueToPermissions.add(i);
+//		}
+//		if (this._frameName != null) {
+//			clone._frameName = this._frameName.copy();
+//		}
+//		for(Overlay key: this._overlays.keySet()) {
+//			clone._overlays.put(key, this._overlays.get(key));
+//		}
+//		for(Vector v: this._vectors) {
+//			clone._vectors.add(v);
+//		}
+//		for (Item i: this._interactableItems) {
+//			clone._interactableItems.add(i.copy());
+//		}
+//		for (Item i: this._overlayItems) {
+//			clone._overlayItems.add(i.copy());
+//		}
+//		for (Item i: this._vectorItems) {
+//			clone._vectorItems.add(i.copy());
+//		}
+//		clone._frameData = this._frameData;
+//		clone._frameset = this._frameset;
+//		clone._number = this._number;
+//		clone._version = this._version;
+//		clone._permissionTriple = this._permissionTriple;
+//		clone._owner = this._owner;
+//		clone._creationDate = this._creationDate;
+//		clone._modifiedUser = this._modifiedUser;
+//		clone._modifiedDate = this._modifiedDate;
+//		clone._modifiedDatePrecise = this._modifiedDatePrecise;
+//		clone._frozenDate = this._frozenDate;
+//		clone._background = this._background;
+//		clone._foreground = this._foreground;
+//		clone.path = this.path;
+//		clone._isLocal = this._isLocal;
+//		clone._sorted = this._sorted;
+//		clone._change = this._change;
+//		clone._saved = this._saved;
+//		clone._lineCount = this._lineCount;
+//		clone._itemCount = this._itemCount;
+//		clone._buffer = this._buffer;
+//		clone._validBuffer = this._validBuffer;
+//		clone._activeTime = (Time) this._activeTime.clone();
+//		clone._darkTime = (Time) this._darkTime.clone();
+//		clone._dotTemplate = this._dotTemplate.copy();
+//		
+//		return clone;
+//	}
 
 	public boolean isReadOnly()
@@ -233,5 +292,5 @@
 		return _validBuffer;
 	}
-
+	
 	private void setBufferValid(boolean newValue)
 	{
Index: trunk/src/org/expeditee/io/DefaultFrameReader.java
===================================================================
--- trunk/src/org/expeditee/io/DefaultFrameReader.java	(revision 1407)
+++ trunk/src/org/expeditee/io/DefaultFrameReader.java	(revision 1408)
@@ -181,5 +181,5 @@
 			_DelayedItemTags.add('/');
 			
-			_ItemTagsExt.put("_el", Item.class.getMethod("setEncryptionLabel", pString));
+			_ItemTagsExt.put("_el", Item.class.getMethod("setEncryptionLabelOnLoad", pString));
 			
 			_ItemTagsExt.put("_ph", Text.class.getMethod("setPlaceholder", pString));
Index: trunk/src/org/expeditee/io/DefaultFrameWriter.java
===================================================================
--- trunk/src/org/expeditee/io/DefaultFrameWriter.java	(revision 1407)
+++ trunk/src/org/expeditee/io/DefaultFrameWriter.java	(revision 1408)
@@ -55,7 +55,7 @@
 
 	// keep track of methods that are put on the same line
-	protected static LinkedHashMap<Character, Method> _ItemTags = null;
+	private static LinkedHashMap<Character, Method> _ItemTags = null;
 	// IMPORTANT: keys in _ItemTagsExt must start with underscore as their first character 
-	protected static LinkedHashMap<String, Method> _ItemTagsExt = null;
+	private static LinkedHashMap<String, Method> _ItemTagsExt = null;
 
 	protected static LinkedHashMap<Character, Method> _FrameTags = null;
@@ -319,3 +319,17 @@
 	}
 
+	/**
+	 * @return the _ItemTags
+	 */
+	public static LinkedHashMap<Character, Method> getItemTags() {
+		return _ItemTags;
+	}
+
+	/**
+	 * @return the _ItemTagsExt
+	 */
+	public static LinkedHashMap<String, Method> getItemTagsExt() {
+		return _ItemTagsExt;
+	}
+
 }
Index: trunk/src/org/expeditee/io/ExpReader.java
===================================================================
--- trunk/src/org/expeditee/io/ExpReader.java	(revision 1407)
+++ trunk/src/org/expeditee/io/ExpReader.java	(revision 1408)
@@ -48,7 +48,7 @@
 	public static final String EXTENTION = ".exp";
 
-	private BufferedReader _reader = null;
-
-	private String _frameName;
+	protected BufferedReader _reader = null;
+
+	protected String _frameName;
 
 	/**
@@ -128,90 +128,17 @@
 			newFrame.setName(_frameName);
 
-			final List<DelayedAction> delayedActions = new LinkedList<DelayedAction>();
+			List<DelayedAction> delayedActions = new LinkedList<DelayedAction>();
 			
 			// First read all the header lines
-			while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {
-				if (isValidLine(next)) {
-					processHeaderLine(newFrame, next);
-				}
-			}
+			next = readTheHeader(newFrame);
 
 			// Now read all the items
-			Item currentItem = null;
-			while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {			
-				// if this is the start of a new item add a new item
-				if (isValidLine(next)) {
-					if (getTag(next) == 'S') {
-						String value = getValue(next);
-						int id = Integer.parseInt(value.substring(2));
-
-						switch (value.charAt(0)) {
-						case 'P': // check if its a point
-							currentItem = new Dot(id);
-							break;
-						default:
-							currentItem = new Text(id);
-							break;
-						}
-						_linePoints.put(currentItem.getID(), currentItem);						
-						newFrame.addItem(currentItem);
-					} else if (currentItem != null && actionShouldBeDelayed(getTag(next))) { 
-						delayedActions.add(new DelayedAction(currentItem, next));
-					} else if (currentItem != null) {
-						processBodyLine(currentItem, next);
-//						final boolean hasSpecifiedPermission = currentItem.getPermission() != null;
-//						final boolean hasSpecifiedOwner = currentItem.getOwner() != null;
-//						if (hasSpecifiedPermission && hasSpecifiedOwner && currentItem.getPermission().getPermission(currentItem.getOwner()) == UserAppliedPermission.denied) {
-//							newFrame.removeItem(currentItem);
-//							newFrame.addItemHidden(currentItem);
-//							continue;
-//						}
-					} else {
-						System.err.println("Error while reading in frame (ExpReader): Found body line but no current item to apply it to.");
-					}
-				}
-			}
+			next = readTheItems(newFrame, delayedActions);
 
 			// Read the lines
-			while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {
-				if (isValidLine(next)) {
-					Point idtype = separateValues(next.substring(2));
-					// The next line must be the endpoints
-					if (!_reader.ready()) {
-						throw new Exception("Unexpected end of file");
-					}
-					next = _reader.readLine();
-					Point startend = separateValues(next.substring(2));
-					int start = startend.getX();
-					int end = startend.getY();
-
-					if (_linePoints.get(start) != null
-							&& _linePoints.get(end) != null) {
-						newFrame.addItem(new Line(_linePoints.get(start),
-								_linePoints.get(end), idtype.getX()));
-					} else {
-						System.out
-								.println("Error reading line with unknown end points");
-					}
-				}
-			}
+			next = readTheLines(newFrame);
 
 			// Read the constraints
-			while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {
-				if (isValidLine(next)) {
-					Point idtype = separateValues(next.substring(2));
-					// The next line must be the endpoints
-					if (!_reader.ready()) {
-						throw new Exception("Unexpected end of file");
-					}
-					next = _reader.readLine();
-					Point startend = separateValues(next.substring(2));
-
-					Item a = _linePoints.get(startend.getX());
-					Item b = _linePoints.get(startend.getY());
-
-					new Constraint(a, b, idtype.getX(), idtype.getY());
-				}
-			}
+			next = readTheConstraints();
 			
 			for(DelayedAction action: delayedActions) {
@@ -220,21 +147,5 @@
 
 			// Read the stats
-			while (_reader.ready() && ((next = _reader.readLine()) != null)) {
-				if (next.startsWith(SessionStats.ACTIVE_TIME_ATTRIBUTE)) {
-					try {
-						String value = next.substring(SessionStats.ACTIVE_TIME_ATTRIBUTE.length()).trim();
-						newFrame.setActiveTime(value);
-					} catch (Exception e) {
-					}
-
-				} else if (next.startsWith(SessionStats.DARK_TIME_ATTRIBUTE)) {
-					try {
-						String value = next.substring(SessionStats.DARK_TIME_ATTRIBUTE.length()).trim();
-						newFrame.setDarkTime(value);
-					} catch (Exception e) {
-					}
-
-				}
-			}
+			next = readTheStats(newFrame);
 
 		} catch (Exception e) {
@@ -252,14 +163,132 @@
 	}
 
-	private class DelayedAction {
+	protected String readTheStats(Frame newFrame) throws IOException {
+		String next = null;
+		while (_reader.ready() && ((next = _reader.readLine()) != null)) {
+			if (next.startsWith(SessionStats.ACTIVE_TIME_ATTRIBUTE)) {
+				try {
+					String value = next.substring(SessionStats.ACTIVE_TIME_ATTRIBUTE.length()).trim();
+					newFrame.setActiveTime(value);
+				} catch (Exception e) {
+				}
+
+			} else if (next.startsWith(SessionStats.DARK_TIME_ATTRIBUTE)) {
+				try {
+					String value = next.substring(SessionStats.DARK_TIME_ATTRIBUTE.length()).trim();
+					newFrame.setDarkTime(value);
+				} catch (Exception e) {
+				}
+
+			}
+		}
+		return next;
+	}
+
+	protected String readTheConstraints() throws IOException, Exception {
+		String next = null;
+		while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {
+			if (isValidLine(next)) {
+				Point idtype = separateValues(next.substring(2));
+				// The next line must be the endpoints
+				if (!_reader.ready()) {
+					throw new Exception("Unexpected end of file");
+				}
+				next = _reader.readLine();
+				Point startend = separateValues(next.substring(2));
+
+				Item a = _linePoints.get(startend.getX());
+				Item b = _linePoints.get(startend.getY());
+
+				new Constraint(a, b, idtype.getX(), idtype.getY());
+			}
+		}
+		return next;
+	}
+
+	protected String readTheLines(Frame newFrame) throws IOException, Exception {
+		String next = null;
+		while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {
+			if (isValidLine(next)) {
+				Point idtype = separateValues(next.substring(2));
+				// The next line must be the endpoints
+				if (!_reader.ready()) {
+					throw new Exception("Unexpected end of file");
+				}
+				next = _reader.readLine();
+				Point startend = separateValues(next.substring(2));
+				int start = startend.getX();
+				int end = startend.getY();
+
+				if (_linePoints.get(start) != null
+						&& _linePoints.get(end) != null) {
+					newFrame.addItem(new Line(_linePoints.get(start),
+							_linePoints.get(end), idtype.getX()));
+				} else {
+					System.out
+							.println("Error reading line with unknown end points");
+				}
+			}
+		}
+		return next;
+	}
+
+	protected String readTheItems(Frame newFrame, final List<DelayedAction> delayedActions) throws IOException {
+		String next = null;
+		Item currentItem = null;
+		while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {			
+			// if this is the start of a new item add a new item
+			if (isValidLine(next)) {
+				if (getTag(next) == 'S') {
+					currentItem = newItem(next);
+					_linePoints.put(currentItem.getID(), currentItem);
+					newFrame.addItem(currentItem);
+				} else if (currentItem != null && actionShouldBeDelayed(getTag(next))) { 
+					delayedActions.add(new DelayedAction(currentItem, next));
+				} else if (currentItem != null) {
+					processBodyLine(currentItem, next);
+				} else {
+					System.err.println("Error while reading in frame (ExpReader): Found body line but no current item to apply it to.");
+				}
+			}
+		}
+		return next;
+	}
+
+	protected Item newItem(String line) {
+		Item currentItem;
+		String value = getValue(line);
+		int id = Integer.parseInt(value.substring(2));
+
+		switch (value.charAt(0)) {
+		case 'P': // check if its a point
+			currentItem = new Dot(id);
+			break;
+		default:
+			currentItem = new Text(id);
+			break;
+		}						
+		return currentItem;
+	}
+
+	protected String readTheHeader(Frame newFrame) throws IOException {
+		String next = null;
+		while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {
+			if (isValidLine(next)) {
+				processHeaderLine(newFrame, next);
+			}
+		}
+		return next;
+	}
+
+	public class DelayedAction {
 		private Item theItem;
 		private String theLine;
 
-		DelayedAction(final Item theItem, final String theLine) {
+		public DelayedAction(final Item theItem, final String theLine) {
 			this.theItem = theItem;
 			this.theLine = theLine;	
 		}
 		
-		void exec() {
+		public void exec() {
 			processBodyLine(theItem, theLine);
 		}
@@ -267,5 +296,5 @@
 	
 	// Stores points used when constructing lines
-	private HashMap<Integer, Item> _linePoints = new HashMap<Integer, Item>();
+	protected HashMap<Integer, Item> _linePoints = new HashMap<Integer, Item>();
 
 	/**
Index: trunk/src/org/expeditee/io/ExpWriter.java
===================================================================
--- trunk/src/org/expeditee/io/ExpWriter.java	(revision 1407)
+++ trunk/src/org/expeditee/io/ExpWriter.java	(revision 1408)
@@ -28,4 +28,5 @@
 import java.lang.reflect.Method;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -53,5 +54,5 @@
 	protected String _framename;
 
-	private static final char TERMINATOR = 'Z';
+	protected static final char TERMINATOR = 'Z';
 
 	public ExpWriter() {
@@ -87,5 +88,5 @@
 		try {
 			_FrameTags.remove('A');
-			_ItemTags.put('S', Item.class.getMethod("getTypeAndID",
+			getItemTags().put('S', Item.class.getMethod("getTypeAndID",
 					new Class[] {}));
 		} catch (Exception e) {
@@ -130,6 +131,4 @@
 		writeTerminator();
 		writeLine(SessionStats.getFrameEventList(frame));
-
-		return;
 	}
 
@@ -137,5 +136,5 @@
 	}
 
-	private void writeHeader(Frame toWrite) throws IOException {
+	protected void writeHeader(Frame toWrite) throws IOException {
 		Iterator<Character> it = _FrameTags.keySet().iterator();
 		Object[] param = {};
@@ -185,5 +184,5 @@
 //	}
 
-	private void writeLine(String tag, String line) throws IOException {
+	protected void writeLine(String tag, String line) throws IOException {
 		writeLine(tag + " " + line);
 	}
@@ -227,5 +226,5 @@
 	}
 
-	private List<Item> _lineEnds = new LinkedList<Item>();
+	protected List<Item> _lineEnds = new LinkedList<Item>();
 
 	// Writes out a LineEnd to the file
@@ -306,50 +305,34 @@
 	}
 
-	private void writeClass(Object toWrite) throws IOException {
-		Iterator<Character> it = _ItemTags.keySet().iterator();
-		Iterator<String> itExt = _ItemTagsExt.keySet().iterator();
-		Object[] param = {};
-
+	protected void writeClass(Item toWrite) throws IOException {
+		writeTags(toWrite, new Object[] {}, getItemTags());
+		writeTags(toWrite, new Object[] {}, getItemTagsExt());
+	}
+
+	protected <T> void writeTags(Item toWrite, Object[] param, LinkedHashMap<T, Method> tags) {
+		Iterator<T> it = tags.keySet().iterator();
 		while (it.hasNext()) {
-			Character tag = it.next();
-			Method toRun = _ItemTags.get(tag);
-			Class<?> declarer = toRun.getDeclaringClass();
-			if (declarer.isAssignableFrom(toWrite.getClass())) {
-				try {
-					Object o = toRun.invoke(toWrite, param);
-					o = Conversion.ConvertToExpeditee(toRun, o);
-					if (o != null) {
-						if (o instanceof List) {
-							for (Object line : (List) o) {
-								writeLine(tag.toString(), line.toString());
-							}
-						} else
-							writeLine(tag.toString(), o.toString());
-					}
-				} catch (Exception e) {
-					e.printStackTrace();
+			T tag = it.next();
+			writeTag(toWrite, param, tags, tag);
+		}
+	}
+
+	protected <T> void writeTag(Item toWrite, Object[] param, LinkedHashMap<T, Method> tags, T tag) {
+		Method toRun = tags.get(tag);
+		Class<?> declarer = toRun.getDeclaringClass();
+		if (declarer.isAssignableFrom(toWrite.getClass())) {
+			try {
+				Object o = toRun.invoke(toWrite, param);
+				o = Conversion.ConvertToExpeditee(toRun, o);
+				if (o != null) {
+					if (o instanceof List) {
+						for (Object line : (List) o) {
+							writeLine(tag.toString(), line.toString());
+						}
+					} else
+						writeLine(tag.toString(), o.toString());
 				}
-			}
-		}
-		
-		while (itExt.hasNext()) {
-			String tag = itExt.next();
-			Method toRun = _ItemTagsExt.get(tag);
-			Class<?> declarer = toRun.getDeclaringClass();
-			if (declarer.isAssignableFrom(toWrite.getClass())) {
-				try {
-					Object o = toRun.invoke(toWrite, param);
-					o = Conversion.ConvertToExpeditee(toRun, o);
-					if (o != null) {
-						if (o instanceof List) {
-							for (Object line : (List) o) {
-								writeLine(tag.toString(), line.toString());
-							}
-						} else
-							writeLine(tag.toString(), o.toString());
-					}
-				} catch (Exception e) {
-					e.printStackTrace();
-				}
+			} catch (Exception e) {
+				e.printStackTrace();
 			}
 		}
Index: trunk/src/org/expeditee/io/KMSWriter.java
===================================================================
--- trunk/src/org/expeditee/io/KMSWriter.java	(revision 1407)
+++ trunk/src/org/expeditee/io/KMSWriter.java	(revision 1408)
@@ -81,5 +81,5 @@
 		try {
 			_FrameTags.put('A', Frame.class.getMethod("getName", new Class[] {}));
-			_ItemTags.put('S', Item.class.getMethod("getID", new Class[] {}));
+			getItemTags().put('S', Item.class.getMethod("getID", new Class[] {}));
 		} catch (Exception e) {
 
@@ -258,10 +258,10 @@
 
 	private void writeClass(Object toWrite) throws IOException {
-		Iterator<Character> it = _ItemTags.keySet().iterator();
+		Iterator<Character> it = getItemTags().keySet().iterator();
 		Object[] param = {};
 
 		while (it.hasNext()) {
 			Character tag = it.next();
-			Method toRun = _ItemTags.get(tag);
+			Method toRun = getItemTags().get(tag);
 			Class<?> declarer = toRun.getDeclaringClass();
 			if (declarer.isAssignableFrom(toWrite.getClass())) {
Index: trunk/src/org/expeditee/items/Item.java
===================================================================
--- trunk/src/org/expeditee/items/Item.java	(revision 1407)
+++ trunk/src/org/expeditee/items/Item.java	(revision 1408)
@@ -22,8 +22,11 @@
 import java.util.Collection;
 import java.util.ConcurrentModificationException;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import org.expeditee.actions.Actions;
@@ -44,4 +47,6 @@
 import org.expeditee.core.bounds.EllipticalBounds;
 import org.expeditee.core.bounds.PolygonBounds;
+import org.expeditee.encryption.items.surrogates.EncryptionDetail;
+import org.expeditee.encryption.items.surrogates.Surrogate;
 import org.expeditee.gio.EcosystemManager;
 import org.expeditee.gio.GraphicsManager;
@@ -57,4 +62,5 @@
 import org.expeditee.gui.Vector;
 import org.expeditee.io.Conversion;
+import org.expeditee.io.DefaultFrameWriter;
 import org.expeditee.settings.UserSettings;
 import org.expeditee.settings.legacy.LegacyFeatures;
@@ -312,4 +318,8 @@
 	private Data _data = new Data();
 
+	private Item surrogateFor = null;
+	private Set<Surrogate> surrogateItems = new HashSet<Surrogate>();
+	private Map<String, EncryptionDetail> propertyEncryption = new HashMap<String, EncryptionDetail>();
+	
 	/** Just calls source.duplicateOnto(dest). */
 	public static void DuplicateItem(Item source, Item dest)
@@ -3459,4 +3469,44 @@
 	public void setEncryptionLabel(String label) {
 		this._encryptionLabel = label;
+		if (this.getSurrogates().isEmpty()) {
+			Surrogate surrogate = Surrogate.forItem(this);
+			this.addToSurrogates(surrogate);
+		}
+		
+		for (Character tag: DefaultFrameWriter.getItemTags().keySet()) {
+			if (tag == 'S') {
+				propertyEncryption.put(tag + "", EncryptionDetail.UnencryptedOnSave);
+			} else {
+				propertyEncryption.put(tag + "", EncryptionDetail.ReencryptOnSave);
+			}
+		}
+		
+		for (String tag: DefaultFrameWriter.getItemTagsExt().keySet()) {
+			if (tag == "_el") {
+				propertyEncryption.put(tag, EncryptionDetail.UnencryptedOnSave);
+			} else {
+				propertyEncryption.put(tag, EncryptionDetail.ReencryptOnSave);
+			}
+		}
+	}
+	
+	public void setEncryptionLabelOnLoad(String label) {
+		this._encryptionLabel = label;
+		
+		for (Character tag: DefaultFrameWriter.getItemTags().keySet()) {
+			if (tag == 'S') {
+				propertyEncryption.put(tag + "", EncryptionDetail.UnencryptedOnSave);
+			} else {
+				propertyEncryption.put(tag + "", EncryptionDetail.ReencryptOnSave);
+			}
+		}
+		
+		for (String tag: DefaultFrameWriter.getItemTagsExt().keySet()) {
+			if (tag == "_el") {
+				propertyEncryption.put(tag, EncryptionDetail.UnencryptedOnSave);
+			} else {
+				propertyEncryption.put(tag, EncryptionDetail.ReencryptOnSave);
+			}
+		}
 	}
 
@@ -3511,3 +3561,37 @@
 		return dot;
 	}
+
+	public Set<Surrogate> getSurrogates() {
+		return surrogateItems;
+	}
+		
+	public void setAsSurrogateFor(Item classic) {
+		this.surrogateFor = classic;
+	}
+
+	public void addToSurrogates(Surrogate surrogate) {
+		this.surrogateItems.add(surrogate);
+	}
+	
+	public boolean isSurrogate() {
+		return this.surrogateFor != null;
+	}
+	
+	public Item getClassic() {
+		return this.surrogateFor;
+	}
+	
+	public EncryptionDetail getEncryptionDetailForTag(String tag) {
+		EncryptionDetail encryptionDetail = propertyEncryption.get(tag);
+		
+		if (encryptionDetail == null) {
+			return EncryptionDetail.UnencryptedOnSave;
+		} else {
+			return encryptionDetail;
+		}
+	}
+	
+	public void setEncryptionDetailForTag(String tag, EncryptionDetail encryptionDetail) {
+		propertyEncryption.put(tag, encryptionDetail);
+	}
 }
