/**
	 * Creates a new ZipReader object, which can be used to read from a zip file, as if the zip files were simple
	 * directories. All files are checked to see if they are a zip.
	 *
	 *

	 * {@code new ZipReader(new File("path/to/container.zip/with/nested.zip/file.txt"));}

	 *
	 *
	 * @param file The path to the internal file. This needn't exist, according to File, as the zip file won't appear as
	 * a directory to other classes. This constructor will however throw a FileNotFoundException if it determines that
	 * the file doesn't exist.
	 */
	public ZipReader(File file) {
		chainedPath = new LinkedList<>();

		//We need to remove jar style or uri style things from the file, so do that here
		if(file.getPath().startsWith("jar:")) {
			String newFile = file.getPath().substring(4);
			file = new File(newFile);
		}
		if(file.getPath().startsWith("file:")) {
			String newFile = file.getPath().substring(5);
			//Replace all \ with /, to simply processing, but also replace ! with /, since jar addresses
			//use that to denote the jar. We don't care, it's just a folder, so replace that with a slash.
			newFile = newFile.replace('\\', '/').replace('!', '/');
			while(newFile.startsWith("//")) {
				//We only want up to one slash here
				newFile = newFile.substring(1);
			}
			file = new File(newFile);
		}

		//make sure file is absolute
		file = file.getAbsoluteFile();
		this.file = file;

		//We need to walk up the parents, putting those files onto the stack which are valid Zips
		File f = file;
		chainedPath.addFirst(f); //Gotta add the file itself to the path for everything to work
		File tempTopZip = null;
		while((f = f.getParentFile()) != null) {
			chainedPath.addFirst(f);
			try {
				//If this works, we'll know we have our top zip file. Everything else will have
				//to be in memory, so we'll start with this if we have to dig deeper.
				if(tempTopZip == null) {
					ZipFile zf = new ZipFile(f);
					tempTopZip = f;
				}
			} catch(ZipException ex) {
				//This is fine, it's just not a zip file
			} catch(IOException | AccessControlException ex) {
				//This is fine too, it may mean we don't have permission to access this directory,
				//but that's ok, we don't need access yet.
			}
		}

		//If it's not a zipped file, this will make operations easier to deal with,
		//so let's save that information
		isZipped = tempTopZip != null;
		if(isZipped) {
			topZip = tempTopZip;
		} else {
			topZip = file;
		}

	}

/**
	 * Creates a new ZipReader object, which can be used to read from a zip file, as if the zip files were simple
	 * directories. All files are checked to see if they are a zip.
	 *
	 *

	 * {@code new ZipReader(new File("path/to/container.zip/with/nested.zip/file.txt"));}

	 *
	 *
	 * @param file The path to the internal file. This needn't exist, according to File, as the zip file won't appear as
	 * a directory to other classes. This constructor will however throw a FileNotFoundException if it determines that
	 * the file doesn't exist.
	 */
	public ZipReader(File file) {
		chainedPath = new LinkedList<File>();

		//We need to remove jar style or uri style things from the file, so do that here
		if(file.getPath().startsWith("jar:")) {
			String newFile = file.getPath().substring(4);
			file = new File(newFile);
		}
		if(file.getPath().startsWith("file:")) {
			String newFile = file.getPath().substring(5);
			//Replace all \ with /, to simply processing, but also replace ! with /, since jar addresses
			//use that to denote the jar. We don't care, it's just a folder, so replace that with a slash.
			newFile = newFile.replace('\\', '/').replace('!', '/');
			while(newFile.startsWith("//")) {
				//We only want up to one slash here
				newFile = newFile.substring(1);
			}
			file = new File(newFile);
		}

		//make sure file is absolute
		file = file.getAbsoluteFile();
		this.file = file;

		//We need to walk up the parents, putting those files onto the stack which are valid Zips
		File f = file;
		chainedPath.addFirst(f); //Gotta add the file itself to the path for everything to work
		File tempTopZip = null;
		while((f = f.getParentFile()) != null) {
			chainedPath.addFirst(f);
			try {
				//If this works, we'll know we have our top zip file. Everything else will have
				//to be in memory, so we'll start with this if we have to dig deeper.
				if(tempTopZip == null) {
					ZipFile zf = new ZipFile(f);
					tempTopZip = f;
				}
			} catch(ZipException ex) {
				//This is fine, it's just not a zip file
			} catch(IOException | AccessControlException ex) {
				//This is fine too, it may mean we don't have permission to access this directory,
				//but that's ok, we don't need access yet.
			}
		}

		//If it's not a zipped file, this will make operations easier to deal with,
		//so let's save that information
		isZipped = tempTopZip != null;
		if(isZipped) {
			topZip = tempTopZip;
		} else {
			topZip = file;
		}

	}

Replace Generic With Diamond LinkedList<File> with LinkedList<> in method public ZipReader(file File) from class com.laytonsmith.PureUtilities.ZipReader


	public static void main(String[] args) {
		ArgumentSuite suite = new ArgumentSuite();
		ArgumentParser mode1 = ArgumentParser.GetParser();
		ArgumentParser mode2 = ArgumentParser.GetParser();
		mode1.addArgument("arg1", ArgumentParser.Type.STRING, "Argument 1", "arg1", false);
		mode1.addArgument("arg2", ArgumentParser.Type.STRING, "Argument 2", "arg2", false);
		mode1.addDescription("A description of Mode 1");
		mode2.addArgument("arg1", ArgumentParser.Type.STRING, "Argument 1", "arg1", false);
		mode2.addArgument("arg2", ArgumentParser.Type.STRING, "Argument 2", "arg2", false);
		mode2.addDescription("A description of Mode 2");
		suite.addModeAlias("mode-2", "mode2");
		suite.addModeAlias("mode--2", "mode2");
		ArgumentParser help = ArgumentParser.GetParser();
		help.addDescription("Displays the help for a mode, then exits.")
				.addArgument("The mode name", "mode name", true);
		suite.addDescription("A description of the suite")
				.addMode("help", help)
				.addMode("mode1", mode1)
				.addMode("mode2", mode2);
		try {
			ArgumentSuiteResults results = suite.match("wat", "help");
			ArgumentParser mode = results.getMode();
			ArgumentParserResults modeResults = results.getResults();
			if(mode == help) {
				String modeHelp = modeResults.getStringArgument();
				ArgumentParser selectedMode = suite.getModeFromName(suite.getModeFromAlias(modeHelp));
				if(selectedMode != null) {
					StreamUtils.GetSystemOut().println(selectedMode.getBuiltDescription());
					System.exit(0);
				} else {
					showHelp(suite);
				}
			} else if(mode == mode1 || mode == mode2) {
				String argument;
				if((argument = modeResults.getStringArgument("arg1")) != null) {
					StreamUtils.GetSystemOut().println("You selected " + argument + " for arg1");
				}
				if((argument = modeResults.getStringArgument("arg2")) != null) {
					StreamUtils.GetSystemOut().println("You selected " + argument + " for arg2");
				}
				System.exit(0);
			}
		} catch(ResultUseException | ValidationException ex) {
			showHelp(suite);
		}
	}

	public static void main(String[] args) {
		ArgumentSuite suite = new ArgumentSuite();
		ArgumentParser mode1 = ArgumentParser.GetParser();
		ArgumentParser mode2 = ArgumentParser.GetParser();
		mode1.addArgument("arg1", ArgumentParser.Type.STRING, "Argument 1", "arg1", false);
		mode1.addArgument("arg2", ArgumentParser.Type.STRING, "Argument 2", "arg2", false);
		mode1.addDescription("A description of Mode 1");
		mode2.addArgument("arg1", ArgumentParser.Type.STRING, "Argument 1", "arg1", false);
		mode2.addArgument("arg2", ArgumentParser.Type.STRING, "Argument 2", "arg2", false);
		mode2.addDescription("A description of Mode 2");
		suite.addModeAlias("mode-2", "mode2");
		suite.addModeAlias("mode--2", "mode2");
		ArgumentParser help = ArgumentParser.GetParser();
		help.addDescription("Displays the help for a mode, then exits.")
				.addArgument("The mode name", "mode name", true);
		suite.addDescription("A description of the suite")
				.addMode("help", help)
				.addMode("mode1", mode1)
				.addMode("mode2", mode2);
		try {
			ArgumentSuiteResults results = suite.match("wat", "help");
			ArgumentParser mode = results.getMode();
			ArgumentParserResults modeResults = results.getResults();
			if(mode == help) {
				String modeHelp = modeResults.getStringArgument();
				ArgumentParser selectedMode = suite.getModeFromName(suite.getModeFromAlias(modeHelp));
				if(selectedMode != null) {
					StreamUtils.GetSystemOut().println(selectedMode.getBuiltDescription());
					System.exit(0);
				} else {
					showHelp(suite);
				}
			} else if(mode == mode1 || mode == mode2) {
				String argument;
				if((argument = modeResults.getStringArgument("arg1")) != null) {
					StreamUtils.GetSystemOut().println("You selected " + argument + " for arg1");
				}
				if((argument = modeResults.getStringArgument("arg2")) != null) {
					StreamUtils.GetSystemOut().println("You selected " + argument + " for arg2");
				}
				System.exit(0);
			}
		} catch(ResultUseException ex) {
			showHelp(suite);
		} catch(ValidationException ex) {
			showHelp(suite);
		}
	}

Merge Catch [catch(ResultUseException ex), catch(ValidationException ex)] to catch(ResultUseException|ValidationException ex) in method public main(args String[]) : void from class com.laytonsmith.PureUtilities.ArgumentSuite


	/**
	 * Does the class discovery for this particular URL. This should only be called by doDiscovery. Other internal
	 * methods should call doDiscovery, which handles looking through the dirtyURLs.
	 */
	private synchronized void discover(URL rootLocation) {
		long start = System.currentTimeMillis();
		if(debug) {
			StreamUtils.GetSystemOut().println("Beginning discovery of " + rootLocation);
		}
		try {
			//If the ClassDiscoveryCache is set, just use this.
			if(classDiscoveryCache != null) {
				ClassDiscoveryURLCache cduc = classDiscoveryCache.getURLCache(rootLocation);
				preCaches.put(rootLocation, cduc);
			}

			String url;
			try {
				url = URLDecoder.decode(rootLocation.toString(), "UTF-8");
			} catch(UnsupportedEncodingException ex) {
				// apparently this should never happen, but we have to catch it anyway
				url = null;
			}

			if(url == null) {
				url = GetClassContainer(ClassDiscovery.class).toString();
			}
			final File rootLocationFile;
			if(!classCache.containsKey(rootLocation)) {
				classCache.put(rootLocation, Collections.synchronizedSet(new HashSet<>()));
			} else {
				classCache.get(rootLocation).clear();
			}
			final Set<ClassMirror<?>> mirrors = classCache.get(rootLocation);
			if(preCaches.containsKey(rootLocation)) {
				if(debug) {
					StreamUtils.GetSystemOut().println("Precache already contains this URL, so using it");
				}
				//No need, already got a cache for this url
				mirrors.addAll(preCaches.get(rootLocation).getClasses());
				return;
			}
			if(debug) {
				StreamUtils.GetSystemOut().println("Precache does not contain data for this URL, so scanning now.");
			}
			url = url.replaceFirst("^jar:", "");
			if(url.endsWith("!/")) {
				url = StringUtils.replaceLast(url, "!/", "");
			}
			if(url.startsWith("file:") && !url.endsWith(".jar")) {
				final AtomicInteger id = new AtomicInteger(0);
//				ExecutorService service = Executors.newFixedThreadPool(10, new ThreadFactory() {
//					@Override
//					public Thread newThread(Runnable r) {
//						return new Thread(r, "ClassDiscovery-Async-" + id.incrementAndGet());
//					}
//				});

				//Remove file: from the front
				String root = url.substring(5);
				rootLocationFile = new File(root);
				List<File> fileList = new ArrayList<>();
				descend(new File(root), fileList);

				//Now, we have all the class files in the package. But, it's the absolute path
				//to all of them. We have to first remove the "front" part
				for(File f : fileList) {
					String file = f.toString();
					if(!file.matches(".*\\$(?:\\d)*\\.class") && file.endsWith(".class")) {
						InputStream stream = null;
						try {
							stream = FileUtil.readAsStream(new File(rootLocationFile,
									f.getAbsolutePath().replaceFirst(Pattern.quote(new File(root).getAbsolutePath() + File.separator), "")));
							ClassReader reader = new ClassReader(stream);
							ClassMirrorVisitor mirrorVisitor = new ClassMirrorVisitor();
							reader.accept(mirrorVisitor, ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
							mirrors.add(mirrorVisitor.getMirror(new URL(url)));
						} catch(IOException ex) {
							Logger.getLogger(ClassDiscovery.class.getName()).log(Level.SEVERE, null, ex);
						} finally {
							if(stream != null) {
								try {
									stream.close();
								} catch(IOException ex) {
									Logger.getLogger(ClassDiscovery.class.getName()).log(Level.SEVERE, null, ex);
								}
							}
						}
					}
				}
//				service.shutdown();
//				try {
//					//Doesn't look like 0 is an option, so we'll just wait a day.
//					service.awaitTermination(1, TimeUnit.DAYS);
//				} catch (InterruptedException ex) {
//					Logger.getLogger(ClassDiscovery.class.getName()).log(Level.SEVERE, null, ex);
//				}
			} else if(url.startsWith("file:") && url.endsWith(".jar")) {
				//We are running from a jar
				url = url.replaceFirst("file:", "");
				rootLocationFile = new File(url);
				ZipIterator zi = new ZipIterator(rootLocationFile);
				try {
					zi.iterate(new ZipIterator.ZipIteratorCallback() {
						@Override
						public void handle(String filename, InputStream in) {
							if(!filename.matches(".*\\$(?:\\d)*\\.class") && filename.endsWith(".class")) {
								try {
									ClassReader reader = new ClassReader(in);
									ClassMirrorVisitor mirrorVisitor = new ClassMirrorVisitor();
									reader.accept(mirrorVisitor, ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
									mirrors.add(mirrorVisitor.getMirror(rootLocationFile.toURI().toURL()));
								} catch(IOException ex) {
									Logger.getLogger(ClassDiscovery.class.getName()).log(Level.SEVERE, null, ex);
								}

							}
						}
					}, progressIterator);
				} catch(IOException ex) {
					Logger.getLogger(ClassDiscovery.class.getName()).log(Level.SEVERE, null, ex);
				}
			} else {
				throw new RuntimeException("Unknown url type: " + rootLocation);
			}
		} catch(RuntimeException e) {
			e.printStackTrace(System.err);
		} finally {
			if(debug) {
				StreamUtils.GetSystemOut().println("Scans finished for " + rootLocation + ", taking " + (System.currentTimeMillis() - start) + " ms.");
			}
		}
	}

	/**
	 * Does the class discovery for this particular URL. This should only be called by doDiscovery. Other internal
	 * methods should call doDiscovery, which handles looking through the dirtyURLs.
	 */
	private synchronized void discover(URL rootLocation) {
		long start = System.currentTimeMillis();
		if(debug) {
			StreamUtils.GetSystemOut().println("Beginning discovery of " + rootLocation);
		}
		try {
			//If the ClassDiscoveryCache is set, just use this.
			if(classDiscoveryCache != null) {
				ClassDiscoveryURLCache cduc = classDiscoveryCache.getURLCache(rootLocation);
				preCaches.put(rootLocation, cduc);
			}

			String url;
			try {
				url = URLDecoder.decode(rootLocation.toString(), "UTF-8");
			} catch(UnsupportedEncodingException ex) {
				// apparently this should never happen, but we have to catch it anyway
				url = null;
			}

			if(url == null) {
				url = GetClassContainer(ClassDiscovery.class).toString();
			}
			final File rootLocationFile;
			if(!classCache.containsKey(rootLocation)) {
				classCache.put(rootLocation, Collections.synchronizedSet(new HashSet<ClassMirror<?>>()));
			} else {
				classCache.get(rootLocation).clear();
			}
			final Set<ClassMirror<?>> mirrors = classCache.get(rootLocation);
			if(preCaches.containsKey(rootLocation)) {
				if(debug) {
					StreamUtils.GetSystemOut().println("Precache already contains this URL, so using it");
				}
				//No need, already got a cache for this url
				mirrors.addAll(preCaches.get(rootLocation).getClasses());
				return;
			}
			if(debug) {
				StreamUtils.GetSystemOut().println("Precache does not contain data for this URL, so scanning now.");
			}
			url = url.replaceFirst("^jar:", "");
			if(url.endsWith("!/")) {
				url = StringUtils.replaceLast(url, "!/", "");
			}
			if(url.startsWith("file:") && !url.endsWith(".jar")) {
				final AtomicInteger id = new AtomicInteger(0);
//				ExecutorService service = Executors.newFixedThreadPool(10, new ThreadFactory() {
//					@Override
//					public Thread newThread(Runnable r) {
//						return new Thread(r, "ClassDiscovery-Async-" + id.incrementAndGet());
//					}
//				});

				//Remove file: from the front
				String root = url.substring(5);
				rootLocationFile = new File(root);
				List<File> fileList = new ArrayList<>();
				descend(new File(root), fileList);

				//Now, we have all the class files in the package. But, it's the absolute path
				//to all of them. We have to first remove the "front" part
				for(File f : fileList) {
					String file = f.toString();
					if(!file.matches(".*\\$(?:\\d)*\\.class") && file.endsWith(".class")) {
						InputStream stream = null;
						try {
							stream = FileUtil.readAsStream(new File(rootLocationFile,
									f.getAbsolutePath().replaceFirst(Pattern.quote(new File(root).getAbsolutePath() + File.separator), "")));
							ClassReader reader = new ClassReader(stream);
							ClassMirrorVisitor mirrorVisitor = new ClassMirrorVisitor();
							reader.accept(mirrorVisitor, ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
							mirrors.add(mirrorVisitor.getMirror(new URL(url)));
						} catch(IOException ex) {
							Logger.getLogger(ClassDiscovery.class.getName()).log(Level.SEVERE, null, ex);
						} finally {
							if(stream != null) {
								try {
									stream.close();
								} catch(IOException ex) {
									Logger.getLogger(ClassDiscovery.class.getName()).log(Level.SEVERE, null, ex);
								}
							}
						}
					}
				}
//				service.shutdown();
//				try {
//					//Doesn't look like 0 is an option, so we'll just wait a day.
//					service.awaitTermination(1, TimeUnit.DAYS);
//				} catch (InterruptedException ex) {
//					Logger.getLogger(ClassDiscovery.class.getName()).log(Level.SEVERE, null, ex);
//				}
			} else if(url.startsWith("file:") && url.endsWith(".jar")) {
				//We are running from a jar
				url = url.replaceFirst("file:", "");
				rootLocationFile = new File(url);
				ZipIterator zi = new ZipIterator(rootLocationFile);
				try {
					zi.iterate(new ZipIterator.ZipIteratorCallback() {
						@Override
						public void handle(String filename, InputStream in) {
							if(!filename.matches(".*\\$(?:\\d)*\\.class") && filename.endsWith(".class")) {
								try {
									ClassReader reader = new ClassReader(in);
									ClassMirrorVisitor mirrorVisitor = new ClassMirrorVisitor();
									reader.accept(mirrorVisitor, ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
									mirrors.add(mirrorVisitor.getMirror(rootLocationFile.toURI().toURL()));
								} catch(IOException ex) {
									Logger.getLogger(ClassDiscovery.class.getName()).log(Level.SEVERE, null, ex);
								}

							}
						}
					}, progressIterator);
				} catch(IOException ex) {
					Logger.getLogger(ClassDiscovery.class.getName()).log(Level.SEVERE, null, ex);
				}
			} else {
				throw new RuntimeException("Unknown url type: " + rootLocation);
			}
		} catch(RuntimeException e) {
			e.printStackTrace(System.err);
		} finally {
			if(debug) {
				StreamUtils.GetSystemOut().println("Scans finished for " + rootLocation + ", taking " + (System.currentTimeMillis() - start) + " ms.");
			}
		}
	}

Replace Generic With Diamond HashSet<ClassMirror<?>> with HashSet<> in method private discover(rootLocation URL) : void from class com.laytonsmith.PureUtilities.ClassLoading.ClassDiscovery


	/**
	 * Adds a new discovery URL. This makes the URL eligible to be included when finding classes/methods/fields with the
	 * various other methods. If the URL already has been added, this has no effect.
	 *
	 * @param url
	 */
	public synchronized void addDiscoveryLocation(URL url) {
		if(url == null) {
			throw new NullPointerException("url cannot be null");
		}
		if(urlCache.contains(url)) {
			//Already here, so just return.
			return;
		}
		urlCache.add(url);
		dirtyURLs.add(url);
		classCache.put(url, new HashSet<>());
	}

	/**
	 * Adds a new discovery URL. This makes the URL eligible to be included when finding classes/methods/fields with the
	 * various other methods. If the URL already has been added, this has no effect.
	 *
	 * @param url
	 */
	public synchronized void addDiscoveryLocation(URL url) {
		if(url == null) {
			throw new NullPointerException("url cannot be null");
		}
		if(urlCache.contains(url)) {
			//Already here, so just return.
			return;
		}
		urlCache.add(url);
		dirtyURLs.add(url);
		classCache.put(url, new HashSet<ClassMirror<?>>());
	}

Replace Generic With Diamond HashSet<ClassMirror<?>> with HashSet<> in method public addDiscoveryLocation(url URL) : void from class com.laytonsmith.PureUtilities.ClassLoading.ClassDiscovery


	/**
	 * Combines finding classes with a specified annotation, and classes that extend a certain type.
	 *
	 * @param <T> The type that will be returned, based on superClass
	 * @param annotation The annotation that the classes should be tagged with
	 * @param superClass The super class that the classes should extend
	 * @return A set of class mirrors that match the criteria
	 */
	@SuppressWarnings("unchecked")
	public <T> Set<ClassMirror<? extends T>> getClassesWithAnnotationThatExtend(Class<? extends Annotation> annotation, Class<T> superClass) {
		Set<ClassMirror<? extends T>> mirrors = new HashSet<>();
		for(ClassMirror<?> c : getClassesWithAnnotation(annotation)) {
			if(doesClassExtend(c, superClass)) {
				mirrors.add((ClassMirror<T>) c);
			}
		}
		if(superClass.getAnnotation(annotation) != null) {
			// The mechanism above won't automatically add this class, so we need to add it
			// ourselves here.
			mirrors.add(new ClassMirror<>(superClass));
		}
		return mirrors;
	}

	/**
	 * Combines finding classes with a specified annotation, and classes that extend a certain type.
	 *
	 * @param <T> The type that will be returned, based on superClass
	 * @param annotation The annotation that the classes should be tagged with
	 * @param superClass The super class that the classes should extend
	 * @return A set of class mirrors that match the criteria
	 */
	@SuppressWarnings("unchecked")
	public <T> Set<ClassMirror<? extends T>> getClassesWithAnnotationThatExtend(Class<? extends Annotation> annotation, Class<T> superClass) {
		Set<ClassMirror<? extends T>> mirrors = new HashSet<>();
		for(ClassMirror<?> c : getClassesWithAnnotation(annotation)) {
			if(doesClassExtend(c, superClass)) {
				mirrors.add((ClassMirror<T>) c);
			}
		}
		if(superClass.getAnnotation(annotation) != null) {
			// The mechanism above won't automatically add this class, so we need to add it
			// ourselves here.
			mirrors.add(new ClassMirror<T>(superClass));
		}
		return mirrors;
	}

Replace Generic With Diamond ClassMirror<T> with ClassMirror<> in method public getClassesWithAnnotationThatExtend(annotation Class<? extends Annotation>, superClass Class<T>) : Set<ClassMirror<? extends T>> from class com.laytonsmith.PureUtilities.ClassLoading.ClassDiscovery


	private static List<Field> fields() {
		if(fields == null) {
			fields = new ArrayList<Field>();
			for(Field f : TermColors.class.getFields()) {
				if(f.getAnnotation(color.class) != null) {
					fields.add(f);
					try {
						defaults.put(f.getName(), (String) f.get(null));
					} catch(IllegalArgumentException | IllegalAccessException ex) {
						Logger.getLogger(TermColors.class.getName()).log(Level.SEVERE, null, ex);
					}
				}
			}
		}
		return fields;
	}

	private static List<Field> fields() {
		if(fields == null) {
			fields = new ArrayList<Field>();
			for(Field f : TermColors.class.getFields()) {
				if(f.getAnnotation(color.class) != null) {
					fields.add(f);
					try {
						defaults.put(f.getName(), (String) f.get(null));
					} catch(IllegalArgumentException ex) {
						Logger.getLogger(TermColors.class.getName()).log(Level.SEVERE, null, ex);
					} catch(IllegalAccessException ex) {
						Logger.getLogger(TermColors.class.getName()).log(Level.SEVERE, null, ex);
					}
				}
			}
		}
		return fields;
	}

Merge Catch [catch(IllegalArgumentException ex), catch(IllegalAccessException ex)] to catch(IllegalArgumentException|IllegalAccessException ex) in method private fields() : List<Field> from class com.laytonsmith.PureUtilities.TermColors


	/**
	 * Enables colors.
	 */
	public static void EnableColors() {
		for(Field f : fields()) {
			try {
				f.set(null, defaults.get(f.getName()));
			} catch(IllegalArgumentException | IllegalAccessException ex) {
				Logger.getLogger(TermColors.class.getName()).log(Level.SEVERE, null, ex);
			}
		}
	}

	/**
	 * Enables colors.
	 */
	public static void EnableColors() {
		for(Field f : fields()) {
			try {
				f.set(null, defaults.get(f.getName()));
			} catch(IllegalArgumentException ex) {
				Logger.getLogger(TermColors.class.getName()).log(Level.SEVERE, null, ex);
			} catch(IllegalAccessException ex) {
				Logger.getLogger(TermColors.class.getName()).log(Level.SEVERE, null, ex);
			}
		}
	}

Merge Catch [catch(IllegalArgumentException ex), catch(IllegalAccessException ex)] to catch(IllegalArgumentException|IllegalAccessException ex) in method public EnableColors() : void from class com.laytonsmith.PureUtilities.TermColors


	/**
	 * Disables colors.
	 */
	public static void DisableColors() {
		for(Field f : fields()) {
			try {
				f.set(null, "");
			} catch(IllegalArgumentException | IllegalAccessException ex) {
				Logger.getLogger(TermColors.class.getName()).log(Level.SEVERE, null, ex);
			}
		}
	}

	/**
	 * Disables colors.
	 */
	public static void DisableColors() {
		for(Field f : fields()) {
			try {
				f.set(null, "");
			} catch(IllegalArgumentException ex) {
				Logger.getLogger(TermColors.class.getName()).log(Level.SEVERE, null, ex);
			} catch(IllegalAccessException ex) {
				Logger.getLogger(TermColors.class.getName()).log(Level.SEVERE, null, ex);
			}
		}
	}

Merge Catch [catch(IllegalArgumentException ex), catch(IllegalAccessException ex)] to catch(IllegalArgumentException|IllegalAccessException ex) in method public DisableColors() : void from class com.laytonsmith.PureUtilities.TermColors


				@Override
				public void run() {
					try {
						try {
							//Let the server startup data blindness go by first, so we display any error messages prominently,
							//since an Error is a case of very bad code that shouldn't have been released to begin with.
							Thread.sleep(15000);
						} catch(InterruptedException ex) {
							//
						}
						Set<Class<?>> abstractionenums = ClassDiscovery.getDefaultInstance().loadClassesWithAnnotation(abstractionenum.class);
						for(Class c : abstractionenums) {
							abstractionenum annotation = (abstractionenum) c.getAnnotation(abstractionenum.class);
							if(EnumConvertor.class.isAssignableFrom(c)) {
								EnumConvertor<Enum, Enum> convertor;
								try {
									//Now, if this is not the current server type, skip it
									if(annotation.implementation() != serverType) {
										continue;
									}
									//Next, verify usage of the annotation (it is an error if not used properly)
									//All EnumConvertor subclasses should have public static getConvertor methods, let's grab it now
									Method m = c.getDeclaredMethod("getConvertor");
									convertor = (EnumConvertor<Enum, Enum>) m.invoke(null);
									//Go through and check for a proper mapping both ways, from concrete to abstract, and vice versa.
									//At this point, if there is an error, it is only a warning, NOT an error.
									Class abstractEnum = annotation.forAbstractEnum();
									Class concreteEnum = annotation.forConcreteEnum();
									checkEnumConvertors(convertor, abstractEnum, concreteEnum, false);
									checkEnumConvertors(convertor, concreteEnum, abstractEnum, true);

								} catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
									throw new Error(ex);
								} catch(NoSuchMethodException ex) {
									throw new Error(serverType.getBranding() + ": The method with signature public static " + c.getName() + " getConvertor() was not found in " + c.getName()
											+ " Please add the following code: \n"
											+ "private static " + c.getName() + " instance;\n"
											+ "public static " + c.getName() + " getConvertor(){\n"
											+ "\tif(instance == null){\n"
											+ "\t\tinstance = new " + c.getName() + "();\n"
											+ "\t}\n"
											+ "\treturn instance;\n"
											+ "}\n"
											+ "If you do not know what  error is, please report this to the developers.");
								}
							} else {
								throw new Error("Only classes that extend EnumConvertor may use @abstractionenum. " + c.getName() + " does not, yet it uses the annotation.");
							}

						}
					} catch(Exception e) {
						boolean debugMode;
						try {
							debugMode = Prefs.DebugMode();
						} catch(RuntimeException ex) {
							//Set it to true if we fail to load prefs, which can happen
							//with a buggy front end.
							debugMode = true;
						}
						if(debugMode) {
							//If we're in debug mode, sure, go ahead and print the stack trace,
							//but otherwise we don't want to bother the user.
							e.printStackTrace();
						}
					}
				}

				@Override
				public void run() {
					try {
						try {
							//Let the server startup data blindness go by first, so we display any error messages prominently,
							//since an Error is a case of very bad code that shouldn't have been released to begin with.
							Thread.sleep(15000);
						} catch(InterruptedException ex) {
							//
						}
						Set<Class<?>> abstractionenums = ClassDiscovery.getDefaultInstance().loadClassesWithAnnotation(abstractionenum.class);
						for(Class c : abstractionenums) {
							abstractionenum annotation = (abstractionenum) c.getAnnotation(abstractionenum.class);
							if(EnumConvertor.class.isAssignableFrom(c)) {
								EnumConvertor<Enum, Enum> convertor;
								try {
									//Now, if this is not the current server type, skip it
									if(annotation.implementation() != serverType) {
										continue;
									}
									//Next, verify usage of the annotation (it is an error if not used properly)
									//All EnumConvertor subclasses should have public static getConvertor methods, let's grab it now
									Method m = c.getDeclaredMethod("getConvertor");
									convertor = (EnumConvertor<Enum, Enum>) m.invoke(null);
									//Go through and check for a proper mapping both ways, from concrete to abstract, and vice versa.
									//At this point, if there is an error, it is only a warning, NOT an error.
									Class abstractEnum = annotation.forAbstractEnum();
									Class concreteEnum = annotation.forConcreteEnum();
									checkEnumConvertors(convertor, abstractEnum, concreteEnum, false);
									checkEnumConvertors(convertor, concreteEnum, abstractEnum, true);

								} catch(IllegalAccessException ex) {
									throw new Error(ex);
								} catch(IllegalArgumentException ex) {
									throw new Error(ex);
								} catch(InvocationTargetException ex) {
									throw new Error(ex);
								} catch(NoSuchMethodException ex) {
									throw new Error(serverType.getBranding() + ": The method with signature public static " + c.getName() + " getConvertor() was not found in " + c.getName()
											+ " Please add the following code: \n"
											+ "private static " + c.getName() + " instance;\n"
											+ "public static " + c.getName() + " getConvertor(){\n"
											+ "\tif(instance == null){\n"
											+ "\t\tinstance = new " + c.getName() + "();\n"
											+ "\t}\n"
											+ "\treturn instance;\n"
											+ "}\n"
											+ "If you do not know what  error is, please report this to the developers.");
								}
							} else {
								throw new Error("Only classes that extend EnumConvertor may use @abstractionenum. " + c.getName() + " does not, yet it uses the annotation.");
							}

						}
					} catch(Exception e) {
						boolean debugMode;
						try {
							debugMode = Prefs.DebugMode();
						} catch(RuntimeException ex) {
							//Set it to true if we fail to load prefs, which can happen
							//with a buggy front end.
							debugMode = true;
						}
						if(debugMode) {
							//If we're in debug mode, sure, go ahead and print the stack trace,
							//but otherwise we don't want to bother the user.
							e.printStackTrace();
						}
					}
				}

Merge Catch [catch(IllegalAccessException ex), catch(IllegalArgumentException ex), catch(InvocationTargetException ex)] to catch(IllegalAccessException|IllegalArgumentException|InvocationTargetException ex) in method public run() : void from class com.laytonsmith.abstraction.Implementation.setServerType.new Thread.new Runnable


		@Override
		public boolean add(Object e) {
			if(!(e instanceof BukkitDirtyRegisteredListener) && e instanceof RegisteredListener) {
				try {
					return super.add(Generate((RegisteredListener) e));
				} catch(NoSuchFieldException | IllegalArgumentException | IllegalAccessException ex) {
					Logger.getLogger(BukkitDirtyRegisteredListener.class.getName()).log(Level.SEVERE, null, ex);
				}
			} else {
				return super.add(e);
			}
			return false;
		}

		@Override
		public boolean add(Object e) {
			if(!(e instanceof BukkitDirtyRegisteredListener) && e instanceof RegisteredListener) {
				try {
					return super.add(Generate((RegisteredListener) e));
				} catch(NoSuchFieldException ex) {
					Logger.getLogger(BukkitDirtyRegisteredListener.class.getName()).log(Level.SEVERE, null, ex);
				} catch(IllegalArgumentException ex) {
					Logger.getLogger(BukkitDirtyRegisteredListener.class.getName()).log(Level.SEVERE, null, ex);
				} catch(IllegalAccessException ex) {
					Logger.getLogger(BukkitDirtyRegisteredListener.class.getName()).log(Level.SEVERE, null, ex);
				}
			} else {
				return super.add(e);
			}
			return false;
		}

Merge Catch [catch(NoSuchFieldException ex), catch(IllegalArgumentException ex), catch(IllegalAccessException ex)] to catch(NoSuchFieldException|IllegalArgumentException|IllegalAccessException ex) in method public add(e Object) : boolean from class com.laytonsmith.commandhelper.BukkitDirtyRegisteredListener.DirtyTreeSet


	@Override
	public GenericTreeNode<T> clone() throws CloneNotSupportedException {
		GenericTreeNode<T> clone = (GenericTreeNode<T>) super.clone();
		Class c = data.getClass();
		if(Arrays.asList(c.getInterfaces()).contains(Cloneable.class)) {
			try {
				Method m = c.getMethod("clone", new Class[]{});
				Object obj = m.invoke(data, new Object[]{});
				clone.data = (T) obj;
				clone.children = new ArrayList<GenericTreeNode<T>>(children);
				clone.optimized = optimized;
			} catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException ex) {
				throw new CloneNotSupportedException();
			}
		}
		return clone;
	}

	@Override
	public GenericTreeNode<T> clone() throws CloneNotSupportedException {
		GenericTreeNode<T> clone = (GenericTreeNode<T>) super.clone();
		Class c = data.getClass();
		if(Arrays.asList(c.getInterfaces()).contains(Cloneable.class)) {
			try {
				Method m = c.getMethod("clone", new Class[]{});
				Object obj = m.invoke(data, new Object[]{});
				clone.data = (T) obj;
				clone.children = new ArrayList<GenericTreeNode<T>>(children);
				clone.optimized = optimized;
			} catch(IllegalAccessException ex) {
				throw new CloneNotSupportedException();
			} catch(IllegalArgumentException ex) {
				throw new CloneNotSupportedException();
			} catch(InvocationTargetException ex) {
				throw new CloneNotSupportedException();
			} catch(NoSuchMethodException e) {
				throw new CloneNotSupportedException();
			}
		}
		return clone;
	}

Merge Catch [catch(IllegalAccessException ex), catch(IllegalArgumentException ex), catch(InvocationTargetException ex), catch(NoSuchMethodException e)] to catch(IllegalAccessException|IllegalArgumentException|InvocationTargetException|NoSuchMethodException ex) in method public clone() : GenericTreeNode<T> from class com.laytonsmith.core.GenericTreeNode


		@Override
		public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
			String namespace = GetNamespace(args, null, getName(), t);
			CHLog.GetLogger().Log(CHLog.Tags.PERSISTENCE, LogLevel.DEBUG, "Clearing value: " + namespace, t);
			try {
				environment.getEnv(GlobalEnv.class).GetPersistenceNetwork().clearKey(environment.getEnv(GlobalEnv.class).GetDaemonManager(), ("storage." + namespace).split("\\."));
			} catch(DataSourceException | ReadOnlyException | IOException ex) {
				throw new CREIOException(ex.getMessage(), t, ex);
			} catch(IllegalArgumentException e) {
				throw new CREFormatException(e.getMessage(), t, e);
			}
			return CVoid.VOID;
		}

		@Override
		public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
			String namespace = GetNamespace(args, null, getName(), t);
			CHLog.GetLogger().Log(CHLog.Tags.PERSISTENCE, LogLevel.DEBUG, "Clearing value: " + namespace, t);
			try {
				environment.getEnv(GlobalEnv.class).GetPersistenceNetwork().clearKey(environment.getEnv(GlobalEnv.class).GetDaemonManager(), ("storage." + namespace).split("\\."));
			} catch(DataSourceException ex) {
				throw new CREIOException(ex.getMessage(), t, ex);
			} catch(ReadOnlyException ex) {
				throw new CREIOException(ex.getMessage(), t, ex);
			} catch(IOException ex) {
				throw new CREIOException(ex.getMessage(), t, ex);
			} catch(IllegalArgumentException e) {
				throw new CREFormatException(e.getMessage(), t, e);
			}
			return CVoid.VOID;
		}

Merge Catch [catch(DataSourceException ex), catch(ReadOnlyException ex), catch(IOException ex)] to catch(DataSourceException|ReadOnlyException|IOException ex) in method public exec(t Target, environment Environment, args Construct...) : Construct from class com.laytonsmith.core.functions.Persistence.clear_value


	/**
	 * Sets the field to the given parameter. If the field is a non-dynamic property, it is actually set in the object
	 * (and converted properly), otherwise it is simply added to the dynamic field list.
	 *
	 * @param field
	 * @param value
	 * @param t
	 */
	public final void set(String field, Construct value, Target t) {
		String alias = alias(field);
		if(alias != null) {
			field = alias;
		}
		for(Field f : this.getClass().getFields()) {
			if(f.isAnnotationPresent(nofield.class)) {
				//Skip this one
				continue;
			}
			if(f.getName().equals(field)) {
				//This is it, so let's set it, (converting if necessary) then break
				Object val;
				Class fType = f.getType();
				if(value instanceof CNull) { //TODO
					//Easy case
					val = null;
				} else {
					if(fType == byte.class) {
						val = Static.getInt8(value, t);
					} else if(fType == short.class) {
						val = Static.getInt16(value, t);
					} else if(fType == int.class) {
						val = Static.getInt32(value, t);
					} else if(fType == long.class) {
						val = Static.getInt(value, t);
					} else if(fType == char.class) {
						if(value.val().length() == 0) {
							val = null;
						} else {
							val = value.val().charAt(0);
						}
					} else if(fType == boolean.class) {
						val = Static.getBoolean(value);
					} else if(fType == float.class) {
						val = Static.getDouble32(value, t);
					} else if(fType == double.class) {
						val = Static.getDouble(value, t);
					} else if(fType == MMap.class) {
						CArray ca = Static.getArray(value, t);
						MMap m = new MMap();
						for(String key : ca.stringKeySet()) {
							m.put(key, ca.get(key, t));
						}
						val = m;
					} else if(fType == MList.class) {
						CArray ca = Static.getArray(value, t);
						MList m = new MList();
						if(ca.inAssociativeMode()) {
							throw new CRECastException("Expected non-associative array, but an associative array was found instead.", t);
						}
						for(int i = 0; i < ca.size(); i++) {
							m.add(ca.get(i, t));
						}
						val = m;
					} else if(Construct.class.isAssignableFrom(fType)) {
						val = value;
					} else if(MObject.class.isAssignableFrom(fType)) {
						CArray ca = Static.getArray(value, t);
						val = MObject.Construct(fType, ca);
					} else {
						//Programming error.
						throw new Error(this.getClass().getName() + " contained the public field "
								+ f.getName() + " of type " + fType.getName() + ", which is an unsupported field type.");
					}
				}
				try {
					//val is now set correctly, guaranteed.
					f.set(this, val);
					//These exceptions cannot happen.
				} catch(IllegalArgumentException | IllegalAccessException ex) {
					throw new Error(ex);
				}
			}
		}
		//Always put the dynamic parameter, regardless
		fields.put(field, value);
	}

	/**
	 * Sets the field to the given parameter. If the field is a non-dynamic property, it is actually set in the object
	 * (and converted properly), otherwise it is simply added to the dynamic field list.
	 *
	 * @param field
	 * @param value
	 * @param t
	 */
	public final void set(String field, Construct value, Target t) {
		String alias = alias(field);
		if(alias != null) {
			field = alias;
		}
		for(Field f : this.getClass().getFields()) {
			if(f.isAnnotationPresent(nofield.class)) {
				//Skip this one
				continue;
			}
			if(f.getName().equals(field)) {
				//This is it, so let's set it, (converting if necessary) then break
				Object val;
				Class fType = f.getType();
				if(value instanceof CNull) { //TODO
					//Easy case
					val = null;
				} else {
					if(fType == byte.class) {
						val = Static.getInt8(value, t);
					} else if(fType == short.class) {
						val = Static.getInt16(value, t);
					} else if(fType == int.class) {
						val = Static.getInt32(value, t);
					} else if(fType == long.class) {
						val = Static.getInt(value, t);
					} else if(fType == char.class) {
						if(value.val().length() == 0) {
							val = null;
						} else {
							val = value.val().charAt(0);
						}
					} else if(fType == boolean.class) {
						val = Static.getBoolean(value);
					} else if(fType == float.class) {
						val = Static.getDouble32(value, t);
					} else if(fType == double.class) {
						val = Static.getDouble(value, t);
					} else if(fType == MMap.class) {
						CArray ca = Static.getArray(value, t);
						MMap m = new MMap();
						for(String key : ca.stringKeySet()) {
							m.put(key, ca.get(key, t));
						}
						val = m;
					} else if(fType == MList.class) {
						CArray ca = Static.getArray(value, t);
						MList m = new MList();
						if(ca.inAssociativeMode()) {
							throw new CRECastException("Expected non-associative array, but an associative array was found instead.", t);
						}
						for(int i = 0; i < ca.size(); i++) {
							m.add(ca.get(i, t));
						}
						val = m;
					} else if(Construct.class.isAssignableFrom(fType)) {
						val = value;
					} else if(MObject.class.isAssignableFrom(fType)) {
						CArray ca = Static.getArray(value, t);
						val = MObject.Construct(fType, ca);
					} else {
						//Programming error.
						throw new Error(this.getClass().getName() + " contained the public field "
								+ f.getName() + " of type " + fType.getName() + ", which is an unsupported field type.");
					}
				}
				try {
					//val is now set correctly, guaranteed.
					f.set(this, val);
					//These exceptions cannot happen.
				} catch(IllegalArgumentException ex) {
					throw new Error(ex);
				} catch(IllegalAccessException ex) {
					throw new Error(ex);
				}
			}
		}
		//Always put the dynamic parameter, regardless
		fields.put(field, value);
	}

Merge Catch [catch(IllegalArgumentException ex), catch(IllegalAccessException ex)] to catch(IllegalArgumentException|IllegalAccessException ex) in method public set(field String, value Construct, t Target) : void from class com.laytonsmith.core.natives.interfaces.MObject


	public static void start(String path) throws IOException {
		File start = new File(path);
		if(!start.exists()) {
			StreamUtils.GetSystemErr().println("The specified file does not exist!");
			return;
		}

		File output = new File(start.getParentFile(), start.getName() + ".mslp");
		if(output.exists()) {
			pl("The file " + output.getName() + " already exists, would you like to overwrite? (Y/N)");
			String overwrite = prompt();
			if(!overwrite.equalsIgnoreCase("y")) {
				return;
			}
		}
		//First attempt to compile it, and make sure it doesn't fail
		AliasCore.LocalPackage localPackage = new AliasCore.LocalPackage();
		AliasCore.GetAuxAliases(start, localPackage);
		boolean error = false;
		for(AliasCore.LocalPackage.FileInfo fi : localPackage.getMSFiles()) {
			try {
				MethodScriptCompiler.compile(MethodScriptCompiler.lex(fi.contents(), fi.file(), true));
			} catch(ConfigCompileException e) {
				error = true;
				ConfigRuntimeException.HandleUncaughtException(e, "Compile error in script. Compilation will attempt to continue, however.", null);
			} catch(ConfigCompileGroupException ex) {
				error = true;
				ConfigRuntimeException.HandleUncaughtException(ex, null);
			}
		}
		List<Script> allScripts = new ArrayList<>();
		for(AliasCore.LocalPackage.FileInfo fi : localPackage.getMSAFiles()) {
			List<Script> tempScripts;
			try {
				tempScripts = MethodScriptCompiler.preprocess(MethodScriptCompiler.lex(fi.contents(), fi.file(), false));
				for(Script s : tempScripts) {
					try {
						s.compile();
						s.checkAmbiguous(allScripts);
						allScripts.add(s);
					} catch(ConfigCompileException e) {
						error = true;
						ConfigRuntimeException.HandleUncaughtException(e, "Compile error in script. Compilation will attempt to continue, however.", null);
					} catch(ConfigCompileGroupException e) {
						error = true;
						ConfigRuntimeException.HandleUncaughtException(e, "Compile errors in script. Compilation will attempt to continue, however.", null);
					}
				}
			} catch(ConfigCompileException e) {
				error = true;
				ConfigRuntimeException.HandleUncaughtException(e, "Could not compile file " + fi.file() + " compilation will halt.", null);
			}
		}

		if(!error) {
			ZipMaker.MakeZip(start, output.getName());

			pl(GREEN + "The MSLP file has been created at " + output.getAbsolutePath() + reset());
		} else {
			pl(RED + "MSLP file has not been created due to compile errors. Correct the errors, and try again." + reset());
		}
	}

	public static void start(String path) throws IOException {
		File start = new File(path);
		if(!start.exists()) {
			StreamUtils.GetSystemErr().println("The specified file does not exist!");
			return;
		}

		File output = new File(start.getParentFile(), start.getName() + ".mslp");
		if(output.exists()) {
			pl("The file " + output.getName() + " already exists, would you like to overwrite? (Y/N)");
			String overwrite = prompt();
			if(!overwrite.equalsIgnoreCase("y")) {
				return;
			}
		}
		//First attempt to compile it, and make sure it doesn't fail
		AliasCore.LocalPackage localPackage = new AliasCore.LocalPackage();
		AliasCore.GetAuxAliases(start, localPackage);
		boolean error = false;
		for(AliasCore.LocalPackage.FileInfo fi : localPackage.getMSFiles()) {
			try {
				MethodScriptCompiler.compile(MethodScriptCompiler.lex(fi.contents(), fi.file(), true));
			} catch(ConfigCompileException e) {
				error = true;
				ConfigRuntimeException.HandleUncaughtException(e, "Compile error in script. Compilation will attempt to continue, however.", null);
			} catch(ConfigCompileGroupException ex) {
				error = true;
				ConfigRuntimeException.HandleUncaughtException(ex, null);
			}
		}
		List<Script> allScripts = new ArrayList<Script>();
		for(AliasCore.LocalPackage.FileInfo fi : localPackage.getMSAFiles()) {
			List<Script> tempScripts;
			try {
				tempScripts = MethodScriptCompiler.preprocess(MethodScriptCompiler.lex(fi.contents(), fi.file(), false));
				for(Script s : tempScripts) {
					try {
						s.compile();
						s.checkAmbiguous(allScripts);
						allScripts.add(s);
					} catch(ConfigCompileException e) {
						error = true;
						ConfigRuntimeException.HandleUncaughtException(e, "Compile error in script. Compilation will attempt to continue, however.", null);
					} catch(ConfigCompileGroupException e) {
						error = true;
						ConfigRuntimeException.HandleUncaughtException(e, "Compile errors in script. Compilation will attempt to continue, however.", null);
					}
				}
			} catch(ConfigCompileException e) {
				error = true;
				ConfigRuntimeException.HandleUncaughtException(e, "Could not compile file " + fi.file() + " compilation will halt.", null);
			}
		}

		if(!error) {
			ZipMaker.MakeZip(start, output.getName());

			pl(GREEN + "The MSLP file has been created at " + output.getAbsolutePath() + reset());
		} else {
			pl(RED + "MSLP file has not been created due to compile errors. Correct the errors, and try again." + reset());
		}
	}

Replace Generic With Diamond ArrayList<Script> with ArrayList<> in method public start(path String) : void from class com.laytonsmith.tools.MSLPMaker


	public static void cleardb() {
		try {
			pl(RED + "Are you absolutely sure you want to clear out your database? " + BLINKON + "No backup is going to be made." + BLINKOFF);
			pl(WHITE + "This will completely wipe your persistence information out. (No other data will be changed)");
			pl("[YES/No]");
			String choice = prompt();
			if(choice.equals("YES")) {
				pl("Positive? [YES/No]");
				if(prompt().equals("YES")) {
					p("Ok, here we go... ");
					Set<String[]> keySet = persistenceNetwork.getNamespace(new String[]{}).keySet();
					DaemonManager dm = new DaemonManager();
					for(String[] key : keySet) {
						try {
							persistenceNetwork.clearKey(dm, key);
						} catch(ReadOnlyException ex) {
							pl(RED + "Read only data source found: " + ex.getMessage());
						}
					}
					try {
						dm.waitForThreads();
					} catch(InterruptedException e) {
						//
					}
					pl("Done!");
				}
			} else if(choice.equalsIgnoreCase("yes")) {
				pl("No, you have to type YES exactly.");
			}
		} catch(DataSourceException | IOException ex) {
			pl(RED + ex.getMessage());
		}
	}

	public static void cleardb() {
		try {
			pl(RED + "Are you absolutely sure you want to clear out your database? " + BLINKON + "No backup is going to be made." + BLINKOFF);
			pl(WHITE + "This will completely wipe your persistence information out. (No other data will be changed)");
			pl("[YES/No]");
			String choice = prompt();
			if(choice.equals("YES")) {
				pl("Positive? [YES/No]");
				if(prompt().equals("YES")) {
					p("Ok, here we go... ");
					Set<String[]> keySet = persistenceNetwork.getNamespace(new String[]{}).keySet();
					DaemonManager dm = new DaemonManager();
					for(String[] key : keySet) {
						try {
							persistenceNetwork.clearKey(dm, key);
						} catch(ReadOnlyException ex) {
							pl(RED + "Read only data source found: " + ex.getMessage());
						}
					}
					try {
						dm.waitForThreads();
					} catch(InterruptedException e) {
						//
					}
					pl("Done!");
				}
			} else if(choice.equalsIgnoreCase("yes")) {
				pl("No, you have to type YES exactly.");
			}
		} catch(DataSourceException ex) {
			pl(RED + ex.getMessage());
		} catch(IOException ex) {
			pl(RED + ex.getMessage());
		}
	}

Merge Catch [catch(DataSourceException ex), catch(IOException ex)] to catch(DataSourceException|IOException ex) in method public cleardb() : void from class com.laytonsmith.tools.Manager


	public static void refactor() {
		pl("This tool allows you to granularly move individual keys from one datasource to another."
				+ " Unlike the merge tool, this works with individual keys, not necessarily keys that are"
				+ " within a particular data source. There are three required inputs, the transfer key pattern,"
				+ " the input configuration file, and the output configuration file. Data is transferred from"
				+ " one configuration to the other, that is, it is added in the new place, and removed in the old place."
				+ " This tool is more complicated"
				+ " than the merge tool, so consider using the other tool for simple tasks.\n\n");
		pl("Would you like to continue? [" + GREEN + "Y" + WHITE + "/"
				+ RED + "N" + WHITE + "]");
		String choice = prompt();
		if("Y".equals(choice)) {
			String filter;
			File input;
			File output;
			while(true) {
				while(true) {
					pl("What keys are you interested in transferring? The filter should be in the same format as the persistence.ini file, i.e."
							+ " \"storage.test\" or \"storage.test.**\". If a wildcard is used, multiple keys may be moved, otherwise, only one will"
							+ " be.");
					filter = prompt();
					break;
				}
				File def = MethodScriptFileLocations.getDefault().getPersistenceConfig();
				while(true) {
					pl("What is the input configuration (where keys will be read in from, then deleted)? Leave blank for the default, which is " + def.toString()
							+ ". The path should be relative to " + jarLocation.toString());
					String sinput = prompt();
					if("".equals(sinput.trim())) {
						input = def;
					} else {
						File temp = new File(sinput);
						if(!temp.isAbsolute()) {
							temp = new File(jarLocation, sinput);
						}
						input = temp;
					}
					if(!input.exists() || !input.isFile()) {
						pl(RED + input.toString() + " isn't a file. Please enter an existing file.");
					} else {
						break;
					}
				}
				while(true) {
					pl("What is the output configuration (where keys will be written to)? The path should be relative to " + jarLocation.toString());
					String soutput = prompt();
					if("".equals(soutput.trim())) {
						pl(RED + "The output cannot be empty");
						continue;
					} else {
						File temp = new File(soutput);
						if(!temp.isAbsolute()) {
							temp = new File(jarLocation, soutput);
						}
						output = temp;
					}
					if(!output.exists() || !output.isFile()) {
						pl(RED + output.toString() + " isn't a file. Please enter an existing file.");
					} else {
						break;
					}
				}

				pl("The filter is \"" + MAGENTA + filter + WHITE + "\".");
				pl("The input configuration is \"" + MAGENTA + input.toString() + WHITE + "\".");
				pl("The output configuration is \"" + MAGENTA + output.toString() + WHITE + "\".");
				pl("Is this correct? [" + GREEN + "Y" + WHITE + "/"
						+ RED + "N" + WHITE + "]");
				if("Y".equals(prompt())) {
					break;
				}
			}
			pl(YELLOW + "Now beginning transfer...");
			URI defaultURI;
			try {
				defaultURI = new URI("file://persistence.db");
			} catch(URISyntaxException ex) {
				throw new Error(ex);
			}
			ConnectionMixinFactory.ConnectionMixinOptions mixinOptions = new ConnectionMixinFactory.ConnectionMixinOptions();
			try {
				DaemonManager dm = new DaemonManager();
				mixinOptions.setWorkingDirectory(chDirectory);
				PersistenceNetwork pninput = new PersistenceNetwork(input, defaultURI, mixinOptions);
				PersistenceNetwork pnoutput = new PersistenceNetwork(output, defaultURI, mixinOptions);
				Pattern p = Pattern.compile(DataSourceFilter.toRegex(filter));
				Map<String[], String> inputData = pninput.getNamespace(new String[]{});
				boolean errors = false;
				int transferred = 0;
				int skipped = 0;
				for(String[] k : inputData.keySet()) {
					String key = StringUtils.Join(k, ".");
					if(p.matcher(key).matches()) {
						pl(GREEN + "transferring " + YELLOW + key);
						//This key matches, so we need to add it to the output network, and then remove it
						//from the input network
						if(pnoutput.getKeySource(k).equals(pninput.getKeySource(k))) {
							continue; //Don't transfer it if it's the same source, otherwise we would
							//end up just deleting it.
						}
						try {
							pnoutput.set(dm, k, inputData.get(k));
							transferred++;
							try {
								pninput.clearKey(dm, k);
							} catch(ReadOnlyException ex) {
								pl(RED + "Could not clear out original key for the value for \"" + MAGENTA + StringUtils.Join(k, ".") + RED + "\", as the input"
										+ " file is set to read only.");
								errors = true;
							}
						} catch(ReadOnlyException ex) {
							pl(RED + "Could not write out the value for \"" + MAGENTA + StringUtils.Join(k, ".") + RED + "\", as the output"
									+ " file is set to read only.");
							errors = true;
						}
					} else {
						skipped++;
					}
				}
				pl(YELLOW + StringUtils.PluralTemplateHelper(transferred, "%d key was", "%d keys were") + " transferred.");
				pl(YELLOW + StringUtils.PluralTemplateHelper(skipped, "%d key was", "%d keys were") + " skipped.");
				if(errors) {
					pl(YELLOW + "Other than the errors listed above, all keys were transferred successfully.");
				} else {
					pl(GREEN + "Done!");
				}
				pl(GREEN + "If this is being done as part of an entire transfer process, don't forget to set " + output.toString()
						+ " as your main Persistence Network configuration file.");
			} catch(IOException | DataSourceException ex) {
				Logger.getLogger(Manager.class.getName()).log(Level.SEVERE, null, ex);
			}
		}
	}

	public static void refactor() {
		pl("This tool allows you to granularly move individual keys from one datasource to another."
				+ " Unlike the merge tool, this works with individual keys, not necessarily keys that are"
				+ " within a particular data source. There are three required inputs, the transfer key pattern,"
				+ " the input configuration file, and the output configuration file. Data is transferred from"
				+ " one configuration to the other, that is, it is added in the new place, and removed in the old place."
				+ " This tool is more complicated"
				+ " than the merge tool, so consider using the other tool for simple tasks.\n\n");
		pl("Would you like to continue? [" + GREEN + "Y" + WHITE + "/"
				+ RED + "N" + WHITE + "]");
		String choice = prompt();
		if("Y".equals(choice)) {
			String filter;
			File input;
			File output;
			while(true) {
				while(true) {
					pl("What keys are you interested in transferring? The filter should be in the same format as the persistence.ini file, i.e."
							+ " \"storage.test\" or \"storage.test.**\". If a wildcard is used, multiple keys may be moved, otherwise, only one will"
							+ " be.");
					filter = prompt();
					break;
				}
				File def = MethodScriptFileLocations.getDefault().getPersistenceConfig();
				while(true) {
					pl("What is the input configuration (where keys will be read in from, then deleted)? Leave blank for the default, which is " + def.toString()
							+ ". The path should be relative to " + jarLocation.toString());
					String sinput = prompt();
					if("".equals(sinput.trim())) {
						input = def;
					} else {
						File temp = new File(sinput);
						if(!temp.isAbsolute()) {
							temp = new File(jarLocation, sinput);
						}
						input = temp;
					}
					if(!input.exists() || !input.isFile()) {
						pl(RED + input.toString() + " isn't a file. Please enter an existing file.");
					} else {
						break;
					}
				}
				while(true) {
					pl("What is the output configuration (where keys will be written to)? The path should be relative to " + jarLocation.toString());
					String soutput = prompt();
					if("".equals(soutput.trim())) {
						pl(RED + "The output cannot be empty");
						continue;
					} else {
						File temp = new File(soutput);
						if(!temp.isAbsolute()) {
							temp = new File(jarLocation, soutput);
						}
						output = temp;
					}
					if(!output.exists() || !output.isFile()) {
						pl(RED + output.toString() + " isn't a file. Please enter an existing file.");
					} else {
						break;
					}
				}

				pl("The filter is \"" + MAGENTA + filter + WHITE + "\".");
				pl("The input configuration is \"" + MAGENTA + input.toString() + WHITE + "\".");
				pl("The output configuration is \"" + MAGENTA + output.toString() + WHITE + "\".");
				pl("Is this correct? [" + GREEN + "Y" + WHITE + "/"
						+ RED + "N" + WHITE + "]");
				if("Y".equals(prompt())) {
					break;
				}
			}
			pl(YELLOW + "Now beginning transfer...");
			URI defaultURI;
			try {
				defaultURI = new URI("file://persistence.db");
			} catch(URISyntaxException ex) {
				throw new Error(ex);
			}
			ConnectionMixinFactory.ConnectionMixinOptions mixinOptions = new ConnectionMixinFactory.ConnectionMixinOptions();
			try {
				DaemonManager dm = new DaemonManager();
				mixinOptions.setWorkingDirectory(chDirectory);
				PersistenceNetwork pninput = new PersistenceNetwork(input, defaultURI, mixinOptions);
				PersistenceNetwork pnoutput = new PersistenceNetwork(output, defaultURI, mixinOptions);
				Pattern p = Pattern.compile(DataSourceFilter.toRegex(filter));
				Map<String[], String> inputData = pninput.getNamespace(new String[]{});
				boolean errors = false;
				int transferred = 0;
				int skipped = 0;
				for(String[] k : inputData.keySet()) {
					String key = StringUtils.Join(k, ".");
					if(p.matcher(key).matches()) {
						pl(GREEN + "transferring " + YELLOW + key);
						//This key matches, so we need to add it to the output network, and then remove it
						//from the input network
						if(pnoutput.getKeySource(k).equals(pninput.getKeySource(k))) {
							continue; //Don't transfer it if it's the same source, otherwise we would
							//end up just deleting it.
						}
						try {
							pnoutput.set(dm, k, inputData.get(k));
							transferred++;
							try {
								pninput.clearKey(dm, k);
							} catch(ReadOnlyException ex) {
								pl(RED + "Could not clear out original key for the value for \"" + MAGENTA + StringUtils.Join(k, ".") + RED + "\", as the input"
										+ " file is set to read only.");
								errors = true;
							}
						} catch(ReadOnlyException ex) {
							pl(RED + "Could not write out the value for \"" + MAGENTA + StringUtils.Join(k, ".") + RED + "\", as the output"
									+ " file is set to read only.");
							errors = true;
						}
					} else {
						skipped++;
					}
				}
				pl(YELLOW + StringUtils.PluralTemplateHelper(transferred, "%d key was", "%d keys were") + " transferred.");
				pl(YELLOW + StringUtils.PluralTemplateHelper(skipped, "%d key was", "%d keys were") + " skipped.");
				if(errors) {
					pl(YELLOW + "Other than the errors listed above, all keys were transferred successfully.");
				} else {
					pl(GREEN + "Done!");
				}
				pl(GREEN + "If this is being done as part of an entire transfer process, don't forget to set " + output.toString()
						+ " as your main Persistence Network configuration file.");
			} catch(IOException ex) {
				Logger.getLogger(Manager.class.getName()).log(Level.SEVERE, null, ex);
			} catch(DataSourceException ex) {
				Logger.getLogger(Manager.class.getName()).log(Level.SEVERE, null, ex);
			}
		}
	}

Merge Catch [catch(IOException ex), catch(DataSourceException ex)] to catch(IOException|DataSourceException ex) in method public refactor() : void from class com.laytonsmith.tools.Manager


/**
	 * Returns the documentation for a single function.
	 *
	 * @param type The type of output to use. May be one of: html, wiki, text
	 * @param platform The platform we're using
	 * @param staged Is this for the staged wiki?
	 * @return
	 * @throws ConfigCompileException
	 */
	@SuppressWarnings("StringConcatenationInsideStringBufferAppend")
	public static String functions(MarkupType type, api.Platforms platform, boolean staged) throws ConfigCompileException {
		Set<FunctionBase> functions = FunctionList.getFunctionList(platform);
		HashMap<Class, ArrayList<FunctionBase>> functionlist = new HashMap<Class, ArrayList<FunctionBase>>();
		StringBuilder out = new StringBuilder();
		for(FunctionBase f : functions) {
			//Sort the functions into classes
			Class apiClass = (f.getClass().getEnclosingClass() != null
					? f.getClass().getEnclosingClass()
					: null);
			ArrayList<FunctionBase> fl = functionlist.get(apiClass);
			if(fl == null) {
				fl = new ArrayList<FunctionBase>();
				functionlist.put(apiClass, fl);
			}
			fl.add(f);
		}
		if(type == MarkupType.HTML) {
			out.append("Command Helper uses a language called MethodScript, which greatly extend the capabilities of the plugin, "
					+ "and make the plugin a fully "
					+ "Turing Complete language. "
					+ "There are several functions defined, and they are grouped into \"classes\". \n");
		} else if(type == MarkupType.WIKI) {
			out.append("Command Helper uses a language called MethodScript, which greatly extend the capabilities of the plugin, "
					+ "and make the plugin a fully "
					+ "[http://en.wikipedia.org/wiki/Turing_Complete Turing Complete] language. "
					+ "There are several functions defined, and they are grouped into \"classes\". \n");
			out.append("
Each function has its own page for documentation, where you can view examples for how to use a"
					+ " particular function.\n");
		} else if(type == MarkupType.TEXT) {
			out.append("Command Helper uses a language called MethodScript, which greatly extend the capabilities of the plugin, "
					+ "and make the plugin a fully "
					+ "Turing Complete language [http://en.wikipedia.org/wiki/Turing_Complete].\n"
					+ "There are several functions defined, and they are grouped into \"classes\".\n");
		}
		List<Map.Entry<Class, ArrayList<FunctionBase>>> entrySet = new ArrayList<Map.Entry<Class, ArrayList<FunctionBase>>>(functionlist.entrySet());
		Collections.sort(entrySet, new Comparator<Map.Entry<Class, ArrayList<FunctionBase>>>() {

			@Override
			public int compare(Map.Entry<Class, ArrayList<FunctionBase>> o1, Map.Entry<Class, ArrayList<FunctionBase>> o2) {
				return o1.getKey().getName().compareTo(o2.getKey().getName());
			}
		});
		int total = 0;

		int workingExamples = 0;
		for(Map.Entry<Class, ArrayList<FunctionBase>> entry : entrySet) {
			Class apiClass = entry.getKey();
			String className = apiClass.getName().split("\\.")[apiClass.getName().split("\\.").length - 1];
			if(className.equals("Sandbox")) {
				continue; //Skip Sandbox functions
			}
			String classDocs = null;
			try {
				Method m = apiClass.getMethod("docs", (Class[]) null);
				Object o = null;
				if((m.getModifiers() & Modifier.STATIC) == 0) {
					try {
						o = apiClass.newInstance();
					} catch(InstantiationException ex) {
					}
				}
				classDocs = (String) m.invoke(o, (Object[]) null);
			} catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException ex) {
			} catch(Exception e) {
				e.printStackTrace(StreamUtils.GetSystemErr());
				StreamUtils.GetSystemErr().println("Continuing however.");
			}
			StringBuilder intro = new StringBuilder();
			if(type == MarkupType.HTML) {
				if(className != null) {
					intro.append("
").append(className).append("
" + "\n");
					intro.append(classDocs == null ? "" : classDocs).append("\n");
				} else {
					intro.append("
Other Functions
" + "\n");
				}
				intro.append("
" + "\n");
			} else if(type == MarkupType.WIKI) {
				if(className != null) {
					intro.append("===").append(className).append("===" + "\n");
					intro.append(classDocs == null ? "" : classDocs).append("\n");
				} else {
					intro.append("===Other Functions===" + "\n");
				}
				intro.append("{| width=\"100%\" cellspacing=\"1\" cellpadding=\"1\" border=\"1\" class=\"wikitable\"\n"
						+ "|-\n"
						+ "! scope=\"col\" width=\"6%\" | Function Name\n"
						+ "! scope=\"col\" width=\"5%\" | Returns\n"
						+ "! scope=\"col\" width=\"10%\" | Arguments\n"
						+ "! scope=\"col\" width=\"10%\" | Throws\n"
						+ "! scope=\"col\" width=\"61%\" | Description\n"
						+ "! scope=\"col\" width=\"3%\" | Since\n"
						+ "! scope=\"col\" width=\"5%\" | Restricted" + "\n");
			} else if(type == MarkupType.TEXT) {
				intro.append("\n").append(className).append("\n");
				intro.append("**********************************************************************************************" + "\n");
				if(className != null) {
					intro.append(classDocs == null ? "" : classDocs).append("\n");
				} else {
					intro.append("Other Functions" + "\n");
				}
				intro.append("**********************************************************************************************" + "\n");
			}
			List<FunctionBase> documentableFunctions = new ArrayList<FunctionBase>();
			for(FunctionBase f : entry.getValue()) {
				if(f.appearInDocumentation()) {
					documentableFunctions.add(f);
				}
			}
			if(!documentableFunctions.isEmpty()) {
				out.append(intro.toString() + "\n");
			}
			Collections.sort(documentableFunctions, new Comparator<FunctionBase>() {

				@Override
				public int compare(FunctionBase o1, FunctionBase o2) {
					return o1.getName().compareTo(o2.getName());
				}
			});
			for(FunctionBase f : documentableFunctions) {
				total++;
				String doc = f.docs();
				String restricted = (f instanceof Function && ((Function) f).isRestricted()) ? "
Yes
"
						: "
No
";
				StringBuilder thrown = new StringBuilder();
				if(f instanceof Function && ((Function) f).thrown() != null) {
					List<Class<? extends CREThrowable>> thrownList = Arrays.asList(((Function) f).thrown());
					for(int i = 0; i < thrownList.size(); i++) {
						String t = ((Class<? extends CREThrowable>) thrownList.get(i)).getAnnotation(typeof.class).value();
						if(type == MarkupType.HTML || type == MarkupType.TEXT) {
							if(i != 0) {
								thrown.append((type == MarkupType.HTML ? "
\n" : " | "));
							}
							thrown.append(t);
						} else {
							if(i != 0) {
								thrown.append("
\n");
							}
							thrown.append("[[CommandHelper/Exceptions#").append(t).append("|").append(t).append("]]");
						}
					}
				}

				String since = (f instanceof Documentation ? ((Documentation) f).since().toString() : "0.0.0");
				DocInfo di = new DocInfo(doc);
				boolean hasExample = false;
				if(f instanceof Function && ((Function) f).examples() != null && ((Function) f).examples().length > 0) {
					hasExample = true;
					workingExamples++;
				}
				if(di.ret == null || di.args == null || di.desc == null) {
					out.append(f.getName() + "'s documentation is not correctly formatted. Please check it and try again.\n");
				}
				if(type == MarkupType.HTML) {
					out.append("
" + di.ret + "	" + di.args + "	" + thrown.toString() + "	" + di.desc + "	" + since + "	" + restricted + "
\n");
				} else if(type == MarkupType.WIKI) {
					//Turn args into a prettified version
					out.append("|- id=\"" + f.getName() + "\"\n"
							+ "! scope=\"row\" | [[CommandHelper/" + (staged ? "Staged/" : "") + "API/" + f.getName() + "|" + f.getName() + "]]()\n"
							+ "| " + di.ret + "\n"
							+ "| " + di.args + "\n"
							+ "| " + thrown.toString() + "\n"
							+ "| " + (di.topDesc != null ? di.topDesc + " [[CommandHelper/" + (staged ? "Staged/" : "") + "API/" + f.getName() + "#Description|See More...]]" : di.desc)
							+ (hasExample ? "
([[CommandHelper/" + (staged ? "Staged/" : "") + "API/" + f.getName() + "#Examples|Examples...]])" : "") + "\n"
							+ "| " + since + "\n"
							+ "| " + restricted + "\n");

				} else if(type == MarkupType.TEXT) {
					out.append(di.ret + " " + f.getName() + "(" + di.args + ")" + " {" + thrown.toString() + "}\n\t" + di.desc + "\n\t" + since + ((f instanceof Function ? ((Function) f).isRestricted() : false) ? "\n\tThis function is restricted"
							: "\n\tThis function is not restricted\n"));
				}
			}
			if(!documentableFunctions.isEmpty()) {
				if(type == MarkupType.HTML) {
					out.append("
\n");
				} else if(type == MarkupType.WIKI) {
					out.append("|}\n{{Back to top}}\n");
				} else if(type == MarkupType.TEXT) {
					out.append("\n");
				}
			}
		}
		if(type == MarkupType.HTML) {
			out.append(""
					+ "
Errors in documentation
\n"
					+ "Please note that this documentation is generated automatically,"
					+ " if you notice an error in the documentation, please file a bug report for the"
					+ " plugin itself!"
					+ "
There are " + total + " functions in this API page
\n");
		} else if(type == MarkupType.WIKI) {
			out.append(""
					+ "===Errors in documentation===\n"
					+ "''Please note that this documentation is generated automatically,"
					+ " if you notice an error in the documentation, please file a bug report for the"
					+ " plugin itself!'' For information on undocumented functions, see [[CommandHelper/Sandbox|this page]]"
					+ "
There are " + total + " functions in this API page, " + workingExamples + " of which"
					+ " have examples.
\n\n{{Back to top}}\n{{LearningTrail}}\n");
		}
		return out.toString();
	}

/**
	 * Returns the documentation for a single function.
	 *
	 * @param type The type of output to use. May be one of: html, wiki, text
	 * @param platform The platform we're using
	 * @param staged Is this for the staged wiki?
	 * @return
	 * @throws ConfigCompileException
	 */
	@SuppressWarnings("StringConcatenationInsideStringBufferAppend")
	public static String functions(MarkupType type, api.Platforms platform, boolean staged) throws ConfigCompileException {
		Set<FunctionBase> functions = FunctionList.getFunctionList(platform);
		HashMap<Class, ArrayList<FunctionBase>> functionlist = new HashMap<Class, ArrayList<FunctionBase>>();
		StringBuilder out = new StringBuilder();
		for(FunctionBase f : functions) {
			//Sort the functions into classes
			Class apiClass = (f.getClass().getEnclosingClass() != null
					? f.getClass().getEnclosingClass()
					: null);
			ArrayList<FunctionBase> fl = functionlist.get(apiClass);
			if(fl == null) {
				fl = new ArrayList<FunctionBase>();
				functionlist.put(apiClass, fl);
			}
			fl.add(f);
		}
		if(type == MarkupType.HTML) {
			out.append("Command Helper uses a language called MethodScript, which greatly extend the capabilities of the plugin, "
					+ "and make the plugin a fully "
					+ "Turing Complete language. "
					+ "There are several functions defined, and they are grouped into \"classes\". \n");
		} else if(type == MarkupType.WIKI) {
			out.append("Command Helper uses a language called MethodScript, which greatly extend the capabilities of the plugin, "
					+ "and make the plugin a fully "
					+ "[http://en.wikipedia.org/wiki/Turing_Complete Turing Complete] language. "
					+ "There are several functions defined, and they are grouped into \"classes\". \n");
			out.append("
Each function has its own page for documentation, where you can view examples for how to use a"
					+ " particular function.\n");
		} else if(type == MarkupType.TEXT) {
			out.append("Command Helper uses a language called MethodScript, which greatly extend the capabilities of the plugin, "
					+ "and make the plugin a fully "
					+ "Turing Complete language [http://en.wikipedia.org/wiki/Turing_Complete].\n"
					+ "There are several functions defined, and they are grouped into \"classes\".\n");
		}
		List<Map.Entry<Class, ArrayList<FunctionBase>>> entrySet = new ArrayList<Map.Entry<Class, ArrayList<FunctionBase>>>(functionlist.entrySet());
		Collections.sort(entrySet, new Comparator<Map.Entry<Class, ArrayList<FunctionBase>>>() {

			@Override
			public int compare(Map.Entry<Class, ArrayList<FunctionBase>> o1, Map.Entry<Class, ArrayList<FunctionBase>> o2) {
				return o1.getKey().getName().compareTo(o2.getKey().getName());
			}
		});
		int total = 0;

		int workingExamples = 0;
		for(Map.Entry<Class, ArrayList<FunctionBase>> entry : entrySet) {
			Class apiClass = entry.getKey();
			String className = apiClass.getName().split("\\.")[apiClass.getName().split("\\.").length - 1];
			if(className.equals("Sandbox")) {
				continue; //Skip Sandbox functions
			}
			String classDocs = null;
			try {
				Method m = apiClass.getMethod("docs", (Class[]) null);
				Object o = null;
				if((m.getModifiers() & Modifier.STATIC) == 0) {
					try {
						o = apiClass.newInstance();
					} catch(InstantiationException ex) {
					}
				}
				classDocs = (String) m.invoke(o, (Object[]) null);
			} catch(IllegalAccessException ex) {
			} catch(IllegalArgumentException ex) {
			} catch(InvocationTargetException ex) {
			} catch(NoSuchMethodException e) {
			} catch(Exception e) {
				e.printStackTrace(StreamUtils.GetSystemErr());
				StreamUtils.GetSystemErr().println("Continuing however.");
			}
			StringBuilder intro = new StringBuilder();
			if(type == MarkupType.HTML) {
				if(className != null) {
					intro.append("
").append(className).append("
" + "\n");
					intro.append(classDocs == null ? "" : classDocs).append("\n");
				} else {
					intro.append("
Other Functions
" + "\n");
				}
				intro.append("
" + "\n");
			} else if(type == MarkupType.WIKI) {
				if(className != null) {
					intro.append("===").append(className).append("===" + "\n");
					intro.append(classDocs == null ? "" : classDocs).append("\n");
				} else {
					intro.append("===Other Functions===" + "\n");
				}
				intro.append("{| width=\"100%\" cellspacing=\"1\" cellpadding=\"1\" border=\"1\" class=\"wikitable\"\n"
						+ "|-\n"
						+ "! scope=\"col\" width=\"6%\" | Function Name\n"
						+ "! scope=\"col\" width=\"5%\" | Returns\n"
						+ "! scope=\"col\" width=\"10%\" | Arguments\n"
						+ "! scope=\"col\" width=\"10%\" | Throws\n"
						+ "! scope=\"col\" width=\"61%\" | Description\n"
						+ "! scope=\"col\" width=\"3%\" | Since\n"
						+ "! scope=\"col\" width=\"5%\" | Restricted" + "\n");
			} else if(type == MarkupType.TEXT) {
				intro.append("\n").append(className).append("\n");
				intro.append("**********************************************************************************************" + "\n");
				if(className != null) {
					intro.append(classDocs == null ? "" : classDocs).append("\n");
				} else {
					intro.append("Other Functions" + "\n");
				}
				intro.append("**********************************************************************************************" + "\n");
			}
			List<FunctionBase> documentableFunctions = new ArrayList<FunctionBase>();
			for(FunctionBase f : entry.getValue()) {
				if(f.appearInDocumentation()) {
					documentableFunctions.add(f);
				}
			}
			if(!documentableFunctions.isEmpty()) {
				out.append(intro.toString() + "\n");
			}
			Collections.sort(documentableFunctions, new Comparator<FunctionBase>() {

				@Override
				public int compare(FunctionBase o1, FunctionBase o2) {
					return o1.getName().compareTo(o2.getName());
				}
			});
			for(FunctionBase f : documentableFunctions) {
				total++;
				String doc = f.docs();
				String restricted = (f instanceof Function && ((Function) f).isRestricted()) ? "
Yes
"
						: "
No
";
				StringBuilder thrown = new StringBuilder();
				if(f instanceof Function && ((Function) f).thrown() != null) {
					List<Class<? extends CREThrowable>> thrownList = Arrays.asList(((Function) f).thrown());
					for(int i = 0; i < thrownList.size(); i++) {
						String t = ((Class<? extends CREThrowable>) thrownList.get(i)).getAnnotation(typeof.class).value();
						if(type == MarkupType.HTML || type == MarkupType.TEXT) {
							if(i != 0) {
								thrown.append((type == MarkupType.HTML ? "
\n" : " | "));
							}
							thrown.append(t);
						} else {
							if(i != 0) {
								thrown.append("
\n");
							}
							thrown.append("[[CommandHelper/Exceptions#").append(t).append("|").append(t).append("]]");
						}
					}
				}

				String since = (f instanceof Documentation ? ((Documentation) f).since().toString() : "0.0.0");
				DocInfo di = new DocInfo(doc);
				boolean hasExample = false;
				if(f instanceof Function && ((Function) f).examples() != null && ((Function) f).examples().length > 0) {
					hasExample = true;
					workingExamples++;
				}
				if(di.ret == null || di.args == null || di.desc == null) {
					out.append(f.getName() + "'s documentation is not correctly formatted. Please check it and try again.\n");
				}
				if(type == MarkupType.HTML) {
					out.append("
" + di.ret + "	" + di.args + "	" + thrown.toString() + "	" + di.desc + "	" + since + "	" + restricted + "
\n");
				} else if(type == MarkupType.WIKI) {
					//Turn args into a prettified version
					out.append("|- id=\"" + f.getName() + "\"\n"
							+ "! scope=\"row\" | [[CommandHelper/" + (staged ? "Staged/" : "") + "API/" + f.getName() + "|" + f.getName() + "]]()\n"
							+ "| " + di.ret + "\n"
							+ "| " + di.args + "\n"
							+ "| " + thrown.toString() + "\n"
							+ "| " + (di.topDesc != null ? di.topDesc + " [[CommandHelper/" + (staged ? "Staged/" : "") + "API/" + f.getName() + "#Description|See More...]]" : di.desc)
							+ (hasExample ? "
([[CommandHelper/" + (staged ? "Staged/" : "") + "API/" + f.getName() + "#Examples|Examples...]])" : "") + "\n"
							+ "| " + since + "\n"
							+ "| " + restricted + "\n");

				} else if(type == MarkupType.TEXT) {
					out.append(di.ret + " " + f.getName() + "(" + di.args + ")" + " {" + thrown.toString() + "}\n\t" + di.desc + "\n\t" + since + ((f instanceof Function ? ((Function) f).isRestricted() : false) ? "\n\tThis function is restricted"
							: "\n\tThis function is not restricted\n"));
				}
			}
			if(!documentableFunctions.isEmpty()) {
				if(type == MarkupType.HTML) {
					out.append("
\n");
				} else if(type == MarkupType.WIKI) {
					out.append("|}\n{{Back to top}}\n");
				} else if(type == MarkupType.TEXT) {
					out.append("\n");
				}
			}
		}
		if(type == MarkupType.HTML) {
			out.append(""
					+ "
Errors in documentation
\n"
					+ "Please note that this documentation is generated automatically,"
					+ " if you notice an error in the documentation, please file a bug report for the"
					+ " plugin itself!"
					+ "
There are " + total + " functions in this API page
\n");
		} else if(type == MarkupType.WIKI) {
			out.append(""
					+ "===Errors in documentation===\n"
					+ "''Please note that this documentation is generated automatically,"
					+ " if you notice an error in the documentation, please file a bug report for the"
					+ " plugin itself!'' For information on undocumented functions, see [[CommandHelper/Sandbox|this page]]"
					+ "
There are " + total + " functions in this API page, " + workingExamples + " of which"
					+ " have examples.
\n\n{{Back to top}}\n{{LearningTrail}}\n");
		}
		return out.toString();
	}

Merge Catch [catch(IllegalAccessException ex), catch(IllegalArgumentException ex), catch(InvocationTargetException ex), catch(NoSuchMethodException e)] to catch(IllegalAccessException|IllegalArgumentException|InvocationTargetException|NoSuchMethodException ex) in method public functions(type MarkupType, platform api.Platforms, staged boolean) : String from class com.laytonsmith.tools.docgen.DocGen


	private void doExamples() throws ConfigCompileException, XPathExpressionException, IOException, DataSourceException, Exception {
		//So they are alphabetical, so we always have a consistent upload order, to
		//facilitate tracing problems.
		SortedSet<String> names = new TreeSet<>();
		for(FunctionBase base : FunctionList.getFunctionList(api.Platforms.INTERPRETER_JAVA)) {
			String name = base.getName();
			if(base.appearInDocumentation()) {
				names.add(name);
			}
		}
		for(String name : names) {
			String docs = DocGen.examples(name, isStaged);
			doUpload(docs, "/API/" + name, true);
		}
	}

	private void doExamples() throws ConfigCompileException, XPathExpressionException, IOException, DataSourceException, Exception {
		//So they are alphabetical, so we always have a consistent upload order, to
		//facilitate tracing problems.
		SortedSet<String> names = new TreeSet<String>();
		for(FunctionBase base : FunctionList.getFunctionList(api.Platforms.INTERPRETER_JAVA)) {
			String name = base.getName();
			if(base.appearInDocumentation()) {
				names.add(name);
			}
		}
		for(String name : names) {
			String docs = DocGen.examples(name, isStaged);
			doUpload(docs, "/API/" + name, true);
		}
	}

Replace Generic With Diamond TreeSet<String> with TreeSet<> in method private doExamples() : void from class com.laytonsmith.tools.docgen.DocGenUIHandler


	private void doTemplates() throws IOException, XPathExpressionException {
		try {
			File root = new File(DocGenUIHandler.class.getResource("/docs").toURI());
			ZipReader reader = new ZipReader(root);
			Queue<File> q = new LinkedList<>();
			q.addAll(Arrays.asList(reader.listFiles()));
			while(q.peek() != null) {
				ZipReader r = new ZipReader(q.poll());
				if(r.isDirectory()) {
					q.addAll(Arrays.asList(r.listFiles()));
				} else {
					String articleName = "/" + r.getFile().getName();
					doUpload(DocGen.Template(r.getFile().getName(), isStaged), articleName, true);
				}
			}
		} catch(URISyntaxException ex) {
			Logger.getLogger(DocGenUIHandler.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	private void doTemplates() throws IOException, XPathExpressionException {
		try {
			File root = new File(DocGenUIHandler.class.getResource("/docs").toURI());
			ZipReader reader = new ZipReader(root);
			Queue<File> q = new LinkedList<File>();
			q.addAll(Arrays.asList(reader.listFiles()));
			while(q.peek() != null) {
				ZipReader r = new ZipReader(q.poll());
				if(r.isDirectory()) {
					q.addAll(Arrays.asList(r.listFiles()));
				} else {
					String articleName = "/" + r.getFile().getName();
					doUpload(DocGen.Template(r.getFile().getName(), isStaged), articleName, true);
				}
			}
		} catch(URISyntaxException ex) {
			Logger.getLogger(DocGenUIHandler.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

Replace Generic With Diamond LinkedList<File> with LinkedList<> in method private doTemplates() : void from class com.laytonsmith.tools.docgen.DocGenUIHandler


	private int getTemplateCount() throws IOException {
		try {
			int count = 0;
			ZipReader reader = new ZipReader(new File(DocGenUIHandler.class.getResource("/docs").toURI()));
			Queue<File> q = new LinkedList<>();
			q.addAll(Arrays.asList(reader.listFiles()));
			while(q.peek() != null) {
				ZipReader r = new ZipReader(q.poll());
				if(r.isDirectory()) {
					q.addAll(Arrays.asList(r.listFiles()));
				} else {
					count++;
				}
			}
			return count;
		} catch(URISyntaxException ex) {
			throw new APIException(ex);
		}
	}

	private int getTemplateCount() throws IOException {
		try {
			int count = 0;
			ZipReader reader = new ZipReader(new File(DocGenUIHandler.class.getResource("/docs").toURI()));
			Queue<File> q = new LinkedList<File>();
			q.addAll(Arrays.asList(reader.listFiles()));
			while(q.peek() != null) {
				ZipReader r = new ZipReader(q.poll());
				if(r.isDirectory()) {
					q.addAll(Arrays.asList(r.listFiles()));
				} else {
					count++;
				}
			}
			return count;
		} catch(URISyntaxException ex) {
			throw new APIException(ex);
		}
	}

Replace Generic With Diamond LinkedList<File> with LinkedList<> in method private getTemplateCount() : int from class com.laytonsmith.tools.docgen.DocGenUIHandler


	private static Map<String, String> mapCreator(String... strings) {
		if(strings.length % 2 != 0) {
			throw new Error("Only an even number of parameters may be passed to mapCreator");
		}
		Map<String, String> map = new HashMap<>();
		for(int i = 0; i < strings.length; i += 2) {
			map.put(strings[i], strings[i + 1]);
		}
		return map;
	}

	private static Map<String, String> mapCreator(String... strings) {
		if(strings.length % 2 != 0) {
			throw new Error("Only an even number of parameters may be passed to mapCreator");
		}
		Map<String, String> map = new HashMap<String, String>();
		for(int i = 0; i < strings.length; i += 2) {
			map.put(strings[i], strings[i + 1]);
		}
		return map;
	}

Replace Generic With Diamond HashMap<String,String> with HashMap<> in method private mapCreator(strings String...) : Map<String,String> from class com.laytonsmith.tools.docgen.DocGenUIHandler


	private static XMLDocument getXML(URL url, Map<String, String> params, boolean useURL) throws APIException {
		try {
			XMLDocument doc = new XMLDocument(getPage(url, params, useURL).getContent());
			if(doc.nodeExists("/api/error")) {
				//Doh.
				throw new APIException(doc.getNode("/api/error/@info"));
			}
			return doc;
		} catch(XPathExpressionException | SAXException | IOException e) {
			throw new APIException(e);
		}
	}

	private static XMLDocument getXML(URL url, Map<String, String> params, boolean useURL) throws APIException {
		try {
			XMLDocument doc = new XMLDocument(getPage(url, params, useURL).getContent());
			if(doc.nodeExists("/api/error")) {
				//Doh.
				throw new APIException(doc.getNode("/api/error/@info"));
			}
			return doc;
		} catch(XPathExpressionException e) {
			throw new APIException(e);
		} catch(SAXException e) {
			throw new APIException(e);
		} catch(IOException e) {
			throw new APIException(e);
		}
	}

Merge Catch [catch(XPathExpressionException e), catch(SAXException e), catch(IOException e)] to catch(XPathExpressionException|SAXException|IOException e) in method private getXML(url URL, params Map<String,String>, useURL boolean) : XMLDocument from class com.laytonsmith.tools.docgen.DocGenUIHandler


	/**
	 * The wiki apparently wants the parameters in the URL, but the method set to post. If useURL is true, it will merge
	 * the params into the url.
	 *
	 * @param url
	 * @param params
	 * @param useURL
	 * @return
	 * @throws IOException
	 */
	private static HTTPResponse getPage(URL url, Map<String, String> params, boolean useURL) throws IOException {
		Map<String, List<String>> headers = new HashMap<>(baseHeaders);
		if(params != null && !params.isEmpty() && useURL) {
			StringBuilder b = new StringBuilder(url.getQuery() == null ? "" : url.getQuery());
			if(b.length() != 0) {
				b.append("&");
			}
			RequestSettings temp = new RequestSettings().setParameters(params);
			b.append(WebUtility.encodeParameters(temp.getParameters()));
			String query = b.toString();
			url = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getPath() + "?" + query);
		}
		headers.put("Host", Arrays.asList(new String[]{url.getHost()}));
		RequestSettings settings = new RequestSettings().setMethod(HTTPMethod.POST).setHeaders(headers)
				.setParameters(params).setCookieJar(cookieStash).setFollowRedirects(true);
		return WebUtility.GetPage(url, settings);
	}

	/**
	 * The wiki apparently wants the parameters in the URL, but the method set to post. If useURL is true, it will merge
	 * the params into the url.
	 *
	 * @param url
	 * @param params
	 * @param useURL
	 * @return
	 * @throws IOException
	 */
	private static HTTPResponse getPage(URL url, Map<String, String> params, boolean useURL) throws IOException {
		Map<String, List<String>> headers = new HashMap<String, List<String>>(baseHeaders);
		if(params != null && !params.isEmpty() && useURL) {
			StringBuilder b = new StringBuilder(url.getQuery() == null ? "" : url.getQuery());
			if(b.length() != 0) {
				b.append("&");
			}
			RequestSettings temp = new RequestSettings().setParameters(params);
			b.append(WebUtility.encodeParameters(temp.getParameters()));
			String query = b.toString();
			url = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getPath() + "?" + query);
		}
		headers.put("Host", Arrays.asList(new String[]{url.getHost()}));
		RequestSettings settings = new RequestSettings().setMethod(HTTPMethod.POST).setHeaders(headers)
				.setParameters(params).setCookieJar(cookieStash).setFollowRedirects(true);
		return WebUtility.GetPage(url, settings);
	}

Replace Generic With Diamond HashMap<String,List<String>> with HashMap<> in method private getPage(url URL, params Map<String,String>, useURL boolean) : HTTPResponse from class com.laytonsmith.tools.docgen.DocGenUIHandler


	private static <T> T GetSetPrivate(Object in, String name, Object value, boolean isSet, Class<T> expected) {
		Object ret = null;
		try {
			Field f = null;
			Class search = in.getClass();
			if(in instanceof Class) {
				search = (Class) in;
			}
			while(search != null) {
				try {
					f = search.getDeclaredField(name);
					break;
				} catch(NoSuchFieldException e) {
					search = search.getSuperclass();
				}
			}
			if(f == null) {
				throw new NoSuchFieldException();
			}
			f.setAccessible(true);
			if(expected != null && !expected.isAssignableFrom(f.getType())) {
				fail("Expected the value to be a " + expected.getName() + ", but it was actually a " + f.getType().getName());
			}
			if(isSet) {
				f.set(in, value);
			} else {
				ret = f.get(in);
			}
		} catch(IllegalArgumentException | IllegalAccessException ex) {
			//This shouldn't happen ever, since we are using the class provided by in, and sending
			//get/set in as well.
			fail(ex.getMessage());
		}
		//This shouldn't happen ever, since we set it to accessible
		 catch(NoSuchFieldException ex) {
			fail("No such field \"" + name + "\" exists in the class " + in.getClass().getName());
		} catch(SecurityException ex) {
			fail("A security policy is preventing the test from getting \"" + name + "\" in the object provided.");
		}
		return (T) ret;
	}

	private static <T> T GetSetPrivate(Object in, String name, Object value, boolean isSet, Class<T> expected) {
		Object ret = null;
		try {
			Field f = null;
			Class search = in.getClass();
			if(in instanceof Class) {
				search = (Class) in;
			}
			while(search != null) {
				try {
					f = search.getDeclaredField(name);
					break;
				} catch(NoSuchFieldException e) {
					search = search.getSuperclass();
				}
			}
			if(f == null) {
				throw new NoSuchFieldException();
			}
			f.setAccessible(true);
			if(expected != null && !expected.isAssignableFrom(f.getType())) {
				fail("Expected the value to be a " + expected.getName() + ", but it was actually a " + f.getType().getName());
			}
			if(isSet) {
				f.set(in, value);
			} else {
				ret = f.get(in);
			}
		} catch(IllegalArgumentException ex) {
			//This shouldn't happen ever, since we are using the class provided by in, and sending
			//get/set in as well.
			fail(ex.getMessage());
		} catch(IllegalAccessException ex) {
			//This shouldn't happen ever, since we set it to accessible
			fail(ex.getMessage());
		} catch(NoSuchFieldException ex) {
			fail("No such field \"" + name + "\" exists in the class " + in.getClass().getName());
		} catch(SecurityException ex) {
			fail("A security policy is preventing the test from getting \"" + name + "\" in the object provided.");
		}
		return (T) ret;
	}

Merge Catch [catch(IllegalArgumentException ex), catch(IllegalAccessException ex)] to catch(IllegalArgumentException|IllegalAccessException ex) in method private GetSetPrivate(in Object, name String, value Object, isSet boolean, expected Class<T>) : T from class com.laytonsmith.testing.StaticTest


	private List<String> parseList(String list) {
		List<String> l = new ArrayList<>();
		for (String part : list.split(",")) {
			if (!part.trim().isEmpty()) {
				l.add(part.trim().toLowerCase());
			}
		}
		return l;
	}

    private List<String> parseList(String list) {
	List<String> l = new ArrayList<String>();
	for (String part : list.split(",")) {
	    if (!part.trim().isEmpty()) {
		l.add(part.trim().toLowerCase());
	    }
	}
	return l;
    }

Replace Generic With Diamond ArrayList<String> with ArrayList<> in method private parseList(list String) : List<String> from class com.laytonsmith.core.compiler.FileOptions