Remove dd_plist from third_party
diff --git a/third_party/BUILD b/third_party/BUILD
index 5bc45b7..0cdea9f 100644
--- a/third_party/BUILD
+++ b/third_party/BUILD
@@ -19,7 +19,6 @@
         "//third_party/java/android_databinding:srcs",
         "//third_party/java/aosp_gradle_core:srcs",
         "//third_party/java/apkbuilder:srcs",
-        "//third_party/java/dd_plist:srcs",
         "//third_party/java/j2objc:srcs",
         "//third_party/java/jacoco:srcs",
         "//third_party/java/javapoet:srcs",
diff --git a/third_party/java/dd_plist/BUILD b/third_party/java/dd_plist/BUILD
deleted file mode 100644
index 2a5c40e..0000000
--- a/third_party/java/dd_plist/BUILD
+++ /dev/null
@@ -1,16 +0,0 @@
-load("@rules_java//java:defs.bzl", "java_library")
-
-package(default_visibility = ["//visibility:public"])
-
-licenses(["notice"])  # MIT
-
-filegroup(
-    name = "srcs",
-    srcs = glob(["**"]),
-    visibility = ["//third_party:__pkg__"],
-)
-
-java_library(
-    name = "dd_plist",
-    srcs = glob(["java/**/*.java"]),
-)
diff --git a/third_party/java/dd_plist/LICENSE b/third_party/java/dd_plist/LICENSE
deleted file mode 100644
index d187b74..0000000
--- a/third_party/java/dd_plist/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (C) 2012 Daniel Dreibrodt
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/third_party/java/dd_plist/java/com/dd/plist/ASCIIPropertyListParser.java b/third_party/java/dd_plist/java/com/dd/plist/ASCIIPropertyListParser.java
deleted file mode 100644
index 533fb39..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/ASCIIPropertyListParser.java
+++ /dev/null
@@ -1,645 +0,0 @@
-/*
- * plist - An open source library to parse and generate property lists
- * Copyright (C) 2014 Daniel Dreibrodt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package com.dd.plist;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.CharBuffer;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetEncoder;
-import java.text.ParseException;
-import java.text.StringCharacterIterator;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Parser for ASCII property lists. Supports Apple OS X/iOS and GnuStep/NeXTSTEP format.
- * This parser is based on the recursive descent paradigm, but the underlying grammar
- * is not explicitely defined.
- * <p/>
- * Resources on ASCII property list format:
- * <ul>
- * <li><a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/PropertyLists/OldStylePlists/OldStylePLists.html>
- * Property List Programming Guide - Old-Style ASCII Property Lists
- * </a></li>
- * <li><a href="http://www.gnustep.org/resources/documentation/Developer/Base/Reference/NSPropertyList.html">
- * GnuStep - NSPropertyListSerialization class documentation
- * </a></li>
- * </ul>
- *
- * @author Daniel Dreibrodt
- */
-public class ASCIIPropertyListParser {
-
-    /**
-     * Parses an ASCII property list file.
-     *
-     * @param f The ASCII property list file.
-     * @return The root object of the property list. This is usally a NSDictionary but can also be a NSArray.
-     * @throws Exception When an error occurs during parsing.
-     */
-    public static NSObject parse(File f) throws IOException, ParseException {
-        return parse(new FileInputStream(f));
-    }
-
-    /**
-     * Parses an ASCII property list from an input stream.
-     *
-     * @param in The input stream that points to the property list's data.
-     * @return The root object of the property list. This is usally a NSDictionary but can also be a NSArray.
-     * @throws Exception When an error occurs during parsing.
-     */
-    public static NSObject parse(InputStream in) throws ParseException, IOException {
-        byte[] buf = PropertyListParser.readAll(in);
-        in.close();
-        return parse(buf);
-    }
-
-    /**
-     * Parses an ASCII property list from a byte array.
-     *
-     * @param bytes The ASCII property list data.
-     * @return The root object of the property list. This is usally a NSDictionary but can also be a NSArray.
-     * @throws Exception When an error occurs during parsing.
-     */
-    public static NSObject parse(byte[] bytes) throws ParseException {
-        ASCIIPropertyListParser parser = new ASCIIPropertyListParser(bytes);
-        return parser.parse();
-    }
-
-    public static final char WHITESPACE_SPACE = ' ';
-    public static final char WHITESPACE_TAB = '\t';
-    public static final char WHITESPACE_NEWLINE = '\n';
-    public static final char WHITESPACE_CARRIAGE_RETURN = '\r';
-
-    public static final char ARRAY_BEGIN_TOKEN = '(';
-    public static final char ARRAY_END_TOKEN = ')';
-    public static final char ARRAY_ITEM_DELIMITER_TOKEN = ',';
-
-    public static final char DICTIONARY_BEGIN_TOKEN = '{';
-    public static final char DICTIONARY_END_TOKEN = '}';
-    public static final char DICTIONARY_ASSIGN_TOKEN = '=';
-    public static final char DICTIONARY_ITEM_DELIMITER_TOKEN = ';';
-
-    public static final char QUOTEDSTRING_BEGIN_TOKEN = '"';
-    public static final char QUOTEDSTRING_END_TOKEN = '"';
-    public static final char QUOTEDSTRING_ESCAPE_TOKEN = '\\';
-
-    public static final char DATA_BEGIN_TOKEN = '<';
-    public static final char DATA_END_TOKEN = '>';
-
-    public static final char DATA_GSOBJECT_BEGIN_TOKEN = '*';
-    public static final char DATA_GSDATE_BEGIN_TOKEN = 'D';
-    public static final char DATA_GSBOOL_BEGIN_TOKEN = 'B';
-    public static final char DATA_GSBOOL_TRUE_TOKEN = 'Y';
-    public static final char DATA_GSBOOL_FALSE_TOKEN = 'N';
-    public static final char DATA_GSINT_BEGIN_TOKEN = 'I';
-    public static final char DATA_GSREAL_BEGIN_TOKEN = 'R';
-
-    public static final char DATE_DATE_FIELD_DELIMITER = '-';
-    public static final char DATE_TIME_FIELD_DELIMITER = ':';
-    public static final char DATE_GS_DATE_TIME_DELIMITER = ' ';
-    public static final char DATE_APPLE_DATE_TIME_DELIMITER = 'T';
-    public static final char DATE_APPLE_END_TOKEN = 'Z';
-
-    public static final char COMMENT_BEGIN_TOKEN = '/';
-    public static final char MULTILINE_COMMENT_SECOND_TOKEN = '*';
-    public static final char SINGLELINE_COMMENT_SECOND_TOKEN = '/';
-    public static final char MULTILINE_COMMENT_END_TOKEN = '/';
-
-    /**
-     * Property list source data
-     */
-    private byte[] data;
-    /**
-     * Current parsing index
-     */
-    private int index;
-
-    /**
-     * Only allow subclasses to change instantiation.
-     */
-    protected ASCIIPropertyListParser() {
-
-    }
-
-    /**
-     * Creates a new parser for the given property list content.
-     *
-     * @param propertyListContent The content of the property list that is to be parsed.
-     */
-    private ASCIIPropertyListParser(byte[] propertyListContent) {
-        data = propertyListContent;
-    }
-
-    /**
-     * Checks whether the given sequence of symbols can be accepted.
-     *
-     * @param sequence The sequence of tokens to look for.
-     * @return Whether the given tokens occur at the current parsing position.
-     */
-    private boolean acceptSequence(char... sequence) {
-        for (int i = 0; i < sequence.length; i++) {
-            if (data[index + i] != sequence[i])
-                return false;
-        }
-        return true;
-    }
-
-    /**
-     * Checks whether the given symbols can be accepted, that is, if one
-     * of the given symbols is found at the current parsing position.
-     *
-     * @param acceptableSymbols The symbols to check.
-     * @return Whether one of the symbols can be accepted or not.
-     */
-    private boolean accept(char... acceptableSymbols) {
-        boolean symbolPresent = false;
-        for (char c : acceptableSymbols) {
-            if (data[index] == c)
-                symbolPresent = true;
-        }
-        return symbolPresent;
-    }
-
-    /**
-     * Checks whether the given symbol can be accepted, that is, if
-     * the given symbols is found at the current parsing position.
-     *
-     * @param acceptableSymbol The symbol to check.
-     * @return Whether the symbol can be accepted or not.
-     */
-    private boolean accept(char acceptableSymbol) {
-        return data[index] == acceptableSymbol;
-    }
-
-    /**
-     * Expects the input to have one of the given symbols at the current parsing position.
-     *
-     * @param expectedSymbols The expected symbols.
-     * @throws ParseException If none of the expected symbols could be found.
-     */
-    private void expect(char... expectedSymbols) throws ParseException {
-        if (!accept(expectedSymbols)) {
-            String excString = "Expected '" + expectedSymbols[0] + "'";
-            for (int i = 1; i < expectedSymbols.length; i++) {
-                excString += " or '" + expectedSymbols[i] + "'";
-            }
-            excString += " but found '" + (char) data[index] + "'";
-            throw new ParseException(excString, index);
-        }
-    }
-
-    /**
-     * Expects the input to have the given symbol at the current parsing position.
-     *
-     * @param expectedSymbol The expected symbol.
-     * @throws ParseException If the expected symbol could be found.
-     */
-    private void expect(char expectedSymbol) throws ParseException {
-        if (!accept(expectedSymbol))
-            throw new ParseException("Expected '" + expectedSymbol + "' but found '" + (char) data[index] + "'", index);
-    }
-
-    /**
-     * Reads an expected symbol.
-     *
-     * @param symbol The symbol to read.
-     * @throws ParseException If the expected symbol could not be read.
-     */
-    private void read(char symbol) throws ParseException {
-        expect(symbol);
-        index++;
-    }
-
-    /**
-     * Skips the current symbol.
-     */
-    private void skip() {
-        index++;
-    }
-
-    /**
-     * Skips several symbols
-     *
-     * @param numSymbols The amount of symbols to skip.
-     */
-    private void skip(int numSymbols) {
-        index += numSymbols;
-    }
-
-    /**
-     * Skips all whitespaces and comments from the current parsing position onward.
-     */
-    private void skipWhitespacesAndComments() {
-        boolean commentSkipped;
-        do {
-            commentSkipped = false;
-
-            //Skip whitespaces
-            while (accept(WHITESPACE_CARRIAGE_RETURN, WHITESPACE_NEWLINE, WHITESPACE_SPACE, WHITESPACE_TAB)) {
-                skip();
-            }
-
-            //Skip single line comments "//..."
-            if (acceptSequence(COMMENT_BEGIN_TOKEN, SINGLELINE_COMMENT_SECOND_TOKEN)) {
-                skip(2);
-                readInputUntil(WHITESPACE_CARRIAGE_RETURN, WHITESPACE_NEWLINE);
-                commentSkipped = true;
-            }
-            //Skip multi line comments "/* ... */"
-            else if (acceptSequence(COMMENT_BEGIN_TOKEN, MULTILINE_COMMENT_SECOND_TOKEN)) {
-                skip(2);
-                while (true) {
-                    if (acceptSequence(MULTILINE_COMMENT_SECOND_TOKEN, MULTILINE_COMMENT_END_TOKEN)) {
-                        skip(2);
-                        break;
-                    }
-                    skip();
-                }
-                commentSkipped = true;
-            }
-        }
-        while (commentSkipped); //if a comment was skipped more whitespace or another comment can follow, so skip again
-    }
-
-    private String toUtf8String(ByteArrayOutputStream stream) {
-        try {
-            return stream.toString("UTF-8");
-        } catch (UnsupportedEncodingException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Reads input until one of the given symbols is found.
-     *
-     * @param symbols The symbols that can occur after the string to read.
-     * @return The input until one the given symbols.
-     */
-    private String readInputUntil(char... symbols) {
-        ByteArrayOutputStream stringBytes = new ByteArrayOutputStream();
-        while (!accept(symbols)) {
-            stringBytes.write(data[index]);
-            skip();
-        }
-        return toUtf8String(stringBytes);
-    }
-
-    /**
-     * Reads input until the given symbol is found.
-     *
-     * @param symbol The symbol that can occur after the string to read.
-     * @return The input until the given symbol.
-     */
-    private String readInputUntil(char symbol) {
-        ByteArrayOutputStream stringBytes = new ByteArrayOutputStream();
-        while (!accept(symbol)) {
-            stringBytes.write(data[index]);
-            skip();
-        }
-        return toUtf8String(stringBytes);
-    }
-
-    /**
-     * Parses the property list from the beginning and returns the root object
-     * of the property list.
-     *
-     * @return The root object of the property list. This can either be a NSDictionary or a NSArray.
-     * @throws ParseException When an error occured during parsing
-     */
-    public NSObject parse() throws ParseException {
-        index = 0;
-        skipWhitespacesAndComments();
-        expect(DICTIONARY_BEGIN_TOKEN, ARRAY_BEGIN_TOKEN, COMMENT_BEGIN_TOKEN);
-        try {
-            return parseObject();
-        } catch (ArrayIndexOutOfBoundsException ex) {
-            throw new ParseException("Reached end of input unexpectedly.", index);
-        }
-    }
-
-    /**
-     * Parses the NSObject found at the current position in the property list
-     * data stream.
-     *
-     * @return The parsed NSObject.
-     * @see ASCIIPropertyListParser#index
-     */
-    private NSObject parseObject() throws ParseException {
-        switch (data[index]) {
-            case ARRAY_BEGIN_TOKEN: {
-                return parseArray();
-            }
-            case DICTIONARY_BEGIN_TOKEN: {
-                return parseDictionary();
-            }
-            case DATA_BEGIN_TOKEN: {
-                return parseData();
-            }
-            case QUOTEDSTRING_BEGIN_TOKEN: {
-                String quotedString = parseQuotedString();
-                //apple dates are quoted strings of length 20 and after the 4 year digits a dash is found
-                if (quotedString.length() == 20 && quotedString.charAt(4) == DATE_DATE_FIELD_DELIMITER) {
-                    try {
-                        return new NSDate(quotedString);
-                    } catch (Exception ex) {
-                        //not a date? --> return string
-                        return new NSString(quotedString);
-                    }
-                } else {
-                    return new NSString(quotedString);
-                }
-            }
-            default: {
-                //0-9
-                if (data[index] > 0x2F && data[index] < 0x3A) {
-                    //could be a date or just a string
-                    return parseDateString();
-                } else {
-                    //non-numerical -> string or boolean
-                    String parsedString = parseString();
-                    return new NSString(parsedString);
-                }
-            }
-        }
-    }
-
-    /**
-     * Parses an array from the current parsing position.
-     * The prerequisite for calling this method is, that an array begin token has been read.
-     *
-     * @return The array found at the parsing position.
-     */
-    private NSArray parseArray() throws ParseException {
-        //Skip begin token
-        skip();
-        skipWhitespacesAndComments();
-        List<NSObject> objects = new LinkedList<NSObject>();
-        while (!accept(ARRAY_END_TOKEN)) {
-            objects.add(parseObject());
-            skipWhitespacesAndComments();
-            if (accept(ARRAY_ITEM_DELIMITER_TOKEN)) {
-                skip();
-            } else {
-                break; //must have reached end of array
-            }
-            skipWhitespacesAndComments();
-        }
-        //parse end token
-        read(ARRAY_END_TOKEN);
-        return new NSArray(objects.toArray(new NSObject[objects.size()]));
-    }
-
-    /**
-     * Parses a dictionary from the current parsing position.
-     * The prerequisite for calling this method is, that a dictionary begin token has been read.
-     *
-     * @return The dictionary found at the parsing position.
-     */
-    private NSDictionary parseDictionary() throws ParseException {
-        //Skip begin token
-        skip();
-        skipWhitespacesAndComments();
-        NSDictionary dict = new NSDictionary();
-        while (!accept(DICTIONARY_END_TOKEN)) {
-            //Parse key
-            String keyString;
-            if (accept(QUOTEDSTRING_BEGIN_TOKEN)) {
-                keyString = parseQuotedString();
-            } else {
-                keyString = parseString();
-            }
-            skipWhitespacesAndComments();
-
-            //Parse assign token
-            read(DICTIONARY_ASSIGN_TOKEN);
-            skipWhitespacesAndComments();
-
-            NSObject object = parseObject();
-            dict.put(keyString, object);
-            skipWhitespacesAndComments();
-            read(DICTIONARY_ITEM_DELIMITER_TOKEN);
-            skipWhitespacesAndComments();
-        }
-        //skip end token
-        skip();
-        return dict;
-    }
-
-    /**
-     * Parses a data object from the current parsing position.
-     * This can either be a NSData object or a GnuStep NSNumber or NSDate.
-     * The prerequisite for calling this method is, that a data begin token has been read.
-     *
-     * @return The data object found at the parsing position.
-     */
-    private NSObject parseData() throws ParseException {
-        NSObject obj = null;
-        //Skip begin token
-        skip();
-        if (accept(DATA_GSOBJECT_BEGIN_TOKEN)) {
-            skip();
-            expect(DATA_GSBOOL_BEGIN_TOKEN, DATA_GSDATE_BEGIN_TOKEN, DATA_GSINT_BEGIN_TOKEN, DATA_GSREAL_BEGIN_TOKEN);
-            if (accept(DATA_GSBOOL_BEGIN_TOKEN)) {
-                //Boolean
-                skip();
-                expect(DATA_GSBOOL_TRUE_TOKEN, DATA_GSBOOL_FALSE_TOKEN);
-                if (accept(DATA_GSBOOL_TRUE_TOKEN)) {
-                    obj = new NSNumber(true);
-                } else {
-                    obj = new NSNumber(false);
-                }
-                //Skip the parsed boolean token
-                skip();
-            } else if (accept(DATA_GSDATE_BEGIN_TOKEN)) {
-                //Date
-                skip();
-                String dateString = readInputUntil(DATA_END_TOKEN);
-                obj = new NSDate(dateString);
-            } else if (accept(DATA_GSINT_BEGIN_TOKEN, DATA_GSREAL_BEGIN_TOKEN)) {
-                //Number
-                skip();
-                String numberString = readInputUntil(DATA_END_TOKEN);
-                obj = new NSNumber(numberString);
-            }
-            //parse data end token
-            read(DATA_END_TOKEN);
-        } else {
-            String dataString = readInputUntil(DATA_END_TOKEN);
-            dataString = dataString.replaceAll("\\s+", "");
-
-            int numBytes = dataString.length() / 2;
-            byte[] bytes = new byte[numBytes];
-            for (int i = 0; i < bytes.length; i++) {
-                String byteString = dataString.substring(i * 2, i * 2 + 2);
-                int byteValue = Integer.parseInt(byteString, 16);
-                bytes[i] = (byte) byteValue;
-            }
-            obj = new NSData(bytes);
-
-            //skip end token
-            skip();
-        }
-
-        return obj;
-    }
-
-    /**
-     * Attempts to parse a plain string as a date if possible.
-     *
-     * @return A NSDate if the string represents such an object. Otherwise a NSString is returned.
-     */
-    private NSObject parseDateString() {
-        String numericalString = parseString();
-        if (numericalString.length() > 4 && numericalString.charAt(4) == DATE_DATE_FIELD_DELIMITER) {
-            try {
-                return new NSDate(numericalString);
-            } catch(Exception ex) {
-                //An exception occurs if the string is not a date but just a string
-            }
-        }
-        return new NSString(numericalString);
-    }
-
-    /**
-     * Parses a plain string from the current parsing position.
-     * The string is made up of all characters to the next whitespace, delimiter token or assignment token.
-     *
-     * @return The string found at the current parsing position.
-     */
-    private String parseString() {
-        return readInputUntil(WHITESPACE_SPACE, WHITESPACE_TAB, WHITESPACE_NEWLINE, WHITESPACE_CARRIAGE_RETURN,
-                ARRAY_ITEM_DELIMITER_TOKEN, DICTIONARY_ITEM_DELIMITER_TOKEN, DICTIONARY_ASSIGN_TOKEN, ARRAY_END_TOKEN);
-    }
-
-    /**
-     * Parses a quoted string from the current parsing position.
-     * The prerequisite for calling this method is, that a quoted string begin token has been read.
-     *
-     * @return The quoted string found at the parsing method with all special characters unescaped.
-     * @throws ParseException If an error occured during parsing.
-     */
-    private String parseQuotedString() throws ParseException {
-        //Skip begin token
-        skip();
-        ByteArrayOutputStream quotedString = new ByteArrayOutputStream();
-        boolean unescapedBackslash = true;
-        //Read from opening quotation marks to closing quotation marks and skip escaped quotation marks
-        while (data[index] != QUOTEDSTRING_END_TOKEN || (data[index - 1] == QUOTEDSTRING_ESCAPE_TOKEN && unescapedBackslash)) {
-            quotedString.write(data[index]);
-            if (accept(QUOTEDSTRING_ESCAPE_TOKEN)) {
-                unescapedBackslash = !(data[index - 1] == QUOTEDSTRING_ESCAPE_TOKEN && unescapedBackslash);
-            }
-            skip();
-        }
-        String unescapedString;
-        try {
-            unescapedString = parseQuotedString(toUtf8String(quotedString));
-        } catch (Exception ex) {
-            throw new ParseException("The quoted string could not be parsed.", index);
-        }
-        //skip end token
-        skip();
-        return unescapedString;
-    }
-
-    /**
-     * Used to encode the parsed strings
-     */
-    private static CharsetEncoder asciiEncoder;
-
-    /**
-     * Parses a string according to the format specified for ASCII property lists.
-     * Such strings can contain escape sequences which are unescaped in this method.
-     *
-     * @param s The escaped string according to the ASCII property list format, without leading and trailing quotation marks.
-     * @return The unescaped string in UTF-8 or ASCII format, depending on the contained characters.
-     * @throws Exception If the string could not be properly parsed.
-     */
-    public static synchronized String parseQuotedString(String s) throws UnsupportedEncodingException, CharacterCodingException {
-        StringBuilder parsed = new StringBuilder();
-        StringCharacterIterator iterator = new StringCharacterIterator(s);
-        char c = iterator.current();
-
-        while (iterator.getIndex() < iterator.getEndIndex()) {
-            switch (c) {
-                case '\\': { //An escaped sequence is following
-                    parsed.append(parseEscapedSequence(iterator));
-                    break;
-                }
-                default: {
-                    parsed.append(c);
-                    break;
-                }
-            }
-            c = iterator.next();
-        }
-        return parsed.toString();
-    }
-
-    /**
-     * Unescapes an escaped character sequence, e.g. \\u00FC.
-     *
-     * @param iterator The string character iterator pointing to the first character after the backslash
-     * @return The unescaped character
-     */
-    private static char parseEscapedSequence(StringCharacterIterator iterator) {
-        char c = iterator.next();
-        if (c == 'b') {
-            return '\b';
-        } else if (c == 'n') {
-            return '\n';
-        } else if (c == 'r') {
-            return '\r';
-        } else if (c == 't') {
-            return '\t';
-        } else if (c == 'U' || c == 'u') {
-            //4 digit hex Unicode value
-            String byte1 = "";
-            byte1 += iterator.next();
-            byte1 += iterator.next();
-            String byte2 = "";
-            byte2 += iterator.next();
-            byte2 += iterator.next();
-            return (char) ((Integer.parseInt(byte1, 16) << 8) + Integer.parseInt(byte2, 16));
-        } else if ((c >= '0') && (c <= '7')) {
-            //3 digit octal ASCII value
-            String num = "";
-            num += c;
-            num += iterator.next();
-            num += iterator.next();
-            return (char) Integer.parseInt(num, 8);
-        } else {
-            // Possibly something that needn't be escaped, but we should accept it
-            // it anyway for consistency with Apple tools.
-            return c;
-        }
-    }
-
-}
diff --git a/third_party/java/dd_plist/java/com/dd/plist/Base64.java b/third_party/java/dd_plist/java/com/dd/plist/Base64.java
deleted file mode 100644
index e6a7ae3..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/Base64.java
+++ /dev/null
@@ -1,2126 +0,0 @@
-/**
- * plist - An open source library to parse and generate property lists
- *
- * Copyright (C) 2012 Daniel Dreibrodt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package com.dd.plist;
-
-/**
- * <p>Encodes and decodes to and from Base64 notation.</p>
- * <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p>
- * 
- * <p>Example:</p>
- *
- * <code>String encoded = Base64.encode( myByteArray );</code>
- *
- * <code>byte[] myByteArray = Base64.decode( encoded );</code>
- * 
- * <p>The <tt>options</tt> parameter, which appears in a few places, is used to pass
- * several pieces of information to the encoder. In the "higher level" methods such as
- * encodeBytes( bytes, options ) the options parameter can be used to indicate such
- * things as first gzipping the bytes before encoding them, not inserting linefeeds,
- * and encoding using the URL-safe and Ordered dialects.</p>
- * 
- * <p>Note, according to <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>,
- * Section 2.1, implementations should not add line feeds unless explicitly told
- * to do so. I've got Base64 set to this behavior now, although earlier versions
- * broke lines by default.</p>
- * 
- * <p>The constants defined in Base64 can be OR-ed together to combine options, so you
- * might make a call like this:</p>
- * 
- * <code>String encoded = Base64.encodeBytes( mybytes, Base64.GZIP | Base64.DO_BREAK_LINES );</code>
- * <p>to compress the data before encoding it and then making the output have newline characters.</p>
- * <p>Also...</p>
- * <code>String encoded = Base64.encodeBytes( crazyString.getBytes() );</code>
- * 
- * 
- * 
- * <p>
- * Change Log:
- * </p>
- *
- * <ul>
- * <li>v2.3.7 - Fixed subtle bug when base 64 input stream contained the
- * value 01111111, which is an invalid base 64 character but should not
- * throw an ArrayIndexOutOfBoundsException either. Led to discovery of
- * mishandling (or potential for better handling) of other bad input
- * characters. You should now get an IOException if you try decoding
- * something that has bad characters in it.</li>
- * <li>v2.3.6 - Fixed bug when breaking lines and the final byte of the encoded
- * string ended in the last column; the buffer was not properly shrunk and
- * contained an extra (null) byte that made it into the string.</li>
- * <li>v2.3.5 - Fixed bug in {@link #encodeFromFile} where estimated buffer size
- * was wrong for files of size 31, 34, and 37 bytes.</li>
- * <li>v2.3.4 - Fixed bug when working with gzipped streams whereby flushing
- * the Base64.B64OutputStream closed the Base64 encoding (by padding with equals
- * signs) too soon. Also added an option to suppress the automatic decoding
- * of gzipped streams. Also added experimental support for specifying a
- * class loader when using the
- * {@link #decodeToObject(java.lang.String, int, java.lang.ClassLoader)}
- * method.</li>
- * <li>v2.3.3 - Changed default char encoding to US-ASCII which reduces the internal Java
- * footprint with its CharEncoders and so forth. Fixed some javadocs that were
- * inconsistent. Removed imports and specified things like java.io.IOException
- * explicitly inline.</li>
- * <li>v2.3.2 - Reduced memory footprint! Finally refined the "guessing" of how big the
- * final encoded data will be so that the code doesn't have to create two output
- * arrays: an oversized initial one and then a final, exact-sized one. Big win
- * when using the {@link #encodeBytesToBytes(byte[])} family of methods (and not
- * using the gzip options which uses a different mechanism with streams and stuff).</li>
- * <li>v2.3.1 - Added {@link #encodeBytesToBytes(byte[], int, int, int)} and some
- * similar helper methods to be more efficient with memory by not returning a
- * String but just a byte array.</li>
- * <li>v2.3 - <strong>This is not a drop-in replacement!</strong> This is two years of comments
- * and bug fixes queued up and finally executed. Thanks to everyone who sent
- * me stuff, and I'm sorry I wasn't able to distribute your fixes to everyone else.
- * Much bad coding was cleaned up including throwing exceptions where necessary
- * instead of returning null values or something similar. Here are some changes
- * that may affect you:
- * <ul>
- * <li><em>Does not break lines, by default.</em> This is to keep in compliance with
- * <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>.</li>
- * <li><em>Throws exceptions instead of returning null values.</em> Because some operations
- * (especially those that may permit the GZIP option) use IO streams, there
- * is a possiblity of an java.io.IOException being thrown. After some discussion and
- * thought, I've changed the behavior of the methods to throw java.io.IOExceptions
- * rather than return null if ever there's an error. I think this is more
- * appropriate, though it will require some changes to your code. Sorry,
- * it should have been done this way to begin with.</li>
- * <li><em>Removed all references to System.out, System.err, and the like.</em>
- * Shame on me. All I can say is sorry they were ever there.</li>
- * <li><em>Throws NullPointerExceptions and IllegalArgumentExceptions</em> as needed
- * such as when passed arrays are null or offsets are invalid.</li>
- * <li>Cleaned up as much javadoc as I could to avoid any javadoc warnings.
- * This was especially annoying before for people who were thorough in their
- * own projects and then had gobs of javadoc warnings on this file.</li>
- * </ul>
- * <li>v2.2.1 - Fixed bug using URL_SAFE and ORDERED encodings. Fixed bug
- * when using very small files (~&lt; 40 bytes).</li>
- * <li>v2.2 - Added some helper methods for encoding/decoding directly from
- * one file to the next. Also added a main() method to support command line
- * encoding/decoding from one file to the next. Also added these Base64 dialects:
- * <ol>
- * <li>The default is RFC3548 format.</li>
- * <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.URLSAFE_FORMAT) generates
- * URL and file name friendly format as described in Section 4 of RFC3548.
- * http://www.faqs.org/rfcs/rfc3548.html</li>
- * <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.ORDERED_FORMAT) generates
- * URL and file name friendly format that preserves lexical ordering as described
- * in http://www.faqs.org/qa/rfcc-1940.html</li>
- * </ol>
- * Special thanks to Jim Kellerman at <a href="http://www.powerset.com/">http://www.powerset.com/</a>
- * for contributing the new Base64 dialects.
- * </li>
- * 
- * <li>v2.1 - Cleaned up javadoc comments and unused variables and methods. Added
- * some convenience methods for reading and writing to and from files.</li>
- * <li>v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems
- * with other encodings (like EBCDIC).</li>
- * <li>v2.0.1 - Fixed an error when decoding a single byte, that is, when the
- * encoded data was a single byte.</li>
- * <li>v2.0 - I got rid of methods that used booleans to set options.
- * Now everything is more consolidated and cleaner. The code now detects
- * when data that's being decoded is gzip-compressed and will decompress it
- * automatically. Generally things are cleaner. You'll probably have to
- * change some method calls that you were making to support the new
- * options format (<tt>int</tt>s that you "OR" together).</li>
- * <li>v1.5.1 - Fixed bug when decompressing and decoding to a
- * byte[] using <tt>decode( String s, boolean gzipCompressed )</tt>.
- * Added the ability to "suspend" encoding in the Output Stream so
- * you can turn on and off the encoding if you need to embed base64
- * data in an otherwise "normal" stream (like an XML file).</li>
- * <li>v1.5 - Output stream pases on flush() command but doesn't do anything itself.
- * This helps when using GZIP streams.
- * Added the ability to GZip-compress objects before encoding them.</li>
- * <li>v1.4 - Added helper methods to read/write files.</li>
- * <li>v1.3.6 - Fixed B64OutputStream.flush() so that 'position' is reset.</li>
- * <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream
- * where last buffer being read, if not completely full, was not returned.</li>
- * <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.</li>
- * <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li>
- * </ul>
- *
- * <p>
- * I am placing this code in the Public Domain. Do with it as you will.
- * This software comes with no guarantees or warranties but with
- * plenty of well-wishing instead!
- * Please visit <a href="http://iharder.net/base64">http://iharder.net/base64</a>
- * periodically to check for updates or to contribute improvements.
- * </p>
- *
- * @author Robert Harder
- * @author rob@iharder.net
- * @version 2.3.7
- */
-public class Base64 {
-
-/* ********  P U B L I C   F I E L D S  ******** */
-
-
-    /**
-     * No options specified. Value is zero.
-     */
-    public final static int NO_OPTIONS = 0;
-
-    /**
-     * Specify encoding in first bit. Value is one.
-     */
-    public final static int ENCODE = 1;
-
-
-    /**
-     * Specify decoding in first bit. Value is zero.
-     */
-    public final static int DECODE = 0;
-
-
-    /**
-     * Specify that data should be gzip-compressed in second bit. Value is two.
-     */
-    public final static int GZIP = 2;
-
-    /**
-     * Specify that gzipped data should <em>not</em> be automatically gunzipped.
-     */
-    public final static int DONT_GUNZIP = 4;
-
-
-    /**
-     * Do break lines when encoding. Value is 8.
-     */
-    public final static int DO_BREAK_LINES = 8;
-
-    /**
-     * Encode using Base64-like encoding that is URL- and Filename-safe as described
-     * in Section 4 of RFC3548:
-     * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
-     * It is important to note that data encoded this way is <em>not</em> officially valid Base64,
-     * or at the very least should not be called Base64 without also specifying that is
-     * was encoded using the URL- and Filename-safe dialect.
-     */
-    public final static int URL_SAFE = 16;
-
-
-    /**
-     * Encode using the special "ordered" dialect of Base64 described here:
-     * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
-     */
-    public final static int ORDERED = 32;
-
-
-/* ********  P R I V A T E   F I E L D S  ******** */
-
-
-    /**
-     * Maximum line length (76) of Base64 output.
-     */
-    private final static int MAX_LINE_LENGTH = 76;
-
-
-    /**
-     * The equals sign (=) as a byte.
-     */
-    private final static byte EQUALS_SIGN = (byte) '=';
-
-
-    /**
-     * The new line character (\n) as a byte.
-     */
-    private final static byte NEW_LINE = (byte) '\n';
-
-
-    /**
-     * Preferred encoding.
-     */
-    private final static String PREFERRED_ENCODING = "US-ASCII";
-
-
-    private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
-    private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
-
-
-/* ********  S T A N D A R D   B A S E 6 4   A L P H A B E T  ******** */
-
-    /**
-     * The 64 valid Base64 values.
-     */
-    /* Host platform me be something funny like EBCDIC, so we hardcode these values. */
-    private final static byte[] _STANDARD_ALPHABET = {
-            (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G',
-            (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
-            (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
-            (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z',
-            (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g',
-            (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n',
-            (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
-            (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z',
-            (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5',
-            (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '+', (byte) '/'
-    };
-
-
-    /**
-     * Translates a Base64 value to either its 6-bit reconstruction value
-     * or a negative number indicating some other meaning.
-     */
-    private final static byte[] _STANDARD_DECODABET = {
-            -9, -9, -9, -9, -9, -9, -9, -9, -9,                 // Decimal  0 -  8
-            -5, -5,                                      // Whitespace: Tab and Linefeed
-            -9, -9,                                      // Decimal 11 - 12
-            -5,                                         // Whitespace: Carriage Return
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 14 - 26
-            -9, -9, -9, -9, -9,                             // Decimal 27 - 31
-            -5,                                         // Whitespace: Space
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,              // Decimal 33 - 42
-            62,                                         // Plus sign at decimal 43
-            -9, -9, -9,                                   // Decimal 44 - 46
-            63,                                         // Slash at decimal 47
-            52, 53, 54, 55, 56, 57, 58, 59, 60, 61,              // Numbers zero through nine
-            -9, -9, -9,                                   // Decimal 58 - 60
-            -1,                                         // Equals sign at decimal 61
-            -9, -9, -9,                                      // Decimal 62 - 64
-            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,            // Letters 'A' through 'N'
-            14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,        // Letters 'O' through 'Z'
-            -9, -9, -9, -9, -9, -9,                          // Decimal 91 - 96
-            26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,     // Letters 'a' through 'm'
-            39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,     // Letters 'n' through 'z'
-            -9, -9, -9, -9, -9                              // Decimal 123 - 127
-            , -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,       // Decimal 128 - 139
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 140 - 152
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 153 - 165
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 166 - 178
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 179 - 191
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 192 - 204
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 205 - 217
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 218 - 230
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 231 - 243
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9         // Decimal 244 - 255
-    };
-
-
-/* ********  U R L   S A F E   B A S E 6 4   A L P H A B E T  ******** */
-
-    /**
-     * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548:
-     * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
-     * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash."
-     */
-    private final static byte[] _URL_SAFE_ALPHABET = {
-            (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G',
-            (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
-            (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
-            (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z',
-            (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g',
-            (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n',
-            (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
-            (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z',
-            (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5',
-            (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '-', (byte) '_'
-    };
-
-    /**
-     * Used in decoding URL- and Filename-safe dialects of Base64.
-     */
-    private final static byte[] _URL_SAFE_DECODABET = {
-            -9, -9, -9, -9, -9, -9, -9, -9, -9,                 // Decimal  0 -  8
-            -5, -5,                                      // Whitespace: Tab and Linefeed
-            -9, -9,                                      // Decimal 11 - 12
-            -5,                                         // Whitespace: Carriage Return
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 14 - 26
-            -9, -9, -9, -9, -9,                             // Decimal 27 - 31
-            -5,                                         // Whitespace: Space
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,              // Decimal 33 - 42
-            -9,                                         // Plus sign at decimal 43
-            -9,                                         // Decimal 44
-            62,                                         // Minus sign at decimal 45
-            -9,                                         // Decimal 46
-            -9,                                         // Slash at decimal 47
-            52, 53, 54, 55, 56, 57, 58, 59, 60, 61,              // Numbers zero through nine
-            -9, -9, -9,                                   // Decimal 58 - 60
-            -1,                                         // Equals sign at decimal 61
-            -9, -9, -9,                                   // Decimal 62 - 64
-            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,            // Letters 'A' through 'N'
-            14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,        // Letters 'O' through 'Z'
-            -9, -9, -9, -9,                                // Decimal 91 - 94
-            63,                                         // Underscore at decimal 95
-            -9,                                         // Decimal 96
-            26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,     // Letters 'a' through 'm'
-            39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,     // Letters 'n' through 'z'
-            -9, -9, -9, -9, -9                              // Decimal 123 - 127
-            , -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 128 - 139
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 140 - 152
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 153 - 165
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 166 - 178
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 179 - 191
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 192 - 204
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 205 - 217
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 218 - 230
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 231 - 243
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9         // Decimal 244 - 255
-    };
-
-
-
-/* ********  O R D E R E D   B A S E 6 4   A L P H A B E T  ******** */
-
-    /**
-     * I don't get the point of this technique, but someone requested it,
-     * and it is described here:
-     * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
-     */
-    private final static byte[] _ORDERED_ALPHABET = {
-            (byte) '-',
-            (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4',
-            (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9',
-            (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G',
-            (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
-            (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
-            (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z',
-            (byte) '_',
-            (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g',
-            (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n',
-            (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
-            (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z'
-    };
-
-    /**
-     * Used in decoding the "ordered" dialect of Base64.
-     */
-    private final static byte[] _ORDERED_DECODABET = {
-            -9, -9, -9, -9, -9, -9, -9, -9, -9,                 // Decimal  0 -  8
-            -5, -5,                                      // Whitespace: Tab and Linefeed
-            -9, -9,                                      // Decimal 11 - 12
-            -5,                                         // Whitespace: Carriage Return
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 14 - 26
-            -9, -9, -9, -9, -9,                             // Decimal 27 - 31
-            -5,                                         // Whitespace: Space
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,              // Decimal 33 - 42
-            -9,                                         // Plus sign at decimal 43
-            -9,                                         // Decimal 44
-            0,                                          // Minus sign at decimal 45
-            -9,                                         // Decimal 46
-            -9,                                         // Slash at decimal 47
-            1, 2, 3, 4, 5, 6, 7, 8, 9, 10,                       // Numbers zero through nine
-            -9, -9, -9,                                   // Decimal 58 - 60
-            -1,                                         // Equals sign at decimal 61
-            -9, -9, -9,                                   // Decimal 62 - 64
-            11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,     // Letters 'A' through 'M'
-            24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,     // Letters 'N' through 'Z'
-            -9, -9, -9, -9,                                // Decimal 91 - 94
-            37,                                         // Underscore at decimal 95
-            -9,                                         // Decimal 96
-            38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,     // Letters 'a' through 'm'
-            51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,     // Letters 'n' through 'z'
-            -9, -9, -9, -9, -9                                 // Decimal 123 - 127
-            , -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 128 - 139
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 140 - 152
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 153 - 165
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 166 - 178
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 179 - 191
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 192 - 204
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 205 - 217
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 218 - 230
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,     // Decimal 231 - 243
-            -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9         // Decimal 244 - 255
-    };
-
-
-/* ********  D E T E R M I N E   W H I C H   A L H A B E T  ******** */
-
-
-    /**
-     * Returns one of the _SOMETHING_ALPHABET byte arrays depending on
-     * the options specified.
-     * It's possible, though silly, to specify ORDERED <b>and</b> URLSAFE
-     * in which case one of them will be picked, though there is
-     * no guarantee as to which one will be picked.
-     */
-    private static byte[] getAlphabet(int options) {
-        if ((options & URL_SAFE) == URL_SAFE) {
-            return _URL_SAFE_ALPHABET;
-        } else if ((options & ORDERED) == ORDERED) {
-            return _ORDERED_ALPHABET;
-        } else {
-            return _STANDARD_ALPHABET;
-        }
-    }    // end getAlphabet
-
-
-    /**
-     * Returns one of the _SOMETHING_DECODABET byte arrays depending on
-     * the options specified.
-     * It's possible, though silly, to specify ORDERED and URL_SAFE
-     * in which case one of them will be picked, though there is
-     * no guarantee as to which one will be picked.
-     */
-    private static byte[] getDecodabet(int options) {
-        if ((options & URL_SAFE) == URL_SAFE) {
-            return _URL_SAFE_DECODABET;
-        } else if ((options & ORDERED) == ORDERED) {
-            return _ORDERED_DECODABET;
-        } else {
-            return _STANDARD_DECODABET;
-        }
-    }    // end getAlphabet
-
-
-    /**
-     * Defeats instantiation.
-     */
-    private Base64() {
-    }
-
-
-
-
-/* ********  E N C O D I N G   M E T H O D S  ******** */
-
-
-    /**
-     * Encodes up to the first three bytes of array <var>threeBytes</var>
-     * and returns a four-byte array in Base64 notation.
-     * The actual number of significant bytes in your array is
-     * given by <var>numSigBytes</var>.
-     * The array <var>threeBytes</var> needs only be as big as
-     * <var>numSigBytes</var>.
-     * Code can reuse a byte array by passing a four-byte array as <var>b4</var>.
-     *
-     * @param b4          A reusable byte array to reduce array instantiation
-     * @param threeBytes  the array to convert
-     * @param numSigBytes the number of significant bytes in your array
-     * @return four byte array in Base64 notation.
-     * @since 1.5.1
-     */
-    private static byte[] encode3to4(byte[] b4, byte[] threeBytes, int numSigBytes, int options) {
-        encode3to4(threeBytes, 0, numSigBytes, b4, 0, options);
-        return b4;
-    }   // end encode3to4
-
-
-    /**
-     * <p>Encodes up to three bytes of the array <var>source</var>
-     * and writes the resulting four Base64 bytes to <var>destination</var>.
-     * The source and destination arrays can be manipulated
-     * anywhere along their length by specifying
-     * <var>srcOffset</var> and <var>destOffset</var>.
-     * This method does not check to make sure your arrays
-     * are large enough to accomodate <var>srcOffset</var> + 3 for
-     * the <var>source</var> array or <var>destOffset</var> + 4 for
-     * the <var>destination</var> array.
-     * The actual number of significant bytes in your array is
-     * given by <var>numSigBytes</var>.</p>
-     * <p>This is the lowest level of the encoding methods with
-     * all possible parameters.</p>
-     *
-     * @param source      the array to convert
-     * @param srcOffset   the index where conversion begins
-     * @param numSigBytes the number of significant bytes in your array
-     * @param destination the array to hold the conversion
-     * @param destOffset  the index where output will be put
-     * @return the <var>destination</var> array
-     * @since 1.3
-     */
-    private static byte[] encode3to4(
-            byte[] source, int srcOffset, int numSigBytes,
-            byte[] destination, int destOffset, int options) {
-
-        byte[] ALPHABET = getAlphabet(options);
-
-        //           1         2         3
-        // 01234567890123456789012345678901 Bit position
-        // --------000000001111111122222222 Array position from threeBytes
-        // --------|    ||    ||    ||    | Six bit groups to index ALPHABET
-        //          >>18  >>12  >> 6  >> 0  Right shift necessary
-        //                0x3f  0x3f  0x3f  Additional AND
-
-        // Create buffer with zero-padding if there are only one or two
-        // significant bytes passed in the array.
-        // We have to shift left 24 in order to flush out the 1's that appear
-        // when Java treats a value as negative that is cast from a byte to an int.
-        int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0)
-                | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0)
-                | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0);
-
-        switch (numSigBytes) {
-            case 3:
-                destination[destOffset] = ALPHABET[(inBuff >>> 18)];
-                destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
-                destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
-                destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f];
-                return destination;
-
-            case 2:
-                destination[destOffset] = ALPHABET[(inBuff >>> 18)];
-                destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
-                destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
-                destination[destOffset + 3] = EQUALS_SIGN;
-                return destination;
-
-            case 1:
-                destination[destOffset] = ALPHABET[(inBuff >>> 18)];
-                destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
-                destination[destOffset + 2] = EQUALS_SIGN;
-                destination[destOffset + 3] = EQUALS_SIGN;
-                return destination;
-
-            default:
-                return destination;
-        }   // end switch
-    }   // end encode3to4
-
-
-    /**
-     * Performs Base64 encoding on the <code>raw</code> ByteBuffer,
-     * writing it to the <code>encoded</code> ByteBuffer.
-     * This is an experimental feature. Currently it does not
-     * pass along any options (such as {@link #DO_BREAK_LINES}
-     * or {@link #GZIP}.
-     *
-     * @param raw     input buffer
-     * @param encoded output buffer
-     * @since 2.3
-     */
-    public static void encode(java.nio.ByteBuffer raw, java.nio.ByteBuffer encoded) {
-        byte[] raw3 = new byte[3];
-        byte[] enc4 = new byte[4];
-
-        while (raw.hasRemaining()) {
-            int rem = Math.min(3, raw.remaining());
-            raw.get(raw3, 0, rem);
-            Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS);
-            encoded.put(enc4);
-        }   // end input remaining
-    }
-
-
-    /**
-     * Performs Base64 encoding on the <code>raw</code> ByteBuffer,
-     * writing it to the <code>encoded</code> CharBuffer.
-     * This is an experimental feature. Currently it does not
-     * pass along any options (such as {@link #DO_BREAK_LINES}
-     * or {@link #GZIP}.
-     *
-     * @param raw     input buffer
-     * @param encoded output buffer
-     * @since 2.3
-     */
-    public static void encode(java.nio.ByteBuffer raw, java.nio.CharBuffer encoded) {
-        byte[] raw3 = new byte[3];
-        byte[] enc4 = new byte[4];
-
-        while (raw.hasRemaining()) {
-            int rem = Math.min(3, raw.remaining());
-            raw.get(raw3, 0, rem);
-            Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS);
-            for (int i = 0; i < 4; i++) {
-                encoded.put((char) (enc4[i] & 0xFF));
-            }
-        }   // end input remaining
-    }
-
-
-    /**
-     * Serializes an object and returns the Base64-encoded
-     * version of that serialized object.
-     * 
-     * <p>As of v 2.3, if the object
-     * cannot be serialized or there is another error,
-     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
-     * In earlier versions, it just returned a null value, but
-     * in retrospect that's a pretty poor way to handle it.</p>
-     * 
-     * The object is not GZip-compressed before being encoded.
-     *
-     * @param serializableObject The object to encode
-     * @return The Base64-encoded object
-     * @throws java.io.IOException  if there is an error
-     * @throws NullPointerException if serializedObject is null
-     * @since 1.4
-     */
-    public static String encodeObject(java.io.Serializable serializableObject)
-            throws java.io.IOException {
-        return encodeObject(serializableObject, NO_OPTIONS);
-    }   // end encodeObject
-
-
-    /**
-     * Serializes an object and returns the Base64-encoded
-     * version of that serialized object.
-     * 
-     * <p>As of v 2.3, if the object
-     * cannot be serialized or there is another error,
-     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
-     * In earlier versions, it just returned a null value, but
-     * in retrospect that's a pretty poor way to handle it.</p>
-     * 
-     * The object is not GZip-compressed before being encoded.
-     * 
-     * Example options:<pre>
-     *   GZIP: gzip-compresses object before encoding it.
-     *   DO_BREAK_LINES: break lines at 76 characters
-     * </pre>
-     * 
-     * Example: <code>encodeObject( myObj, Base64.GZIP )</code> or
-     * 
-     * Example: <code>encodeObject( myObj, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
-     *
-     * @param serializableObject The object to encode
-     * @param options            Specified options
-     * @return The Base64-encoded object
-     * @throws java.io.IOException if there is an error
-     * @see Base64#GZIP
-     * @see Base64#DO_BREAK_LINES
-     * @since 2.0
-     */
-    public static String encodeObject(java.io.Serializable serializableObject, int options)
-            throws java.io.IOException {
-
-        if (serializableObject == null) {
-            throw new NullPointerException("Cannot serialize a null object.");
-        }   // end if: null
-
-        // Streams
-        java.io.ByteArrayOutputStream baos = null;
-        java.io.OutputStream b64os = null;
-        java.util.zip.GZIPOutputStream gzos = null;
-        java.io.ObjectOutputStream oos = null;
-
-
-        try {
-            // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
-            baos = new java.io.ByteArrayOutputStream();
-            b64os = new B64OutputStream(baos, ENCODE | options);
-            if ((options & GZIP) != 0) {
-                // Gzip
-                gzos = new java.util.zip.GZIPOutputStream(b64os);
-                oos = new java.io.ObjectOutputStream(gzos);
-            } else {
-                // Not gzipped
-                oos = new java.io.ObjectOutputStream(b64os);
-            }
-            oos.writeObject(serializableObject);
-        }   // end try
-        catch (java.io.IOException e) {
-            // Catch it and then throw it immediately so that
-            // the finally{} block is called for cleanup.
-            throw e;
-        }   // end catch
-        finally {
-            try {
-                oos.close();
-            } catch (Exception e) {
-            }
-            try {
-                gzos.close();
-            } catch (Exception e) {
-            }
-            try {
-                b64os.close();
-            } catch (Exception e) {
-            }
-            try {
-                baos.close();
-            } catch (Exception e) {
-            }
-        }   // end finally
-
-        // Return value according to relevant encoding.
-        try {
-            return new String(baos.toByteArray(), PREFERRED_ENCODING);
-        }   // end try
-        catch (java.io.UnsupportedEncodingException uue) {
-            // Fall back to some Java default
-            return new String(baos.toByteArray());
-        }   // end catch
-
-    }   // end encode
-
-
-    /**
-     * Encodes a byte array into Base64 notation.
-     * Does not GZip-compress data.
-     *
-     * @param source The data to convert
-     * @return The data in Base64-encoded form
-     * @throws NullPointerException if source array is null
-     * @since 1.4
-     */
-    public static String encodeBytes(byte[] source) {
-        // Since we're not going to have the GZIP encoding turned on,
-        // we're not going to have an java.io.IOException thrown, so
-        // we should not force the user to have to catch it.
-        String encoded = null;
-        try {
-            encoded = encodeBytes(source, 0, source.length, NO_OPTIONS);
-        } catch (java.io.IOException ex) {
-            assert false : ex.getMessage();
-        }   // end catch
-        assert encoded != null;
-        return encoded;
-    }   // end encodeBytes
-
-
-    /**
-     * Encodes a byte array into Base64 notation.
-     * <p>
-     * Example options:<pre>
-     *   GZIP: gzip-compresses object before encoding it.
-     *   DO_BREAK_LINES: break lines at 76 characters
-     *     <i>Note: Technically, this makes your encoding non-compliant.</i>
-     * </pre>
-     * <p>
-     * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
-     * <p>
-     * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
-     * 
-     * 
-     * <p>As of v 2.3, if there is an error with the GZIP stream,
-     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
-     * In earlier versions, it just returned a null value, but
-     * in retrospect that's a pretty poor way to handle it.</p>
-     *
-     * @param source  The data to convert
-     * @param options Specified options
-     * @return The Base64-encoded data as a String
-     * @throws java.io.IOException  if there is an error
-     * @throws NullPointerException if source array is null
-     * @see Base64#GZIP
-     * @see Base64#DO_BREAK_LINES
-     * @since 2.0
-     */
-    public static String encodeBytes(byte[] source, int options) throws java.io.IOException {
-        return encodeBytes(source, 0, source.length, options);
-    }   // end encodeBytes
-
-
-    /**
-     * Encodes a byte array into Base64 notation.
-     * Does not GZip-compress data.
-     * 
-     * <p>As of v 2.3, if there is an error,
-     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
-     * In earlier versions, it just returned a null value, but
-     * in retrospect that's a pretty poor way to handle it.</p>
-     *
-     * @param source The data to convert
-     * @param off    Offset in array where conversion should begin
-     * @param len    Length of data to convert
-     * @return The Base64-encoded data as a String
-     * @throws NullPointerException     if source array is null
-     * @throws IllegalArgumentException if source array, offset, or length are invalid
-     * @since 1.4
-     */
-    public static String encodeBytes(byte[] source, int off, int len) {
-        // Since we're not going to have the GZIP encoding turned on,
-        // we're not going to have an java.io.IOException thrown, so
-        // we should not force the user to have to catch it.
-        String encoded = null;
-        try {
-            encoded = encodeBytes(source, off, len, NO_OPTIONS);
-        } catch (java.io.IOException ex) {
-            assert false : ex.getMessage();
-        }   // end catch
-        assert encoded != null;
-        return encoded;
-    }   // end encodeBytes
-
-
-    /**
-     * Encodes a byte array into Base64 notation.
-     * <p>
-     * Example options:<pre>
-     *   GZIP: gzip-compresses object before encoding it.
-     *   DO_BREAK_LINES: break lines at 76 characters
-     *     <i>Note: Technically, this makes your encoding non-compliant.</i>
-     * </pre>
-     * <p>
-     * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
-     * <p>
-     * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
-     * 
-     * 
-     * <p>As of v 2.3, if there is an error with the GZIP stream,
-     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
-     * In earlier versions, it just returned a null value, but
-     * in retrospect that's a pretty poor way to handle it.</p>
-     *
-     * @param source  The data to convert
-     * @param off     Offset in array where conversion should begin
-     * @param len     Length of data to convert
-     * @param options Specified options
-     * @return The Base64-encoded data as a String
-     * @throws java.io.IOException      if there is an error
-     * @throws NullPointerException     if source array is null
-     * @throws IllegalArgumentException if source array, offset, or length are invalid
-     * @see Base64#GZIP
-     * @see Base64#DO_BREAK_LINES
-     * @since 2.0
-     */
-    public static String encodeBytes(byte[] source, int off, int len, int options) throws java.io.IOException {
-        byte[] encoded = encodeBytesToBytes(source, off, len, options);
-
-        // Return value according to relevant encoding.
-        try {
-            return new String(encoded, PREFERRED_ENCODING);
-        }   // end try
-        catch (java.io.UnsupportedEncodingException uue) {
-            return new String(encoded);
-        }   // end catch
-
-    }   // end encodeBytes
-
-
-    /**
-     * Similar to {@link #encodeBytes(byte[])} but returns
-     * a byte array instead of instantiating a String. This is more efficient
-     * if you're working with I/O streams and have large data sets to encode.
-     *
-     * @param source The data to convert
-     * @return The Base64-encoded data as a byte[] (of ASCII characters)
-     * @throws NullPointerException if source array is null
-     * @since 2.3.1
-     */
-    public static byte[] encodeBytesToBytes(byte[] source) {
-        byte[] encoded = null;
-        try {
-            encoded = encodeBytesToBytes(source, 0, source.length, Base64.NO_OPTIONS);
-        } catch (java.io.IOException ex) {
-            assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage();
-        }
-        return encoded;
-    }
-
-
-    /**
-     * Similar to {@link #encodeBytes(byte[], int, int, int)} but returns
-     * a byte array instead of instantiating a String. This is more efficient
-     * if you're working with I/O streams and have large data sets to encode.
-     *
-     * @param source  The data to convert
-     * @param off     Offset in array where conversion should begin
-     * @param len     Length of data to convert
-     * @param options Specified options
-     * @return The Base64-encoded data as a String
-     * @throws java.io.IOException      if there is an error
-     * @throws NullPointerException     if source array is null
-     * @throws IllegalArgumentException if source array, offset, or length are invalid
-     * @see Base64#GZIP
-     * @see Base64#DO_BREAK_LINES
-     * @since 2.3.1
-     */
-    public static byte[] encodeBytesToBytes(byte[] source, int off, int len, int options) throws java.io.IOException {
-
-        if (source == null) {
-            throw new NullPointerException("Cannot serialize a null array.");
-        }   // end if: null
-
-        if (off < 0) {
-            throw new IllegalArgumentException("Cannot have negative offset: " + off);
-        }   // end if: off < 0
-
-        if (len < 0) {
-            throw new IllegalArgumentException("Cannot have length offset: " + len);
-        }   // end if: len < 0
-
-        if (off + len > source.length) {
-            throw new IllegalArgumentException(
-                    String.format("Cannot have offset of %d and length of %d with array of length %d", off, len, source.length));
-        }   // end if: off < 0
-
-
-        // Compress?
-        if ((options & GZIP) != 0) {
-            java.io.ByteArrayOutputStream baos = null;
-            java.util.zip.GZIPOutputStream gzos = null;
-            B64OutputStream b64os = null;
-
-            try {
-                // GZip -> Base64 -> ByteArray
-                baos = new java.io.ByteArrayOutputStream();
-                b64os = new B64OutputStream(baos, ENCODE | options);
-                gzos = new java.util.zip.GZIPOutputStream(b64os);
-
-                gzos.write(source, off, len);
-                gzos.close();
-            }   // end try
-            catch (java.io.IOException e) {
-                // Catch it and then throw it immediately so that
-                // the finally{} block is called for cleanup.
-                throw e;
-            }   // end catch
-            finally {
-                try {
-                    gzos.close();
-                } catch (Exception e) {
-                }
-                try {
-                    b64os.close();
-                } catch (Exception e) {
-                }
-                try {
-                    baos.close();
-                } catch (Exception e) {
-                }
-            }   // end finally
-
-            return baos.toByteArray();
-        }   // end if: compress
-
-        // Else, don't compress. Better not to use streams at all then.
-        else {
-            boolean breakLines = (options & DO_BREAK_LINES) != 0;
-
-            //int    len43   = len * 4 / 3;
-            //byte[] outBuff = new byte[   ( len43 )                      // Main 4:3
-            //                           + ( (len % 3) > 0 ? 4 : 0 )      // Account for padding
-            //                           + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
-            // Try to determine more precisely how big the array needs to be.
-            // If we get it right, we don't have to do an array copy, and
-            // we save a bunch of memory.
-            int encLen = (len / 3) * 4 + (len % 3 > 0 ? 4 : 0); // Bytes needed for actual encoding
-            if (breakLines) {
-                encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline characters
-            }
-            byte[] outBuff = new byte[encLen];
-
-
-            int d = 0;
-            int e = 0;
-            int len2 = len - 2;
-            int lineLength = 0;
-            for (; d < len2; d += 3, e += 4) {
-                encode3to4(source, d + off, 3, outBuff, e, options);
-
-                lineLength += 4;
-                if (breakLines && lineLength >= MAX_LINE_LENGTH) {
-                    outBuff[e + 4] = NEW_LINE;
-                    e++;
-                    lineLength = 0;
-                }   // end if: end of line
-            }   // en dfor: each piece of array
-
-            if (d < len) {
-                encode3to4(source, d + off, len - d, outBuff, e, options);
-                e += 4;
-            }   // end if: some padding needed
-
-
-            // Only resize array if we didn't guess it right.
-            if (e <= outBuff.length - 1) {
-                // If breaking lines and the last byte falls right at
-                // the line length (76 bytes per line), there will be
-                // one extra byte, and the array will need to be resized.
-                // Not too bad of an estimate on array size, I'd say.
-                byte[] finalOut = new byte[e];
-                System.arraycopy(outBuff, 0, finalOut, 0, e);
-                //System.err.println("Having to resize array from " + outBuff.length + " to " + e );
-                return finalOut;
-            } else {
-                //System.err.println("No need to resize array.");
-                return outBuff;
-            }
-
-        }   // end else: don't compress
-
-    }   // end encodeBytesToBytes
-
-
-
-
-
-/* ********  D E C O D I N G   M E T H O D S  ******** */
-
-
-    /**
-     * Decodes four bytes from array <var>source</var>
-     * and writes the resulting bytes (up to three of them)
-     * to <var>destination</var>.
-     * The source and destination arrays can be manipulated
-     * anywhere along their length by specifying
-     * <var>srcOffset</var> and <var>destOffset</var>.
-     * This method does not check to make sure your arrays
-     * are large enough to accomodate <var>srcOffset</var> + 4 for
-     * the <var>source</var> array or <var>destOffset</var> + 3 for
-     * the <var>destination</var> array.
-     * This method returns the actual number of bytes that
-     * were converted from the Base64 encoding.
-     * <p>This is the lowest level of the decoding methods with
-     * all possible parameters.</p>
-     *
-     * @param source      the array to convert
-     * @param srcOffset   the index where conversion begins
-     * @param destination the array to hold the conversion
-     * @param destOffset  the index where output will be put
-     * @param options     alphabet type is pulled from this (standard, url-safe, ordered)
-     * @return the number of decoded bytes converted
-     * @throws NullPointerException     if source or destination arrays are null
-     * @throws IllegalArgumentException if srcOffset or destOffset are invalid
-     *                                  or there is not enough room in the array.
-     * @since 1.3
-     */
-    private static int decode4to3(
-            byte[] source, int srcOffset,
-            byte[] destination, int destOffset, int options) {
-
-        // Lots of error checking and exception throwing
-        if (source == null) {
-            throw new NullPointerException("Source array was null.");
-        }   // end if
-        if (destination == null) {
-            throw new NullPointerException("Destination array was null.");
-        }   // end if
-        if (srcOffset < 0 || srcOffset + 3 >= source.length) {
-            throw new IllegalArgumentException(String.format(
-                    "Source array with length %d cannot have offset of %d and still process four bytes.", source.length, srcOffset));
-        }   // end if
-        if (destOffset < 0 || destOffset + 2 >= destination.length) {
-            throw new IllegalArgumentException(String.format(
-                    "Destination array with length %d cannot have offset of %d and still store three bytes.", destination.length, destOffset));
-        }   // end if
-
-
-        byte[] DECODABET = getDecodabet(options);
-
-        // Example: Dk==
-        if (source[srcOffset + 2] == EQUALS_SIGN) {
-            // Two ways to do the same thing. Don't know which way I like best.
-            //int outBuff =   ( ( DECODABET[ source[ srcOffset    ] ] << 24 ) >>>  6 )
-            //              | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
-            int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
-                    | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12);
-
-            destination[destOffset] = (byte) (outBuff >>> 16);
-            return 1;
-        }
-
-        // Example: DkL=
-        else if (source[srcOffset + 3] == EQUALS_SIGN) {
-            // Two ways to do the same thing. Don't know which way I like best.
-            //int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] << 24 ) >>>  6 )
-            //              | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
-            //              | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
-            int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
-                    | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
-                    | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6);
-
-            destination[destOffset] = (byte) (outBuff >>> 16);
-            destination[destOffset + 1] = (byte) (outBuff >>> 8);
-            return 2;
-        }
-
-        // Example: DkLE
-        else {
-            // Two ways to do the same thing. Don't know which way I like best.
-            //int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] << 24 ) >>>  6 )
-            //              | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
-            //              | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
-            //              | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
-            int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
-                    | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
-                    | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6)
-                    | ((DECODABET[source[srcOffset + 3]] & 0xFF));
-
-
-            destination[destOffset] = (byte) (outBuff >> 16);
-            destination[destOffset + 1] = (byte) (outBuff >> 8);
-            destination[destOffset + 2] = (byte) (outBuff);
-
-            return 3;
-        }
-    }   // end decodeToBytes
-
-
-    /**
-     * Low-level access to decoding ASCII characters in
-     * the form of a byte array. <strong>Ignores GUNZIP option, if
-     * it's set.</strong> This is not generally a recommended method,
-     * although it is used internally as part of the decoding process.
-     * Special case: if len = 0, an empty array is returned. Still,
-     * if you need more speed and reduced memory footprint (and aren't
-     * gzipping), consider this method.
-     *
-     * @param source The Base64 encoded data
-     * @return decoded data
-     * @since 2.3.1
-     * @throws java.io.IOException If bogus characters are contained in the input
-     */
-    public static byte[] decode(byte[] source)
-            throws java.io.IOException {
-        byte[] decoded = null;
-//        try {
-        decoded = decode(source, 0, source.length, Base64.NO_OPTIONS);
-//        } catch( java.io.IOException ex ) {
-//            assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage();
-//        }
-        return decoded;
-    }
-
-
-    /**
-     * Low-level access to decoding ASCII characters in
-     * the form of a byte array. <strong>Ignores GUNZIP option, if
-     * it's set.</strong> This is not generally a recommended method,
-     * although it is used internally as part of the decoding process.
-     * Special case: if len = 0, an empty array is returned. Still,
-     * if you need more speed and reduced memory footprint (and aren't
-     * gzipping), consider this method.
-     *
-     * @param source  The Base64 encoded data
-     * @param off     The offset of where to begin decoding
-     * @param len     The length of characters to decode
-     * @param options Can specify options such as alphabet type to use
-     * @return decoded data
-     * @throws java.io.IOException If bogus characters exist in source data
-     * @since 1.3
-     */
-    public static byte[] decode(byte[] source, int off, int len, int options)
-            throws java.io.IOException {
-
-        // Lots of error checking and exception throwing
-        if (source == null) {
-            throw new NullPointerException("Cannot decode null source array.");
-        }   // end if
-        if (off < 0 || off + len > source.length) {
-            throw new IllegalArgumentException(String.format(
-                    "Source array with length %d cannot have offset of %d and process %d bytes.", source.length, off, len));
-        }   // end if
-
-        if (len == 0) {
-            return new byte[0];
-        } else if (len < 4) {
-            throw new IllegalArgumentException(
-                    "Base64-encoded string must have at least four characters, but length specified was " + len);
-        }   // end if
-
-        byte[] DECODABET = getDecodabet(options);
-
-        int len34 = len * 3 / 4;       // Estimate on array size
-        byte[] outBuff = new byte[len34]; // Upper limit on size of output
-        int outBuffPosn = 0;             // Keep track of where we're writing
-
-        byte[] b4 = new byte[4];     // Four byte buffer from source, eliminating white space
-        int b4Posn = 0;               // Keep track of four byte input buffer
-        int i = 0;               // Source array counter
-        byte sbiDecode = 0;               // Special value from DECODABET
-
-        for (i = off; i < off + len; i++) {  // Loop through source
-
-            sbiDecode = DECODABET[source[i] & 0xFF];
-
-            // White space, Equals sign, or legit Base64 character
-            // Note the values such as -5 and -9 in the
-            // DECODABETs at the top of the file.
-            if (sbiDecode >= WHITE_SPACE_ENC) {
-                if (sbiDecode >= EQUALS_SIGN_ENC) {
-                    b4[b4Posn++] = source[i];         // Save non-whitespace
-                    if (b4Posn > 3) {                  // Time to decode?
-                        outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, options);
-                        b4Posn = 0;
-
-                        // If that was the equals sign, break out of 'for' loop
-                        if (source[i] == EQUALS_SIGN) {
-                            break;
-                        }   // end if: equals sign
-                    }   // end if: quartet built
-                }   // end if: equals sign or better
-            }   // end if: white space, equals sign or better
-            else {
-                // There's a bad input character in the Base64 stream.
-                throw new java.io.IOException(String.format(
-                        "Bad Base64 input character decimal %d in array position %d", ((int) source[i]) & 0xFF, i));
-            }   // end else:
-        }   // each input character
-
-        byte[] out = new byte[outBuffPosn];
-        System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
-        return out;
-    }   // end decode
-
-
-    /**
-     * Decodes data from Base64 notation, automatically
-     * detecting gzip-compressed data and decompressing it.
-     *
-     * @param s the string to decode
-     * @return the decoded data
-     * @throws java.io.IOException If there is a problem
-     * @since 1.4
-     */
-    public static byte[] decode(String s) throws java.io.IOException {
-        return decode(s, NO_OPTIONS);
-    }
-
-
-    /**
-     * Decodes data from Base64 notation, automatically
-     * detecting gzip-compressed data and decompressing it.
-     *
-     * @param s       the string to decode
-     * @param options encode options such as URL_SAFE
-     * @return the decoded data
-     * @throws java.io.IOException  if there is an error
-     * @throws NullPointerException if <tt>s</tt> is null
-     * @since 1.4
-     */
-    public static byte[] decode(String s, int options) throws java.io.IOException {
-
-        if (s == null) {
-            throw new NullPointerException("Input string was null.");
-        }   // end if
-
-        byte[] bytes;
-        try {
-            bytes = s.getBytes(PREFERRED_ENCODING);
-        }   // end try
-        catch (java.io.UnsupportedEncodingException uee) {
-            bytes = s.getBytes();
-        }   // end catch
-        //</change>
-
-        // Decode
-        bytes = decode(bytes, 0, bytes.length, options);
-
-        // Check to see if it's gzip-compressed
-        // GZIP Magic Two-Byte Number: 0x8b1f (35615)
-        boolean dontGunzip = (options & DONT_GUNZIP) != 0;
-        if ((bytes != null) && (bytes.length >= 4) && (!dontGunzip)) {
-
-            int head = ((int) bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
-            if (java.util.zip.GZIPInputStream.GZIP_MAGIC == head) {
-                java.io.ByteArrayInputStream bais = null;
-                java.util.zip.GZIPInputStream gzis = null;
-                java.io.ByteArrayOutputStream baos = null;
-                byte[] buffer = new byte[2048];
-                int length = 0;
-
-                try {
-                    baos = new java.io.ByteArrayOutputStream();
-                    bais = new java.io.ByteArrayInputStream(bytes);
-                    gzis = new java.util.zip.GZIPInputStream(bais);
-
-                    while ((length = gzis.read(buffer)) >= 0) {
-                        baos.write(buffer, 0, length);
-                    }   // end while: reading input
-
-                    // No error? Get new bytes.
-                    bytes = baos.toByteArray();
-
-                }   // end try
-                catch (java.io.IOException e) {
-                    e.printStackTrace();
-                    // Just return originally-decoded bytes
-                }   // end catch
-                finally {
-                    try {
-                        baos.close();
-                    } catch (Exception e) {
-                    }
-                    try {
-                        gzis.close();
-                    } catch (Exception e) {
-                    }
-                    try {
-                        bais.close();
-                    } catch (Exception e) {
-                    }
-                }   // end finally
-
-            }   // end if: gzipped
-        }   // end if: bytes.length >= 2
-
-        return bytes;
-    }   // end decode
-
-
-    /**
-     * Attempts to decode Base64 data and deserialize a Java
-     * Object within. Returns <tt>null</tt> if there was an error.
-     *
-     * @param encodedObject The Base64 data to decode
-     * @return The decoded and deserialized object
-     * @throws NullPointerException   if encodedObject is null
-     * @throws java.io.IOException    if there is a general error
-     * @throws ClassNotFoundException if the decoded object is of a
-     *                                class that cannot be found by the JVM
-     * @since 1.5
-     */
-    public static Object decodeToObject(String encodedObject)
-            throws java.io.IOException, java.lang.ClassNotFoundException {
-        return decodeToObject(encodedObject, NO_OPTIONS, null);
-    }
-
-
-    /**
-     * Attempts to decode Base64 data and deserialize a Java
-     * Object within. Returns <tt>null</tt> if there was an error.
-     * If <tt>loader</tt> is not null, it will be the class loader
-     * used when deserializing.
-     *
-     * @param encodedObject The Base64 data to decode
-     * @param options       Various parameters related to decoding
-     * @param loader        Optional class loader to use in deserializing classes.
-     * @return The decoded and deserialized object
-     * @throws NullPointerException   if encodedObject is null
-     * @throws java.io.IOException    if there is a general error
-     * @throws ClassNotFoundException if the decoded object is of a
-     *                                class that cannot be found by the JVM
-     * @since 2.3.4
-     */
-    public static Object decodeToObject(
-            String encodedObject, int options, final ClassLoader loader)
-            throws java.io.IOException, java.lang.ClassNotFoundException {
-
-        // Decode and gunzip if necessary
-        byte[] objBytes = decode(encodedObject, options);
-
-        java.io.ByteArrayInputStream bais = null;
-        java.io.ObjectInputStream ois = null;
-        Object obj = null;
-
-        try {
-            bais = new java.io.ByteArrayInputStream(objBytes);
-
-            // If no custom class loader is provided, use Java's builtin OIS.
-            if (loader == null) {
-                ois = new java.io.ObjectInputStream(bais);
-            }   // end if: no loader provided
-
-            // Else make a customized object input stream that uses
-            // the provided class loader.
-            else {
-                ois = new java.io.ObjectInputStream(bais) {
-                    @Override
-                    public Class<?> resolveClass(java.io.ObjectStreamClass streamClass)
-                            throws java.io.IOException, ClassNotFoundException {
-                        Class c = Class.forName(streamClass.getName(), false, loader);
-                        if (c == null) {
-                            return super.resolveClass(streamClass);
-                        } else {
-                            return c;   // Class loader knows of this class.
-                        }   // end else: not null
-                    }   // end resolveClass
-                };  // end ois
-            }   // end else: no custom class loader
-
-            obj = ois.readObject();
-        }   // end try
-        catch (java.io.IOException e) {
-            throw e;    // Catch and throw in order to execute finally{}
-        }   // end catch
-        catch (java.lang.ClassNotFoundException e) {
-            throw e;    // Catch and throw in order to execute finally{}
-        }   // end catch
-        finally {
-            try {
-                bais.close();
-            } catch (Exception e) {
-            }
-            try {
-                ois.close();
-            } catch (Exception e) {
-            }
-        }   // end finally
-
-        return obj;
-    }   // end decodeObject
-
-
-    /**
-     * Convenience method for encoding data to a file.
-     * 
-     * <p>As of v 2.3, if there is a error,
-     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
-     * In earlier versions, it just returned false, but
-     * in retrospect that's a pretty poor way to handle it.</p>
-     *
-     * @param dataToEncode byte array of data to encode in base64 form
-     * @param filename     Filename for saving encoded data
-     * @throws java.io.IOException  if there is an error
-     * @throws NullPointerException if dataToEncode is null
-     * @since 2.1
-     */
-    public static void encodeToFile(byte[] dataToEncode, String filename)
-            throws java.io.IOException {
-
-        if (dataToEncode == null) {
-            throw new NullPointerException("Data to encode was null.");
-        }   // end iff
-
-        B64OutputStream bos = null;
-        try {
-            bos = new B64OutputStream(
-                    new java.io.FileOutputStream(filename), Base64.ENCODE);
-            bos.write(dataToEncode);
-        }   // end try
-        catch (java.io.IOException e) {
-            throw e; // Catch and throw to execute finally{} block
-        }   // end catch: java.io.IOException
-        finally {
-            try {
-                bos.close();
-            } catch (Exception e) {
-            }
-        }   // end finally
-
-    }   // end encodeToFile
-
-
-    /**
-     * Convenience method for decoding data to a file.
-     * 
-     * <p>As of v 2.3, if there is a error,
-     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
-     * In earlier versions, it just returned false, but
-     * in retrospect that's a pretty poor way to handle it.</p>
-     *
-     * @param dataToDecode Base64-encoded data as a string
-     * @param filename     Filename for saving decoded data
-     * @throws java.io.IOException if there is an error
-     * @since 2.1
-     */
-    public static void decodeToFile(String dataToDecode, String filename)
-            throws java.io.IOException {
-
-        B64OutputStream bos = null;
-        try {
-            bos = new B64OutputStream(
-                    new java.io.FileOutputStream(filename), Base64.DECODE);
-            bos.write(dataToDecode.getBytes(PREFERRED_ENCODING));
-        }   // end try
-        catch (java.io.IOException e) {
-            throw e; // Catch and throw to execute finally{} block
-        }   // end catch: java.io.IOException
-        finally {
-            try {
-                bos.close();
-            } catch (Exception e) {
-            }
-        }   // end finally
-
-    }   // end decodeToFile
-
-
-    /**
-     * Convenience method for reading a base64-encoded
-     * file and decoding it.
-     * 
-     * <p>As of v 2.3, if there is a error,
-     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
-     * In earlier versions, it just returned false, but
-     * in retrospect that's a pretty poor way to handle it.</p>
-     *
-     * @param filename Filename for reading encoded data
-     * @return decoded byte array
-     * @throws java.io.IOException if there is an error
-     * @since 2.1
-     */
-    public static byte[] decodeFromFile(String filename)
-            throws java.io.IOException {
-
-        byte[] decodedData = null;
-        B64InputStream bis = null;
-        try {
-            // Set up some useful variables
-            java.io.File file = new java.io.File(filename);
-            byte[] buffer = null;
-            int length = 0;
-            int numBytes = 0;
-
-            // Check for size of file
-            if (file.length() > Integer.MAX_VALUE) {
-                throw new java.io.IOException("File is too big for this convenience method (" + file.length() + " bytes).");
-            }   // end if: file too big for int index
-            buffer = new byte[(int) file.length()];
-
-            // Open a stream
-            bis = new B64InputStream(
-                    new java.io.BufferedInputStream(
-                            new java.io.FileInputStream(file)), Base64.DECODE);
-
-            // Read until done
-            while ((numBytes = bis.read(buffer, length, 4096)) >= 0) {
-                length += numBytes;
-            }   // end while
-
-            // Save in a variable to return
-            decodedData = new byte[length];
-            System.arraycopy(buffer, 0, decodedData, 0, length);
-
-        }   // end try
-        catch (java.io.IOException e) {
-            throw e; // Catch and release to execute finally{}
-        }   // end catch: java.io.IOException
-        finally {
-            try {
-                bis.close();
-            } catch (Exception e) {
-            }
-        }   // end finally
-
-        return decodedData;
-    }   // end decodeFromFile
-
-
-    /**
-     * Convenience method for reading a binary file
-     * and base64-encoding it.
-     * 
-     * <p>As of v 2.3, if there is a error,
-     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
-     * In earlier versions, it just returned false, but
-     * in retrospect that's a pretty poor way to handle it.</p>
-     *
-     * @param filename Filename for reading binary data
-     * @return base64-encoded string
-     * @throws java.io.IOException if there is an error
-     * @since 2.1
-     */
-    public static String encodeFromFile(String filename)
-            throws java.io.IOException {
-
-        String encodedData = null;
-        B64InputStream bis = null;
-        try {
-            // Set up some useful variables
-            java.io.File file = new java.io.File(filename);
-            byte[] buffer = new byte[Math.max((int) (file.length() * 1.4 + 1), 40)]; // Need max() for math on small files (v2.2.1); Need +1 for a few corner cases (v2.3.5)
-            int length = 0;
-            int numBytes = 0;
-
-            // Open a stream
-            bis = new B64InputStream(
-                    new java.io.BufferedInputStream(
-                            new java.io.FileInputStream(file)), Base64.ENCODE);
-
-            // Read until done
-            while ((numBytes = bis.read(buffer, length, 4096)) >= 0) {
-                length += numBytes;
-            }   // end while
-
-            // Save in a variable to return
-            encodedData = new String(buffer, 0, length, Base64.PREFERRED_ENCODING);
-
-        }   // end try
-        catch (java.io.IOException e) {
-            throw e; // Catch and release to execute finally{}
-        }   // end catch: java.io.IOException
-        finally {
-            try {
-                bis.close();
-            } catch (Exception e) {
-            }
-        }   // end finally
-
-        return encodedData;
-    }   // end encodeFromFile
-
-    /**
-     * Reads <tt>infile</tt> and encodes it to <tt>outfile</tt>.
-     *
-     * @param infile  Input file
-     * @param outfile Output file
-     * @throws java.io.IOException if there is an error
-     * @since 2.2
-     */
-    public static void encodeFileToFile(String infile, String outfile)
-            throws java.io.IOException {
-
-        String encoded = Base64.encodeFromFile(infile);
-        java.io.OutputStream out = null;
-        try {
-            out = new java.io.BufferedOutputStream(
-                    new java.io.FileOutputStream(outfile));
-            out.write(encoded.getBytes("US-ASCII")); // Strict, 7-bit output.
-        }   // end try
-        catch (java.io.IOException e) {
-            throw e; // Catch and release to execute finally{}
-        }   // end catch
-        finally {
-            try {
-                out.close();
-            } catch (Exception ex) {
-            }
-        }   // end finally
-    }   // end encodeFileToFile
-
-
-    /**
-     * Reads <tt>infile</tt> and decodes it to <tt>outfile</tt>.
-     *
-     * @param infile  Input file
-     * @param outfile Output file
-     * @throws java.io.IOException if there is an error
-     * @since 2.2
-     */
-    public static void decodeFileToFile(String infile, String outfile)
-            throws java.io.IOException {
-
-        byte[] decoded = Base64.decodeFromFile(infile);
-        java.io.OutputStream out = null;
-        try {
-            out = new java.io.BufferedOutputStream(
-                    new java.io.FileOutputStream(outfile));
-            out.write(decoded);
-        }   // end try
-        catch (java.io.IOException e) {
-            throw e; // Catch and release to execute finally{}
-        }   // end catch
-        finally {
-            try {
-                out.close();
-            } catch (Exception ex) {
-            }
-        }   // end finally
-    }   // end decodeFileToFile
-
-
-    /* ********  I N N E R   C L A S S   I N P U T S T R E A M  ******** */
-
-
-    /**
-     * A {@link com.dd.plist.Base64.B64InputStream} will read data from another
-     * <tt>java.io.InputStream</tt>, given in the constructor,
-     * and encode/decode to/from Base64 notation on the fly.
-     *
-     * @see Base64
-     * @since 1.3
-     */
-    public static class B64InputStream extends java.io.FilterInputStream {
-
-        private boolean encode;         // Encoding or decoding
-        private int position;       // Current position in the buffer
-        private byte[] buffer;         // Small buffer holding converted data
-        private int bufferLength;   // Length of buffer (3 or 4)
-        private int numSigBytes;    // Number of meaningful bytes in the buffer
-        private int lineLength;
-        private boolean breakLines;     // Break lines at less than 80 characters
-        private int options;        // Record options used to create the stream.
-        private byte[] decodabet;      // Local copies to avoid extra method calls
-
-
-        /**
-         * Constructs a {@link com.dd.plist.Base64.B64InputStream} in DECODE mode.
-         *
-         * @param in the <tt>java.io.InputStream</tt> from which to read data.
-         * @since 1.3
-         */
-        public B64InputStream(java.io.InputStream in) {
-            this(in, DECODE);
-        }   // end constructor
-
-
-        /**
-         * Constructs a {@link com.dd.plist.Base64.B64InputStream} in
-         * either ENCODE or DECODE mode.
-         * 
-         * Valid options:<pre>
-         *   ENCODE or DECODE: Encode or Decode as data is read.
-         *   DO_BREAK_LINES: break lines at 76 characters
-         *     (only meaningful when encoding)
-         * </pre>
-         * 
-         * Example: <code>new Base64.B64InputStream( in, Base64.DECODE )</code>
-         *
-         * @param in      the <tt>java.io.InputStream</tt> from which to read data.
-         * @param options Specified options
-         * @see Base64#ENCODE
-         * @see Base64#DECODE
-         * @see Base64#DO_BREAK_LINES
-         * @since 2.0
-         */
-        public B64InputStream(java.io.InputStream in, int options) {
-
-            super(in);
-            this.options = options; // Record for later
-            this.breakLines = (options & DO_BREAK_LINES) > 0;
-            this.encode = (options & ENCODE) > 0;
-            this.bufferLength = encode ? 4 : 3;
-            this.buffer = new byte[bufferLength];
-            this.position = -1;
-            this.lineLength = 0;
-            this.decodabet = getDecodabet(options);
-        }   // end constructor
-
-        /**
-         * Reads enough of the input stream to convert
-         * to/from Base64 and returns the next byte.
-         *
-         * @return next byte
-         * @since 1.3
-         */
-        @Override
-        public int read() throws java.io.IOException {
-
-            // Do we need to get data?
-            if (position < 0) {
-                if (encode) {
-                    byte[] b3 = new byte[3];
-                    int numBinaryBytes = 0;
-                    for (int i = 0; i < 3; i++) {
-                        int b = in.read();
-
-                        // If end of stream, b is -1.
-                        if (b >= 0) {
-                            b3[i] = (byte) b;
-                            numBinaryBytes++;
-                        } else {
-                            break; // out of for loop
-                        }   // end else: end of stream
-
-                    }   // end for: each needed input byte
-
-                    if (numBinaryBytes > 0) {
-                        encode3to4(b3, 0, numBinaryBytes, buffer, 0, options);
-                        position = 0;
-                        numSigBytes = 4;
-                    }   // end if: got data
-                    else {
-                        return -1;  // Must be end of stream
-                    }   // end else
-                }   // end if: encoding
-
-                // Else decoding
-                else {
-                    byte[] b4 = new byte[4];
-                    int i = 0;
-                    for (i = 0; i < 4; i++) {
-                        // Read four "meaningful" bytes:
-                        int b = 0;
-                        do {
-                            b = in.read();
-                        }
-                        while (b >= 0 && decodabet[b & 0x7f] <= WHITE_SPACE_ENC);
-
-                        if (b < 0) {
-                            break; // Reads a -1 if end of stream
-                        }   // end if: end of stream
-
-                        b4[i] = (byte) b;
-                    }   // end for: each needed input byte
-
-                    if (i == 4) {
-                        numSigBytes = decode4to3(b4, 0, buffer, 0, options);
-                        position = 0;
-                    }   // end if: got four characters
-                    else if (i == 0) {
-                        return -1;
-                    }   // end else if: also padded correctly
-                    else {
-                        // Must have broken out from above.
-                        throw new java.io.IOException("Improperly padded Base64 input.");
-                    }   // end
-
-                }   // end else: decode
-            }   // end else: get data
-
-            // Got data?
-            if (position >= 0) {
-                // End of relevant data?
-                if ( /*!encode &&*/ position >= numSigBytes) {
-                    return -1;
-                }   // end if: got data
-
-                if (encode && breakLines && lineLength >= MAX_LINE_LENGTH) {
-                    lineLength = 0;
-                    return '\n';
-                }   // end if
-                else {
-                    lineLength++;   // This isn't important when decoding
-                    // but throwing an extra "if" seems
-                    // just as wasteful.
-
-                    int b = buffer[position++];
-
-                    if (position >= bufferLength) {
-                        position = -1;
-                    }   // end if: end
-
-                    return b & 0xFF; // This is how you "cast" a byte that's
-                    // intended to be unsigned.
-                }   // end else
-            }   // end if: position >= 0
-
-            // Else error
-            else {
-                throw new java.io.IOException("Error in Base64 code reading stream.");
-            }   // end else
-        }   // end read
-
-
-        /**
-         * Calls {@link #read()} repeatedly until the end of stream
-         * is reached or <var>len</var> bytes are read.
-         * Returns number of bytes read into array or -1 if
-         * end of stream is encountered.
-         *
-         * @param dest array to hold values
-         * @param off  offset for array
-         * @param len  max number of bytes to read into array
-         * @return bytes read into array or -1 if end of stream is encountered.
-         * @since 1.3
-         */
-        @Override
-        public int read(byte[] dest, int off, int len)
-                throws java.io.IOException {
-            int i;
-            int b;
-            for (i = 0; i < len; i++) {
-                b = read();
-
-                if (b >= 0) {
-                    dest[off + i] = (byte) b;
-                } else if (i == 0) {
-                    return -1;
-                } else {
-                    break; // Out of 'for' loop
-                } // Out of 'for' loop
-            }   // end for: each byte read
-            return i;
-        }   // end read
-
-    }   // end inner class B64InputStream
-
-
-
-
-
-
-    /* ********  I N N E R   C L A S S   O U T P U T S T R E A M  ******** */
-
-
-    /**
-     * A {@link com.dd.plist.Base64.B64OutputStream} will write data to another
-     * <tt>java.io.OutputStream</tt>, given in the constructor,
-     * and encode/decode to/from Base64 notation on the fly.
-     *
-     * @see Base64
-     * @since 1.3
-     */
-    public static class B64OutputStream extends java.io.FilterOutputStream {
-
-        private boolean encode;
-        private int position;
-        private byte[] buffer;
-        private int bufferLength;
-        private int lineLength;
-        private boolean breakLines;
-        private byte[] b4;         // Scratch used in a few places
-        private boolean suspendEncoding;
-        private int options;    // Record for later
-        private byte[] decodabet;  // Local copies to avoid extra method calls
-
-        /**
-         * Constructs a {@link com.dd.plist.Base64.B64OutputStream} in ENCODE mode.
-         *
-         * @param out the <tt>java.io.OutputStream</tt> to which data will be written.
-         * @since 1.3
-         */
-        public B64OutputStream(java.io.OutputStream out) {
-            this(out, ENCODE);
-        }   // end constructor
-
-
-        /**
-         * Constructs a {@link com.dd.plist.Base64.B64OutputStream} in
-         * either ENCODE or DECODE mode.
-         * 
-         * Valid options:<pre>
-         *   ENCODE or DECODE: Encode or Decode as data is read.
-         *   DO_BREAK_LINES: don't break lines at 76 characters
-         *     (only meaningful when encoding)
-         * </pre>
-         * 
-         * Example: <code>new Base64.B64OutputStream( out, Base64.ENCODE )</code>
-         *
-         * @param out     the <tt>java.io.B64OutputStream</tt> to which data will be written.
-         * @param options Specified options.
-         * @see Base64#ENCODE
-         * @see Base64#DECODE
-         * @see Base64#DO_BREAK_LINES
-         * @since 1.3
-         */
-        public B64OutputStream(java.io.OutputStream out, int options) {
-            super(out);
-            this.breakLines = (options & DO_BREAK_LINES) != 0;
-            this.encode = (options & ENCODE) != 0;
-            this.bufferLength = encode ? 3 : 4;
-            this.buffer = new byte[bufferLength];
-            this.position = 0;
-            this.lineLength = 0;
-            this.suspendEncoding = false;
-            this.b4 = new byte[4];
-            this.options = options;
-            this.decodabet = getDecodabet(options);
-        }   // end constructor
-
-
-        /**
-         * Writes the byte to the output stream after
-         * converting to/from Base64 notation.
-         * When encoding, bytes are buffered three
-         * at a time before the output stream actually
-         * gets a write() call.
-         * When decoding, bytes are buffered four
-         * at a time.
-         *
-         * @param theByte the byte to write
-         * @since 1.3
-         */
-        @Override
-        public void write(int theByte)
-                throws java.io.IOException {
-            // Encoding suspended?
-            if (suspendEncoding) {
-                this.out.write(theByte);
-                return;
-            }   // end if: supsended
-
-            // Encode?
-            if (encode) {
-                buffer[position++] = (byte) theByte;
-                if (position >= bufferLength) { // Enough to encode.
-
-                    this.out.write(encode3to4(b4, buffer, bufferLength, options));
-
-                    lineLength += 4;
-                    if (breakLines && lineLength >= MAX_LINE_LENGTH) {
-                        this.out.write(NEW_LINE);
-                        lineLength = 0;
-                    }   // end if: end of line
-
-                    position = 0;
-                }   // end if: enough to output
-            }   // end if: encoding
-
-            // Else, Decoding
-            else {
-                // Meaningful Base64 character?
-                if (decodabet[theByte & 0x7f] > WHITE_SPACE_ENC) {
-                    buffer[position++] = (byte) theByte;
-                    if (position >= bufferLength) { // Enough to output.
-
-                        int len = Base64.decode4to3(buffer, 0, b4, 0, options);
-                        out.write(b4, 0, len);
-                        position = 0;
-                    }   // end if: enough to output
-                }   // end if: meaningful base64 character
-                else if (decodabet[theByte & 0x7f] != WHITE_SPACE_ENC) {
-                    throw new java.io.IOException("Invalid character in Base64 data.");
-                }   // end else: not white space either
-            }   // end else: decoding
-        }   // end write
-
-
-        /**
-         * Calls {@link #write(int)} repeatedly until <var>len</var>
-         * bytes are written.
-         *
-         * @param theBytes array from which to read bytes
-         * @param off      offset for array
-         * @param len      max number of bytes to read into array
-         * @since 1.3
-         */
-        @Override
-        public void write(byte[] theBytes, int off, int len)
-                throws java.io.IOException {
-            // Encoding suspended?
-            if (suspendEncoding) {
-                this.out.write(theBytes, off, len);
-                return;
-            }   // end if: supsended
-
-            for (int i = 0; i < len; i++) {
-                write(theBytes[off + i]);
-            }   // end for: each byte written
-
-        }   // end write
-
-
-        /**
-         * Method added by PHIL. [Thanks, PHIL. -Rob]
-         * This pads the buffer without closing the stream.
-         *
-         * @throws java.io.IOException if there's an error.
-         */
-        public void flushBase64() throws java.io.IOException {
-            if (position > 0) {
-                if (encode) {
-                    out.write(encode3to4(b4, buffer, position, options));
-                    position = 0;
-                }   // end if: encoding
-                else {
-                    throw new java.io.IOException("Base64 input not properly padded.");
-                }   // end else: decoding
-            }   // end if: buffer partially full
-
-        }   // end flush
-
-
-        /**
-         * Flushes and closes (I think, in the superclass) the stream.
-         *
-         * @since 1.3
-         */
-        @Override
-        public void close() throws java.io.IOException {
-            // 1. Ensure that pending characters are written
-            flushBase64();
-
-            // 2. Actually close the stream
-            // Base class both flushes and closes.
-            super.close();
-
-            buffer = null;
-            out = null;
-        }   // end close
-
-
-        /**
-         * Suspends encoding of the stream.
-         * May be helpful if you need to embed a piece of
-         * base64-encoded data in a stream.
-         *
-         * @throws java.io.IOException if there's an error flushing
-         * @since 1.5.1
-         */
-        public void suspendEncoding() throws java.io.IOException {
-            flushBase64();
-            this.suspendEncoding = true;
-        }   // end suspendEncoding
-
-
-        /**
-         * Resumes encoding of the stream.
-         * May be helpful if you need to embed a piece of
-         * base64-encoded data in a stream.
-         *
-         * @since 1.5.1
-         */
-        public void resumeEncoding() {
-            this.suspendEncoding = false;
-        }   // end resumeEncoding
-
-
-    }   // end inner class B64OutputStream
-
-
-}   // end class Base64
diff --git a/third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListParser.java b/third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListParser.java
deleted file mode 100644
index 9b20101..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListParser.java
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * plist - An open source library to parse and generate property lists
- * Copyright (C) 2011-2014 Daniel Dreibrodt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.dd.plist;
-
-import java.io.*;
-import java.math.BigInteger;
-
-/**
- * Parses property lists that are in Apple's binary format.
- * Use this class when you are sure about the format of the property list.
- * Otherwise use the PropertyListParser class.
- *
- * Parsing is done by calling the static <code>parse</code> methods.
- *
- * @author Daniel Dreibrodt
- */
-public class BinaryPropertyListParser {
-
-    /**
-     * Major version of the property list format
-     */
-    @SuppressWarnings("FieldCanBeLocal") //Useful when the features of different format versions are implemented
-    private int majorVersion;
-
-    /**
-     * Minor version of the property list format
-     */
-    @SuppressWarnings("FieldCanBeLocal") //Useful when the features of different format versions are implemented
-    private int minorVersion;
-
-    /**
-     * property list in bytes
-     */
-    private byte[] bytes;
-
-    /**
-     * Length of an object reference in bytes
-     */
-    private int objectRefSize;
-
-    /**
-     * The table holding the information at which offset each object is found
-     */
-    private int[] offsetTable;
-
-    /**
-     * Protected constructor so that instantiation is fully controlled by the
-     * static parse methods.
-     *
-     * @see BinaryPropertyListParser#parse(byte[])
-     */
-    protected BinaryPropertyListParser() {
-        /** empty **/
-    }
-
-    /**
-     * Parses a binary property list from a byte array.
-     *
-     * @param data The binary property list's data.
-     * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray.
-     * @throws PropertyListFormatException When the property list's format could not be parsed.
-     * @throws java.io.UnsupportedEncodingException When a NSString object could not be decoded.
-     */
-    public static NSObject parse(byte[] data) throws PropertyListFormatException, UnsupportedEncodingException {
-        BinaryPropertyListParser parser = new BinaryPropertyListParser();
-        return parser.doParse(data);
-    }
-
-    /**
-     * Parses a binary property list from a byte array.
-     *
-     * @param data The binary property list's data.
-     * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray.
-     * @throws PropertyListFormatException When the property list's format could not be parsed.
-     * @throws java.io.UnsupportedEncodingException When a NSString object could not be decoded.
-     */
-    private NSObject doParse(byte[] data) throws PropertyListFormatException, UnsupportedEncodingException {
-        bytes = data;
-        String magic = new String(copyOfRange(bytes, 0, 8));
-        if (!magic.startsWith("bplist")) {
-            throw new IllegalArgumentException("The given data is no binary property list. Wrong magic bytes: " + magic);
-        }
-
-        majorVersion = magic.charAt(6) - 0x30; //ASCII number
-        minorVersion = magic.charAt(7) - 0x30; //ASCII number
-
-        // 0.0 - OS X Tiger and earlier
-        // 0.1 - Leopard
-        // 0.? - Snow Leopard
-        // 1.5 - Lion
-        // 2.0 - Snow Lion
-
-        if (majorVersion > 0) {
-            throw new IllegalArgumentException("Unsupported binary property list format: v" + majorVersion + "." + minorVersion + ". " +
-                    "Version 1.0 and later are not yet supported.");
-            //Version 1.0+ is not even supported by OS X's own parser
-        }
-
-        /*
-         * Handle trailer, last 32 bytes of the file
-         */
-        byte[] trailer = copyOfRange(bytes, bytes.length - 32, bytes.length);
-        //6 null bytes (index 0 to 5)
-
-        int offsetSize = (int) parseUnsignedInt(trailer, 6, 7);
-        objectRefSize = (int) parseUnsignedInt(trailer, 7, 8);
-        int numObjects = (int) parseUnsignedInt(trailer, 8, 16);
-        int topObject = (int) parseUnsignedInt(trailer, 16, 24);
-        int offsetTableOffset = (int) parseUnsignedInt(trailer, 24, 32);
-
-        /*
-         * Handle offset table
-         */
-        offsetTable = new int[numObjects];
-
-        for (int i = 0; i < numObjects; i++) {
-            offsetTable[i] = (int) parseUnsignedInt(bytes, offsetTableOffset + i * offsetSize, offsetTableOffset + (i + 1) * offsetSize);
-        }
-
-        return parseObject(topObject);
-    }
-
-    /**
-     * Parses a binary property list from an input stream.
-     *
-     * @param is The input stream that points to the property list's data.
-     * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray.
-     * @throws PropertyListFormatException When the property list's format could not be parsed.
-     * @throws java.io.IOException When a NSString object could not be decoded or an InputStream IO error occurs.
-     */
-    public static NSObject parse(InputStream is) throws IOException, PropertyListFormatException {
-        byte[] buf = PropertyListParser.readAll(is);
-        return parse(buf);
-    }
-
-    /**
-     * Parses a binary property list file.
-     *
-     * @param f The binary property list file
-     * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray.
-     * @throws PropertyListFormatException When the property list's format could not be parsed.
-     * @throws java.io.UnsupportedEncodingException When a NSString object could not be decoded or a file IO error occurs.
-     */
-    public static NSObject parse(File f) throws IOException, PropertyListFormatException {
-        return parse(new FileInputStream(f));
-    }
-
-    /**
-     * Parses an object inside the currently parsed binary property list.
-     * For the format specification check
-     * <a href="http://www.opensource.apple.com/source/CF/CF-855.17/CFBinaryPList.c">
-     * Apple's binary property list parser implementation</a>.
-     *
-     * @param obj The object ID.
-     * @return The parsed object.
-     * @throws PropertyListFormatException When the property list's format could not be parsed.
-     * @throws java.io.UnsupportedEncodingException When a NSString object could not be decoded.
-     */
-    private NSObject parseObject(int obj) throws PropertyListFormatException, UnsupportedEncodingException {
-        int offset = offsetTable[obj];
-        byte type = bytes[offset];
-        int objType = (type & 0xF0) >> 4; //First  4 bits
-        int objInfo = (type & 0x0F);      //Second 4 bits
-        switch (objType) {
-            case 0x0: {
-                //Simple
-                switch (objInfo) {
-                    case 0x0: {
-                        //null object (v1.0 and later)
-                        return null;
-                    }
-                    case 0x8: {
-                        //false
-                        return new NSNumber(false);
-                    }
-                    case 0x9: {
-                        //true
-                        return new NSNumber(true);
-                    }
-                    case 0xC: {
-                        //URL with no base URL (v1.0 and later)
-                        //TODO Implement binary URL parsing (not yet even implemented in Core Foundation as of revision 855.17)
-                        throw new UnsupportedOperationException("The given binary property list contains a URL object. Parsing of this object type is not yet implemented.");
-                    }
-                    case 0xD: {
-                        //URL with base URL (v1.0 and later)
-                        //TODO Implement binary URL parsing (not yet even implemented in Core Foundation as of revision 855.17)
-                        throw new UnsupportedOperationException("The given binary property list contains a URL object. Parsing of this object type is not yet implemented.");
-                    }
-                    case 0xE: {
-                        //16-byte UUID (v1.0 and later)
-                        //TODO Implement binary UUID parsing (not yet even implemented in Core Foundation as of revision 855.17)
-                        throw new UnsupportedOperationException("The given binary property list contains a UUID object. Parsing of this object type is not yet implemented.");
-                    }
-                    default: {
-                        throw new PropertyListFormatException("The given binary property list contains an object of unknown type (" + objType + ")");
-                    }
-                }
-            }
-            case 0x1: {
-                //integer
-                int length = (int) Math.pow(2, objInfo);
-                return new NSNumber(bytes, offset + 1, offset + 1 + length, NSNumber.INTEGER);
-            }
-            case 0x2: {
-                //real
-                int length = (int) Math.pow(2, objInfo);
-                return new NSNumber(bytes, offset + 1, offset + 1 + length, NSNumber.REAL);
-            }
-            case 0x3: {
-                //Date
-                if (objInfo != 0x3) {
-                    throw new PropertyListFormatException("The given binary property list contains a date object of an unknown type ("+objInfo+")");
-                }
-                return new NSDate(bytes, offset + 1, offset + 9);
-            }
-            case 0x4: {
-                //Data
-                int[] lengthAndOffset = readLengthAndOffset(objInfo, offset);
-                int length = lengthAndOffset[0];
-                int dataOffset = lengthAndOffset[1];
-                return new NSData(copyOfRange(bytes, offset + dataOffset, offset + dataOffset + length));
-            }
-            case 0x5: {
-                //ASCII string
-                int[] lengthAndOffset = readLengthAndOffset(objInfo, offset);
-                int length = lengthAndOffset[0];  //Each character is 1 byte
-                int strOffset = lengthAndOffset[1];
-                return new NSString(bytes, offset + strOffset, offset + strOffset + length, "ASCII");
-            }
-            case 0x6: {
-                //UTF-16-BE string
-                int[] lengthAndOffset = readLengthAndOffset(objInfo, offset);
-                int characters = lengthAndOffset[0];
-                int strOffset = lengthAndOffset[1];
-                //UTF-16 characters can have variable length, but the Core Foundation reference implementation
-                //assumes 2 byte characters, thus only covering the Basic Multilingual Plane
-                int length = characters * 2;
-                return new NSString(bytes, offset + strOffset, offset + strOffset + length, "UTF-16BE");
-            }
-            case 0x7: {
-                //UTF-8 string (v1.0 and later)
-                int[] lengthAndOffset = readLengthAndOffset(objInfo, offset);
-                int strOffset = lengthAndOffset[1];
-                int characters = lengthAndOffset[0];
-                //UTF-8 characters can have variable length, so we need to calculate the byte length dynamically
-                //by reading the UTF-8 characters one by one
-                int length = calculateUtf8StringLength(bytes, offset + strOffset, characters);
-                return new NSString(bytes, offset + strOffset, offset + strOffset + length, "UTF-8");
-            }
-            case 0x8: {
-                //UID (v1.0 and later)
-                int length = objInfo + 1;
-                return new UID(String.valueOf(obj), copyOfRange(bytes, offset + 1, offset + 1 + length));
-            }
-            case 0xA: {
-                //Array
-                int[] lengthAndOffset = readLengthAndOffset(objInfo, offset);
-                int length = lengthAndOffset[0];
-                int arrayOffset = lengthAndOffset[1];
-
-                NSArray array = new NSArray(length);
-                for (int i = 0; i < length; i++) {
-                    int objRef = (int) parseUnsignedInt(bytes, offset + arrayOffset + i * objectRefSize, offset + arrayOffset + (i + 1) * objectRefSize);
-                    array.setValue(i, parseObject(objRef));
-                }
-                return array;
-            }
-            case 0xB: {
-                //Ordered set (v1.0 and later)
-                int[] lengthAndOffset = readLengthAndOffset(objInfo, offset);
-                int length = lengthAndOffset[0];
-                int contentOffset = lengthAndOffset[1];
-
-                NSSet set = new NSSet(true);
-                for (int i = 0; i < length; i++) {
-                    int objRef = (int) parseUnsignedInt(bytes, offset + contentOffset + i * objectRefSize, offset + contentOffset + (i + 1) * objectRefSize);
-                    set.addObject(parseObject(objRef));
-                }
-                return set;
-            }
-            case 0xC: {
-                //Set (v1.0 and later)
-                int[] lengthAndOffset = readLengthAndOffset(objInfo, offset);
-                int length = lengthAndOffset[0];
-                int contentOffset = lengthAndOffset[1];
-
-                NSSet set = new NSSet();
-                for (int i = 0; i < length; i++) {
-                    int objRef = (int) parseUnsignedInt(bytes, offset + contentOffset + i * objectRefSize, offset + contentOffset + (i + 1) * objectRefSize);
-                    set.addObject(parseObject(objRef));
-                }
-                return set;
-            }
-            case 0xD: {
-                //Dictionary
-                int[] lengthAndOffset = readLengthAndOffset(objInfo, offset);
-                int length = lengthAndOffset[0];
-                int contentOffset = lengthAndOffset[1];
-
-                NSDictionary dict = new NSDictionary();
-                for (int i = 0; i < length; i++) {
-                    int keyRef = (int) parseUnsignedInt(bytes, offset + contentOffset + i * objectRefSize, offset + contentOffset + (i + 1) * objectRefSize);
-                    int valRef = (int) parseUnsignedInt(bytes, offset + contentOffset + (length * objectRefSize) + i * objectRefSize, offset + contentOffset + (length * objectRefSize) + (i + 1) * objectRefSize);
-                    NSObject key = parseObject(keyRef);
-                    NSObject val = parseObject(valRef);
-                    assert key != null; //Encountering a null object at this point would either be a fundamental error in the parser or an error in the property list
-                    dict.put(key.toString(), val);
-                }
-                return dict;
-            }
-            default: {
-                throw new PropertyListFormatException("The given binary property list contains an object of unknown type (" + objType + ")");
-            }
-        }
-    }
-
-    /**
-     * Reads the length for arrays, sets and dictionaries.
-     *
-     * @param objInfo Object information byte.
-     * @param offset  Offset in the byte array at which the object is located.
-     * @return An array with the length two. First entry is the length, second entry the offset at which the content starts.
-     */
-    private int[] readLengthAndOffset(int objInfo, int offset) {
-        int lengthValue = objInfo;
-        int offsetValue = 1;
-        if (objInfo == 0xF) {
-            int int_type = bytes[offset + 1];
-            int intType = (int_type & 0xF0) >> 4;
-            if (intType != 0x1) {
-                System.err.println("BinaryPropertyListParser: Length integer has an unexpected type" + intType + ". Attempting to parse anyway...");
-            }
-            int intInfo = int_type & 0x0F;
-            int intLength = (int) Math.pow(2, intInfo);
-            offsetValue = 2 + intLength;
-            if (intLength < 3) {
-                lengthValue = (int) parseUnsignedInt(bytes, offset + 2, offset + 2 + intLength);
-            } else {
-                lengthValue = new BigInteger(copyOfRange(bytes, offset + 2, offset + 2 + intLength)).intValue();
-            }
-        }
-        return new int[]{lengthValue, offsetValue};
-    }
-
-    private int calculateUtf8StringLength(byte[] bytes, int offset, int numCharacters) {
-        int length = 0;
-        for(int i = 0; i < numCharacters; i++) {
-            int tempOffset = offset + length;
-            if(bytes.length <= tempOffset) {
-                //WARNING: Invalid UTF-8 string, fall back to length = number of characters
-                return numCharacters;
-            }
-            if(bytes[tempOffset] < 0x80) {
-                length++;
-            }
-            if(bytes[tempOffset] < 0xC2) {
-                //Invalid value (marks continuation byte), fall back to length = number of characters
-                return numCharacters;
-            }
-            else if(bytes[tempOffset] < 0xE0) {
-                if((bytes[tempOffset + 1] & 0xC0) != 0x80) {
-                    //Invalid continuation byte, fall back to length = number of characters
-                    return numCharacters;
-                }
-                length += 2;
-            }
-            else if(bytes[tempOffset] < 0xF0) {
-                if((bytes[tempOffset + 1] & 0xC0) != 0x80
-                        || (bytes[tempOffset + 2] & 0xC0) != 0x80) {
-                    //Invalid continuation byte, fall back to length = number of characters
-                    return numCharacters;
-                }
-                length += 3;
-            }
-            else if(bytes[tempOffset] < 0xF5) {
-                if((bytes[tempOffset + 1] & 0xC0) != 0x80
-                        || (bytes[tempOffset + 2] & 0xC0) != 0x80
-                        || (bytes[tempOffset + 3] & 0xC0) != 0x80) {
-                    //Invalid continuation byte, fall back to length = number of characters
-                    return numCharacters;
-                }
-                length += 4;
-            }
-        }
-        return length;
-    }
-
-    /**
-     * Parses an unsigned integers from a byte array.
-     *
-     * @param bytes The byte array containing the unsigned integer.
-     * @return The unsigned integer represented by the given bytes.
-     */
-    @SuppressWarnings("unused")
-    public static long parseUnsignedInt(byte[] bytes) {
-        return parseUnsignedInt(bytes, 0, bytes.length);
-    }
-
-    /**
-     * Parses an unsigned integer from a byte array.
-     *
-     * @param bytes The byte array containing the unsigned integer.
-     * @param startIndex Beginning of the unsigned int in the byte array.
-     * @param endIndex End of the unsigned int in the byte array.
-     * @return The unsigned integer represented by the given bytes.
-     */
-    public static long parseUnsignedInt(byte[] bytes, int startIndex, int endIndex) {
-        long l = 0;
-        for (int i = startIndex; i < endIndex; i++) {
-            l <<= 8;
-            l |= bytes[i] & 0xFF;
-        }
-        l &= 0xFFFFFFFFL;
-        return l;
-    }
-
-    /**
-     * Parses a long from a (big-endian) byte array.
-     *
-     * @param bytes The bytes representing the long integer.
-     * @return The long integer represented by the given bytes.
-     */
-    @SuppressWarnings("unused")
-    public static long parseLong(byte[] bytes) {
-        return parseLong(bytes, 0, bytes.length);
-    }
-
-    /**
-     * Parses a long from a (big-endian) byte array.
-     *
-     * @param bytes The bytes representing the long integer.
-     * @param startIndex Beginning of the long in the byte array.
-     * @param endIndex End of the long in the byte array.
-     * @return The long integer represented by the given bytes.
-     */
-    public static long parseLong(byte[] bytes, int startIndex, int endIndex) {
-        long l = 0;
-        for (int i = startIndex; i < endIndex; i++) {
-            l <<= 8;
-            l |= bytes[i] & 0xFF;
-        }
-        return l;
-    }
-
-    /**
-     * Parses a double from a (big-endian) byte array.
-     *
-     * @param bytes The bytes representing the double.
-     * @return The double represented by the given bytes.
-     */
-    @SuppressWarnings("unused")
-    public static double parseDouble(byte[] bytes) {
-        return parseDouble(bytes, 0, bytes.length);
-    }
-
-    /**
-     * Parses a double from a (big-endian) byte array.
-     *
-     * @param bytes The bytes representing the double.
-     * @param startIndex Beginning of the double in the byte array.
-     * @param endIndex End of the double in the byte array.
-     * @return The double represented by the given bytes.
-     */
-    public static double parseDouble(byte[] bytes, int startIndex, int endIndex) {
-        if (endIndex - startIndex == 8) {
-            return Double.longBitsToDouble(parseLong(bytes, startIndex, endIndex));
-        } else if (endIndex - startIndex == 4) {
-            return Float.intBitsToFloat((int)parseLong(bytes, startIndex, endIndex));
-        } else {
-            throw new IllegalArgumentException("endIndex ("+endIndex+") - startIndex ("+startIndex+") != 4 or 8");
-        }
-    }
-
-    /**
-     * Copies a part of a byte array into a new array.
-     *
-     * @param src        The source array.
-     * @param startIndex The index from which to start copying.
-     * @param endIndex   The index until which to copy.
-     * @return The copied array.
-     */
-    public static byte[] copyOfRange(byte[] src, int startIndex, int endIndex) {
-        int length = endIndex - startIndex;
-        if (length < 0) {
-            throw new IllegalArgumentException("startIndex (" + startIndex + ")" + " > endIndex (" + endIndex + ")");
-        }
-        byte[] dest = new byte[length];
-        System.arraycopy(src, startIndex, dest, 0, length);
-        return dest;
-    }
-}
-
diff --git a/third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListWriter.java b/third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListWriter.java
deleted file mode 100644
index 21645be..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/BinaryPropertyListWriter.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * plist - An open source library to parse and generate property lists
- * Copyright (C) 2012 Keith Randall
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.dd.plist;
-
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-/**
- * A BinaryPropertyListWriter is a helper class for writing out
- * binary property list files.  It contains an output stream and
- * various structures for keeping track of which NSObjects have
- * already been serialized, and where they were put in the file.
- *
- * @author Keith Randall
- */
-public class BinaryPropertyListWriter {
-
-    public static final int VERSION_00 = 0;
-    public static final int VERSION_10 = 10;
-    public static final int VERSION_15 = 15;
-    public static final int VERSION_20 = 20;
-
-    /**
-     * Finds out the minimum binary property list format version that
-     * can be used to save the given NSObject tree.
-     *
-     * @param root Object root
-     * @return Version code
-     */
-    private static int getMinimumRequiredVersion(NSObject root) {
-        int minVersion = VERSION_00;
-        if (root == null) {
-            minVersion = VERSION_10;
-        }
-        if (root instanceof NSDictionary) {
-            NSDictionary dict = (NSDictionary) root;
-            for (NSObject o : dict.getHashMap().values()) {
-                int v = getMinimumRequiredVersion(o);
-                if (v > minVersion)
-                    minVersion = v;
-            }
-        } else if (root instanceof NSArray) {
-            NSArray array = (NSArray) root;
-            for (NSObject o : array.getArray()) {
-                int v = getMinimumRequiredVersion(o);
-                if (v > minVersion)
-                    minVersion = v;
-            }
-        } else if (root instanceof NSSet) {
-            //Sets are only allowed in property lists v1+
-            minVersion = VERSION_10;
-            NSSet set = (NSSet) root;
-            for (NSObject o : set.allObjects()) {
-                int v = getMinimumRequiredVersion(o);
-                if (v > minVersion)
-                    minVersion = v;
-            }
-        }
-        return minVersion;
-    }
-
-    /**
-     * Writes a binary plist file with the given object as the root.
-     *
-     * @param file the file to write to
-     * @param root the source of the data to write to the file
-     * @throws IOException When an IO error occurs while writing to the file or the object structure contains
-     *                     data that cannot be saved.
-     */
-    public static void write(File file, NSObject root) throws IOException {
-        OutputStream out = new FileOutputStream(file);
-        write(out, root);
-        out.close();
-    }
-
-    /**
-     * Writes a binary plist serialization of the given object as the root.
-     *
-     * @param out  the stream to write to
-     * @param root the source of the data to write to the stream
-     * @throws IOException When an IO error occurs while writing to the stream or the object structure contains
-     *                     data that cannot be saved.
-     */
-    public static void write(OutputStream out, NSObject root) throws IOException {
-        int minVersion = getMinimumRequiredVersion(root);
-        if (minVersion > VERSION_00) {
-            String versionString = ((minVersion == VERSION_10) ? "v1.0" : ((minVersion == VERSION_15) ? "v1.5" : ((minVersion == VERSION_20) ? "v2.0" : "v0.0")));
-            throw new IOException("The given property list structure cannot be saved. " +
-                    "The required version of the binary format (" + versionString + ") is not yet supported.");
-        }
-        BinaryPropertyListWriter w = new BinaryPropertyListWriter(out, minVersion);
-        w.write(root);
-    }
-
-    /**
-     * Writes a binary plist serialization of the given object as the root
-     * into a byte array.
-     *
-     * @param root The root object of the property list
-     * @return The byte array containing the serialized property list
-     * @throws IOException When an IO error occurs while writing to the stream or the object structure contains
-     *                     data that cannot be saved.
-     */
-    public static byte[] writeToArray(NSObject root) throws IOException {
-        ByteArrayOutputStream bout = new ByteArrayOutputStream();
-        write(bout, root);
-        return bout.toByteArray();
-    }
-
-    private int version = VERSION_00;
-
-    // raw output stream to result file
-    private OutputStream out;
-
-    // # of bytes written so far
-    private long count;
-
-    // map from object to its ID
-    private Map<NSObject, Integer> idMap = new LinkedHashMap<NSObject, Integer>();
-    private int idSizeInBytes;
-
-    /**
-     * Creates a new binary property list writer
-     *
-     * @param outStr The output stream into which the binary property list will be written
-     * @throws IOException When an IO error occurs while writing to the stream or the object structure contains
-     *                     data that cannot be saved.
-     */
-    BinaryPropertyListWriter(OutputStream outStr) throws IOException {
-        out = new BufferedOutputStream(outStr);
-    }
-
-    BinaryPropertyListWriter(OutputStream outStr, int version) throws IOException {
-        this.version = version;
-        out = new BufferedOutputStream(outStr);
-    }
-
-    void write(NSObject root) throws IOException {
-        // magic bytes
-        write(new byte[]{'b', 'p', 'l', 'i', 's', 't'});
-
-        //version
-        switch (version) {
-            case VERSION_00: {
-                write(new byte[]{'0', '0'});
-                break;
-            }
-            case VERSION_10: {
-                write(new byte[]{'1', '0'});
-                break;
-            }
-            case VERSION_15: {
-                write(new byte[]{'1', '5'});
-                break;
-            }
-            case VERSION_20: {
-                write(new byte[]{'2', '0'});
-                break;
-            }
-        }
-
-        // assign IDs to all the objects.
-        root.assignIDs(this);
-
-        idSizeInBytes = computeIdSizeInBytes(idMap.size());
-
-        // offsets of each object, indexed by ID
-        long[] offsets = new long[idMap.size()];
-
-        // write each object, save offset
-        for (Map.Entry<NSObject, Integer> entry : idMap.entrySet()) {
-            NSObject obj = entry.getKey();
-            int id = entry.getValue();
-            offsets[id] = count;
-            if (obj == null) {
-                write(0x00);
-            } else {
-                obj.toBinary(this);
-            }
-        }
-
-        // write offset table
-        long offsetTableOffset = count;
-        int offsetSizeInBytes = computeOffsetSizeInBytes(count);
-        for (long offset : offsets) {
-            writeBytes(offset, offsetSizeInBytes);
-        }
-
-        if (version != VERSION_15) {
-            // write trailer
-            // 6 null bytes
-            write(new byte[6]);
-            // size of an offset
-            write(offsetSizeInBytes);
-            // size of a ref
-            write(idSizeInBytes);
-            // number of objects
-            writeLong(idMap.size());
-            // top object
-            writeLong(idMap.get(root));
-            // offset table offset
-            writeLong(offsetTableOffset);
-        }
-
-        out.flush();
-    }
-
-    void assignID(NSObject obj) {
-        if (!idMap.containsKey(obj)) {
-            idMap.put(obj, idMap.size());
-        }
-    }
-
-    int getID(NSObject obj) {
-        return idMap.get(obj);
-    }
-
-    private static int computeIdSizeInBytes(int numberOfIds) {
-        if (numberOfIds < 256) return 1;
-        if (numberOfIds < 65536) return 2;
-        return 4;
-    }
-
-    private int computeOffsetSizeInBytes(long maxOffset) {
-        if (maxOffset < 256) return 1;
-        if (maxOffset < 65536) return 2;
-        if (maxOffset < 4294967296L) return 4;
-        return 8;
-    }
-
-    void writeIntHeader(int kind, int value) throws IOException {
-        assert value >= 0;
-        if (value < 15) {
-            write((kind << 4) + value);
-        } else if (value < 256) {
-            write((kind << 4) + 15);
-            write(0x10);
-            writeBytes(value, 1);
-        } else if (value < 65536) {
-            write((kind << 4) + 15);
-            write(0x11);
-            writeBytes(value, 2);
-        } else {
-            write((kind << 4) + 15);
-            write(0x12);
-            writeBytes(value, 4);
-        }
-    }
-
-    void write(int b) throws IOException {
-        out.write(b);
-        count++;
-    }
-
-    void write(byte[] bytes) throws IOException {
-        out.write(bytes);
-        count += bytes.length;
-    }
-
-    void writeBytes(long value, int bytes) throws IOException {
-        // write low-order bytes big-endian style
-        for (int i = bytes - 1; i >= 0; i--) {
-            write((int) (value >> (8 * i)));
-        }
-    }
-
-    void writeID(int id) throws IOException {
-        writeBytes(id, idSizeInBytes);
-    }
-
-    void writeLong(long value) throws IOException {
-        writeBytes(value, 8);
-    }
-
-    void writeDouble(double value) throws IOException {
-        writeLong(Double.doubleToRawLongBits(value));
-    }
-}
diff --git a/third_party/java/dd_plist/java/com/dd/plist/NSArray.java b/third_party/java/dd_plist/java/com/dd/plist/NSArray.java
deleted file mode 100644
index a0b2a4d..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/NSArray.java
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * plist - An open source library to parse and generate property lists
- * Copyright (C) 2014 Daniel Dreibrodt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.dd.plist;
-
-import java.io.IOException;
-import java.util.Arrays;
-
-/**
- * Represents an Array.
- *
- * @author Daniel Dreibrodt
- */
-public class NSArray extends NSObject {
-
-    private NSObject[] array;
-
-    /**
-     * Creates an empty array of the given length.
-     *
-     * @param length The number of elements this array will be able to hold.
-     */
-    public NSArray(int length) {
-        array = new NSObject[length];
-    }
-
-    /**
-     * Creates a array from an existing one
-     *
-     * @param a The array which should be wrapped by the NSArray
-     */
-    public NSArray(NSObject... a) {
-        array = a;
-    }
-
-    /**
-     * Returns the object stored at the given index.
-     * Equivalent to <code>getArray()[i]</code>.
-     *
-     * @param i The index of the object.
-     * @return The object at the given index.
-     */
-    public NSObject objectAtIndex(int i) {
-        return array[i];
-    }
-
-    /**
-     * Remove the i-th element from the array.
-     * The array will be resized.
-     *
-     * @param i The index of the object
-     */
-    public void remove(int i) {
-        if ((i >= array.length) || (i < 0))
-            throw new ArrayIndexOutOfBoundsException("invalid index:" + i + ";the array length is " + array.length);
-        NSObject[] newArray = new NSObject[array.length - 1];
-        System.arraycopy(array, 0, newArray, 0, i);
-        System.arraycopy(array, i + 1, newArray, i, array.length - i - 1);
-        array = newArray;
-    }
-
-    /**
-     * Stores an object at the specified index.
-     * If there was another object stored at that index it will be replaced.
-     * Equivalent to <code>getArray()[key] = value</code>.
-     *
-     * @param key   The index where to store the object.
-     * @param value The object.
-     */
-    public void setValue(int key, Object value) {
-        array[key] = NSObject.wrap(value);
-    }
-
-    /**
-     * Returns the array of NSObjects represented by this NSArray.
-     * Any changes to the values of this array will also affect the NSArray.
-     *
-     * @return The actual array represented by this NSArray.
-     */
-    public NSObject[] getArray() {
-        return array;
-    }
-
-    /**
-     * Returns the size of the array.
-     *
-     * @return The number of elements that this array can store.
-     */
-    public int count() {
-        return array.length;
-    }
-
-    /**
-     * Checks whether an object is present in the array or whether it is equal
-     * to any of the objects in the array.
-     *
-     * @param obj The object to look for.
-     * @return <code>true</code>, when the object could be found. <code>false</code> otherwise.
-     * @see Object#equals(java.lang.Object)
-     */
-    public boolean containsObject(Object obj) {
-        NSObject nso = NSObject.wrap(obj);
-        for (NSObject elem : array) {
-            if(elem == null) {
-                if(obj == null)
-                    return true;
-                continue;
-            }
-            if (elem.equals(nso)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Searches for an object in the array. If it is found its index will be
-     * returned. This method also returns an index if the object is not the same
-     * as the one stored in the array but has equal contents.
-     *
-     * @param obj The object to look for.
-     * @return The index of the object, if it was found. -1 otherwise.
-     * @see Object#equals(java.lang.Object)
-     * @see #indexOfIdenticalObject(Object)
-     */
-    public int indexOfObject(Object obj) {
-        NSObject nso = NSObject.wrap(obj);
-        for (int i = 0; i < array.length; i++) {
-            if (array[i].equals(nso)) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    /**
-     * Searches for an object in the array. If it is found its index will be
-     * returned. This method only returns the index of an object that is
-     * <b>identical</b> to the given one. Thus objects that might contain the
-     * same value as the given one will not be considered.
-     *
-     * @param obj The object to look for.
-     * @return The index of the object, if it was found. -1 otherwise.
-     * @see #indexOfObject(Object)
-     */
-    public int indexOfIdenticalObject(Object obj) {
-        NSObject nso = NSObject.wrap(obj);
-        for (int i = 0; i < array.length; i++) {
-            if (array[i] == nso) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    /**
-     * Returns the last object contained in this array.
-     * Equivalent to <code>getArray()[getArray().length-1]</code>.
-     *
-     * @return The value of the highest index in the array.
-     */
-    public NSObject lastObject() {
-        return array[array.length - 1];
-    }
-
-    /**
-     * Returns a new array containing only the values stored at the given
-     * indices. The values are sorted by their index.
-     *
-     * @param indexes The indices of the objects.
-     * @return The new array containing the objects stored at the given indices.
-     */
-    public NSObject[] objectsAtIndexes(int... indexes) {
-        NSObject[] result = new NSObject[indexes.length];
-        Arrays.sort(indexes);
-        for (int i = 0; i < indexes.length; i++)
-            result[i] = array[indexes[i]];
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if(obj == null)
-            return false;
-        if(obj.getClass().equals(NSArray.class)) {
-            return Arrays.equals(((NSArray) obj).getArray(), this.array);
-        } else {
-            NSObject nso = NSObject.wrap(obj);
-            if(nso.getClass().equals(NSArray.class)) {
-                return Arrays.equals(((NSArray) nso).getArray(), this.array);
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 7;
-        hash = 89 * hash + Arrays.deepHashCode(this.array);
-        return hash;
-    }
-
-    @Override
-    void toXML(StringBuilder xml, int level) {
-        indent(xml, level);
-        xml.append("<array>");
-        xml.append(NSObject.NEWLINE);
-        for (NSObject o : array) {
-            o.toXML(xml, level + 1);
-            xml.append(NSObject.NEWLINE);
-        }
-        indent(xml, level);
-        xml.append("</array>");
-    }
-
-    @Override
-    void assignIDs(BinaryPropertyListWriter out) {
-        super.assignIDs(out);
-        for (NSObject obj : array) {
-            obj.assignIDs(out);
-        }
-    }
-
-    @Override
-    void toBinary(BinaryPropertyListWriter out) throws IOException {
-        out.writeIntHeader(0xA, array.length);
-        for (NSObject obj : array) {
-            out.writeID(out.getID(obj));
-        }
-    }
-
-    /**
-     * Generates a valid ASCII property list which has this NSArray as its
-     * root object. The generated property list complies with the format as
-     * described in <a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/PropertyLists/OldStylePlists/OldStylePLists.html">
-     * Property List Programming Guide - Old-Style ASCII Property Lists</a>.
-     *
-     * @return ASCII representation of this object.
-     */
-    public String toASCIIPropertyList() {
-        StringBuilder ascii = new StringBuilder();
-        toASCII(ascii, 0);
-        ascii.append(NEWLINE);
-        return ascii.toString();
-    }
-
-    /**
-     * Generates a valid ASCII property list in GnuStep format which has this
-     * NSArray as its root object. The generated property list complies with
-     * the format as described in <a href="http://www.gnustep.org/resources/documentation/Developer/Base/Reference/NSPropertyList.html">
-     * GnuStep - NSPropertyListSerialization class documentation
-     * </a>
-     *
-     * @return GnuStep ASCII representation of this object.
-     */
-    public String toGnuStepASCIIPropertyList() {
-        StringBuilder ascii = new StringBuilder();
-        toASCIIGnuStep(ascii, 0);
-        ascii.append(NEWLINE);
-        return ascii.toString();
-    }
-
-    @Override
-    protected void toASCII(StringBuilder ascii, int level) {
-        indent(ascii, level);
-        ascii.append(ASCIIPropertyListParser.ARRAY_BEGIN_TOKEN);
-        int indexOfLastNewLine = ascii.lastIndexOf(NEWLINE);
-        for (int i = 0; i < array.length; i++) {
-            Class<?> objClass = array[i].getClass();
-            if ((objClass.equals(NSDictionary.class) || objClass.equals(NSArray.class) || objClass.equals(NSData.class))
-                    && indexOfLastNewLine != ascii.length()) {
-                ascii.append(NEWLINE);
-                indexOfLastNewLine = ascii.length();
-                array[i].toASCII(ascii, level + 1);
-            } else {
-                if (i != 0)
-                    ascii.append(" ");
-                array[i].toASCII(ascii, 0);
-            }
-
-            if (i != array.length - 1)
-                ascii.append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
-
-            if (ascii.length() - indexOfLastNewLine > ASCII_LINE_LENGTH) {
-                ascii.append(NEWLINE);
-                indexOfLastNewLine = ascii.length();
-            }
-        }
-        ascii.append(ASCIIPropertyListParser.ARRAY_END_TOKEN);
-    }
-
-    @Override
-    protected void toASCIIGnuStep(StringBuilder ascii, int level) {
-        indent(ascii, level);
-        ascii.append(ASCIIPropertyListParser.ARRAY_BEGIN_TOKEN);
-        int indexOfLastNewLine = ascii.lastIndexOf(NEWLINE);
-        for (int i = 0; i < array.length; i++) {
-            Class<?> objClass = array[i].getClass();
-            if ((objClass.equals(NSDictionary.class) || objClass.equals(NSArray.class) || objClass.equals(NSData.class))
-                    && indexOfLastNewLine != ascii.length()) {
-                ascii.append(NEWLINE);
-                indexOfLastNewLine = ascii.length();
-                array[i].toASCIIGnuStep(ascii, level + 1);
-            } else {
-                if (i != 0)
-                    ascii.append(" ");
-                array[i].toASCIIGnuStep(ascii, 0);
-            }
-
-            if (i != array.length - 1)
-                ascii.append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
-
-            if (ascii.length() - indexOfLastNewLine > ASCII_LINE_LENGTH) {
-                ascii.append(NEWLINE);
-                indexOfLastNewLine = ascii.length();
-            }
-        }
-        ascii.append(ASCIIPropertyListParser.ARRAY_END_TOKEN);
-    }
-}
diff --git a/third_party/java/dd_plist/java/com/dd/plist/NSData.java b/third_party/java/dd_plist/java/com/dd/plist/NSData.java
deleted file mode 100644
index d156a2f..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/NSData.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * plist - An open source library to parse and generate property lists
- * Copyright (C) 2011 Daniel Dreibrodt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package com.dd.plist;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-
-/**
- * NSData objects are wrappers for byte buffers.
- *
- * @author Daniel Dreibrodt
- */
-public class NSData extends NSObject {
-
-    private byte[] bytes;
-
-    /**
-     * Creates the NSData object from the binary representation of it.
-     *
-     * @param bytes The raw data contained in the NSData object.
-     */
-    public NSData(byte[] bytes) {
-        this.bytes = bytes;
-    }
-
-    /**
-     * Creates a NSData object from its textual representation, which is a Base64 encoded amount of bytes.
-     *
-     * @param base64 The Base64 encoded contents of the NSData object.
-     * @throws IOException When the given string is not a proper Base64 formatted string.
-     */
-    public NSData(String base64) throws IOException {
-        //Remove all white spaces from the string so that it is parsed completely
-        //and not just until the first white space occurs.
-        String data = base64.replaceAll("\\s+", "");
-        bytes = Base64.decode(data);
-    }
-
-    /**
-     * Creates a NSData object from a file. Using the files contents as the contents of this NSData object.
-     *
-     * @param file The file containing the data.
-     * @throws FileNotFoundException If the file could not be found.
-     * @throws IOException           If the file could not be read.
-     */
-    public NSData(File file) throws IOException {
-        bytes = new byte[(int) file.length()];
-        RandomAccessFile raf = new RandomAccessFile(file, "r");
-        raf.read(bytes);
-        raf.close();
-    }
-
-    /**
-     * The bytes contained in this NSData object.
-     *
-     * @return The data as bytes
-     */
-    public byte[] bytes() {
-        return bytes;
-    }
-
-    /**
-     * Gets the amount of data stored in this object.
-     *
-     * @return The number of bytes contained in this object.
-     */
-    public int length() {
-        return bytes.length;
-    }
-
-    /**
-     * Loads the bytes from this NSData object into a byte buffer
-     *
-     * @param buf    The byte buffer which will contain the data
-     * @param length The amount of data to copy
-     */
-    public void getBytes(ByteBuffer buf, int length) {
-        buf.put(bytes, 0, Math.min(bytes.length, length));
-    }
-
-    /**
-     * Loads the bytes from this NSData object into a byte buffer
-     *
-     * @param buf        The byte buffer which will contain the data
-     * @param rangeStart The start index
-     * @param rangeStop  The stop index
-     */
-    public void getBytes(ByteBuffer buf, int rangeStart, int rangeStop) {
-        buf.put(bytes, rangeStart, Math.min(bytes.length, rangeStop));
-    }
-
-    /**
-     * Gets the Base64 encoded data contained in this NSData object.
-     *
-     * @return The Base64 encoded data as a <code>String</code>.
-     */
-    public String getBase64EncodedData() {
-        return Base64.encodeBytes(bytes);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        return obj.getClass().equals(getClass()) && Arrays.equals(((NSData) obj).bytes, bytes);
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 5;
-        hash = 67 * hash + Arrays.hashCode(this.bytes);
-        return hash;
-    }
-
-    @Override
-    void toXML(StringBuilder xml, int level) {
-        indent(xml, level);
-        xml.append("<data>");
-        xml.append(NSObject.NEWLINE);
-        String base64 = getBase64EncodedData();
-        for (String line : base64.split("\n")) {
-            indent(xml, level + 1);
-            xml.append(line);
-            xml.append(NSObject.NEWLINE);
-        }
-        indent(xml, level);
-        xml.append("</data>");
-    }
-
-    @Override
-    void toBinary(BinaryPropertyListWriter out) throws IOException {
-        out.writeIntHeader(0x4, bytes.length);
-        out.write(bytes);
-    }
-
-    @Override
-    protected void toASCII(StringBuilder ascii, int level) {
-        indent(ascii, level);
-        ascii.append(ASCIIPropertyListParser.DATA_BEGIN_TOKEN);
-        int indexOfLastNewLine = ascii.lastIndexOf(NEWLINE);
-        for (int i = 0; i < bytes.length; i++) {
-            int b = bytes[i] & 0xFF;
-            if (b < 16)
-                ascii.append("0");
-            ascii.append(Integer.toHexString(b));
-            if (ascii.length() - indexOfLastNewLine > ASCII_LINE_LENGTH) {
-                ascii.append(NEWLINE);
-                indexOfLastNewLine = ascii.length();
-            } else if ((i + 1) % 2 == 0 && i != bytes.length - 1) {
-                ascii.append(" ");
-            }
-        }
-        ascii.append(ASCIIPropertyListParser.DATA_END_TOKEN);
-    }
-
-    @Override
-    protected void toASCIIGnuStep(StringBuilder ascii, int level) {
-        toASCII(ascii, level);
-    }
-}
diff --git a/third_party/java/dd_plist/java/com/dd/plist/NSDate.java b/third_party/java/dd_plist/java/com/dd/plist/NSDate.java
deleted file mode 100644
index 0f4246c..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/NSDate.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * plist - An open source library to parse and generate property lists
- * Copyright (C) 2011 Daniel Dreibrodt, Keith Randall
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.dd.plist;
-
-import java.io.IOException;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.TimeZone;
-
-/**
- * Represents a date.
- *
- * @author Daniel Dreibrodt
- */
-public class NSDate extends NSObject {
-
-    private Date date;
-
-    // EPOCH = new SimpleDateFormat("yyyy MM dd zzz").parse("2001 01 01 GMT").getTime();
-    // ...but that's annoying in a static initializer because it can throw exceptions, ick.
-    // So we just hardcode the correct value.
-    private final static long EPOCH = 978307200000L;
-
-    private static final SimpleDateFormat sdfDefault = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
-    private static final SimpleDateFormat sdfGnuStep = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
-
-    static {
-        sdfDefault.setTimeZone(TimeZone.getTimeZone("GMT"));
-        sdfGnuStep.setTimeZone(TimeZone.getTimeZone("GMT"));
-    }
-
-    /**
-     * Parses the XML date string and creates a Java Date object from it.
-     * This function is synchronized as SimpleDateFormat is not thread-safe.
-     *
-     * @param textRepresentation The date string as found in the XML property list
-     * @return The parsed Date
-     * @throws ParseException If the given string cannot be parsed.
-     * @see SimpleDateFormat#parse(java.lang.String)
-     */
-    private static synchronized Date parseDateString(String textRepresentation) throws ParseException {
-        try {
-            return sdfDefault.parse(textRepresentation);
-        } catch (ParseException ex) {
-            return sdfGnuStep.parse(textRepresentation);
-        }
-    }
-
-    /**
-     * Generates a String representation of a Java Date object. The string
-     * is formatted according to the specification for XML property list dates.
-     *
-     * @param date The date which should be represented.
-     * @return The string representation of the date.
-     */
-    private static synchronized String makeDateString(Date date) {
-        return sdfDefault.format(date);
-    }
-
-    /**
-     * Generates a String representation of a Java Date object. The string
-     * is formatted according to the specification for GnuStep ASCII property
-     * list dates.
-     *
-     * @param date The date which should be represented.
-     * @return The string representation of the date.
-     */
-    private static synchronized String makeDateStringGnuStep(Date date) {
-        return sdfGnuStep.format(date);
-    }
-
-    /**
-     * Creates a date from its binary representation.
-     *
-     * @param bytes The date bytes
-     */
-    public NSDate(byte[] bytes){
-        this(bytes, 0, bytes.length);
-    }
-
-    /**
-     * Creates a date from its binary representation.
-     *
-     * @param bytes byte array with all information
-     * @param startIndex int with the starting index of the date
-     * @param endIndex int with the end index of the date
-     */
-    public NSDate(byte[] bytes, final int startIndex, final int endIndex) {
-        //dates are 8 byte big-endian double, seconds since the epoch
-        date = new Date(EPOCH + (long) (1000 * BinaryPropertyListParser.parseDouble(bytes, startIndex, endIndex)));
-    }
-
-    /**
-     * Parses a date from its textual representation.
-     * That representation has the following pattern: <code>yyyy-MM-dd'T'HH:mm:ss'Z'</code>
-     *
-     * @param textRepresentation The textual representation of the date (ISO 8601 format)
-     * @throws ParseException When the date could not be parsed, i.e. it does not match the expected pattern.
-     */
-    public NSDate(String textRepresentation) throws ParseException {
-        date = parseDateString(textRepresentation);
-    }
-
-    /**
-     * Creates a NSDate from a Java Date
-     *
-     * @param d The date
-     */
-    public NSDate(Date d) {
-        if (d == null)
-            throw new IllegalArgumentException("Date cannot be null");
-        date = d;
-    }
-
-    /**
-     * Gets the date.
-     *
-     * @return The date.
-     */
-    public Date getDate() {
-        return date;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        return obj.getClass().equals(getClass()) && date.equals(((NSDate) obj).getDate());
-    }
-
-    @Override
-    public int hashCode() {
-        return date.hashCode();
-    }
-
-    @Override
-    void toXML(StringBuilder xml, int level) {
-        indent(xml, level);
-        xml.append("<date>");
-        xml.append(makeDateString(date));
-        xml.append("</date>");
-    }
-
-    @Override
-    public void toBinary(BinaryPropertyListWriter out) throws IOException {
-        out.write(0x33);
-        out.writeDouble((date.getTime() - EPOCH) / 1000.0);
-    }
-
-    /**
-     * Generates a string representation of the date.
-     *
-     * @return A string representation of the date.
-     * @see java.util.Date#toString()
-     */
-    @Override
-    public String toString() {
-        return date.toString();
-    }
-
-    @Override
-    protected void toASCII(StringBuilder ascii, int level) {
-        indent(ascii, level);
-        ascii.append("\"");
-        ascii.append(makeDateString(date));
-        ascii.append("\"");
-    }
-
-    @Override
-    protected void toASCIIGnuStep(StringBuilder ascii, int level) {
-        indent(ascii, level);
-        ascii.append("<*D");
-        ascii.append(makeDateStringGnuStep(date));
-        ascii.append(">");
-    }
-}
diff --git a/third_party/java/dd_plist/java/com/dd/plist/NSDictionary.java b/third_party/java/dd_plist/java/com/dd/plist/NSDictionary.java
deleted file mode 100644
index 9beedbc..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/NSDictionary.java
+++ /dev/null
@@ -1,511 +0,0 @@
-/*
- * plist - An open source library to parse and generate property lists
- * Copyright (C) 2014 Daniel Dreibrodt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.dd.plist;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A NSDictionary is a collection of keys and values, essentially a Hashtable.
- * The keys are simple Strings whereas the values can be any kind of NSObject.
- *
- * You can access the keys through the function <code>allKeys()</code>. Access
- * to the objects stored for each key is given through the function
- * <code>objectoForKey(String key)</code>.
- *
- * @author Daniel Dreibrodt
- * @see java.util.Hashtable
- * @see com.dd.plist.NSObject
- */
-public class NSDictionary extends NSObject  implements Map<String, NSObject> {
-
-    private HashMap<String, NSObject> dict;
-
-    /**
-     * Creates a new empty NSDictionary.
-     */
-    public NSDictionary() {
-        //With a linked HashMap the order of elements in the dictionary is kept.
-        dict = new LinkedHashMap<String, NSObject>();
-    }
-
-    /**
-     * Gets the hashmap which stores the keys and values of this dictionary.
-     * Changes to the hashmap's contents are directly reflected in this
-     * dictionary.
-     *
-     * @return The hashmap which is used by this dictionary to store its contents.
-     */
-    public HashMap<String, NSObject> getHashMap() {
-        return dict;
-    }
-
-    /**
-     * Gets the NSObject stored for the given key.
-     *
-     * @param key The key.
-     * @return The object.
-     */
-    public NSObject objectForKey(String key) {
-        return dict.get(key);
-    }
-
-    /*
-	 * (non-Javadoc)
-	 *
-	 * @see java.util.Map#size()
-	 */
-    public int size() {
-        return dict.size();
-    }
-
-    /*
-	 * (non-Javadoc)
-	 *
-	 * @see java.util.Map#isEmpty()
-	 */
-    public boolean isEmpty() {
-        return dict.isEmpty();
-    }
-
-    /*
-	 * (non-Javadoc)
-	 *
-	 * @see java.util.Map#containsKey(java.lang.Object)
-	 */
-    public boolean containsKey(Object key) {
-        return dict.containsKey(key);
-    }
-
-    /*
-	 * (non-Javadoc)
-	 *
-	 * @see java.util.Map#containsValue(java.lang.Object)
-	 */
-    public boolean containsValue(Object value) {
-        if(value == null)
-            return false;
-        NSObject wrap = NSObject.wrap(value);
-        return dict.containsValue(wrap);
-    }
-
-    /*
-	 * (non-Javadoc)
-	 *
-	 * @see java.util.Map#get(java.lang.Object)
-	 */
-    public NSObject get(Object key) {
-        return dict.get(key);
-    }
-
-    /*
-	 * (non-Javadoc)
-	 *
-	 * @see java.util.Map#putAll(java.util.Map)
-	 */
-    public void putAll(Map<? extends String, ? extends NSObject> values) {
-        for (Object object : values.entrySet()) {
-            @SuppressWarnings("unchecked")
-            Map.Entry<String, NSObject> entry = (Map.Entry<String, NSObject>) object;
-            put(entry.getKey(), entry.getValue());
-        }
-    }
-
-    /**
-     * Puts a new key-value pair into this dictionary.
-     * If the value is null, no operation will be performed on the dictionary.
-     *
-     * @param key The key.
-     * @param obj The value.
-     * @return The value previously associated to the given key,
-     *         or null, if no value was associated to it.
-     */
-    public NSObject put(String key, NSObject obj) {
-        if(key == null)
-            return null;
-        if(obj == null)
-            return dict.get(key);
-        return dict.put(key, obj);
-    }
-
-    /**
-     * Puts a new key-value pair into this dictionary.
-     * If key or value are null, no operation will be performed on the dictionary.
-     *
-     * @param key The key.
-     * @param obj The value. Supported object types are numbers, byte-arrays, dates, strings and arrays or sets of those.
-     * @return The value previously associated to the given key,
-     *         or null, if no value was associated to it.
-     */
-    public NSObject put(String key, Object obj) {
-        return put(key, NSObject.wrap(obj));
-    }
-
-    /**
-     * Removes a key-value pair from this dictionary.
-     *
-     * @param key The key
-     * @return the value previously associated to the given key.
-     */
-    public NSObject remove(String key) {
-        return dict.remove(key);
-    }
-
-    /*
-	 * (non-Javadoc)
-	 *
-	 * @see java.util.Map#remove(java.lang.Object)
-	 */
-    public NSObject remove(Object key) {
-        return dict.remove(key);
-    }
-
-    /**
-     * Removes all key-value pairs from this dictionary.
-     * @see java.util.Map#clear()
-     */
-    public void clear() {
-        dict.clear();
-    }
-
-    /*
-	 * (non-Javadoc)
-	 *
-	 * @see java.util.Map#keySet()
-	 */
-    public Set<String> keySet() {
-        return dict.keySet();
-    }
-
-    /*
-     * (non-Javadoc)
-     *
-     * @see java.util.Map#values()
-     */
-    public Collection<NSObject> values() {
-        return dict.values();
-    }
-
-    /*
-     * (non-Javadoc)
-     *
-     * @see java.util.Map#entrySet()
-     */
-    public Set<Entry<String, NSObject>> entrySet() {
-        return dict.entrySet();
-    }
-
-    /**
-     * Checks whether a given key is contained in this dictionary.
-     *
-     * @param key The key that will be searched for.
-     * @return Whether the key is contained in this dictionary.
-     */
-    public boolean containsKey(String key) {
-        return dict.containsKey(key);
-    }
-
-    /**
-     * Checks whether a given value is contained in this dictionary.
-     *
-     * @param val The value that will be searched for.
-     * @return Whether the key is contained in this dictionary.
-     */
-    public boolean containsValue(NSObject val) {
-        return val != null && dict.containsValue(val);
-    }
-
-    /**
-     * Checks whether a given value is contained in this dictionary.
-     *
-     * @param val The value that will be searched for.
-     * @return Whether the key is contained in this dictionary.
-     */
-    public boolean containsValue(String val) {
-        for (NSObject o : dict.values()) {
-            if (o.getClass().equals(NSString.class)) {
-                NSString str = (NSString) o;
-                if (str.getContent().equals(val))
-                    return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Checks whether a given value is contained in this dictionary.
-     *
-     * @param val The value that will be searched for.
-     * @return Whether the key is contained in this dictionary.
-     */
-    public boolean containsValue(long val) {
-        for (NSObject o : dict.values()) {
-            if (o.getClass().equals(NSNumber.class)) {
-                NSNumber num = (NSNumber) o;
-                if (num.isInteger() && num.intValue() == val)
-                    return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Checks whether a given value is contained in this dictionary.
-     *
-     * @param val The value that will be searched for.
-     * @return Whether the key is contained in this dictionary.
-     */
-    public boolean containsValue(double val) {
-        for (NSObject o : dict.values()) {
-            if (o.getClass().equals(NSNumber.class)) {
-                NSNumber num = (NSNumber) o;
-                if (num.isReal() && num.doubleValue() == val)
-                    return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Checks whether a given value is contained in this dictionary.
-     *
-     * @param val The value that will be searched for.
-     * @return Whether the key is contained in this dictionary.
-     */
-    public boolean containsValue(boolean val) {
-        for (NSObject o : dict.values()) {
-            if (o.getClass().equals(NSNumber.class)) {
-                NSNumber num = (NSNumber) o;
-                if (num.isBoolean() && num.boolValue() == val)
-                    return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Checks whether a given value is contained in this dictionary.
-     *
-     * @param val The value that will be searched for.
-     * @return Whether the key is contained in this dictionary.
-     */
-    public boolean containsValue(Date val) {
-        for (NSObject o : dict.values()) {
-            if (o.getClass().equals(NSDate.class)) {
-                NSDate dat = (NSDate) o;
-                if (dat.getDate().equals(val))
-                    return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Checks whether a given value is contained in this dictionary.
-     *
-     * @param val The value that will be searched for.
-     * @return Whether the key is contained in this dictionary.
-     */
-    public boolean containsValue(byte[] val) {
-        for (NSObject o : dict.values()) {
-            if (o.getClass().equals(NSData.class)) {
-                NSData dat = (NSData) o;
-                if (Arrays.equals(dat.bytes(), val))
-                    return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Counts the number of contained key-value pairs.
-     *
-     * @return The size of this NSDictionary.
-     */
-    public int count() {
-        return dict.size();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        return (obj.getClass().equals(this.getClass()) && ((NSDictionary) obj).dict.equals(dict));
-    }
-
-    /**
-     * Gets a list of all keys used in this NSDictionary.
-     *
-     * @return The list of all keys used in this NSDictionary.
-     */
-    public String[] allKeys() {
-        return dict.keySet().toArray(new String[count()]);
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 7;
-        hash = 83 * hash + (this.dict != null ? this.dict.hashCode() : 0);
-        return hash;
-    }
-
-    @Override
-    void toXML(StringBuilder xml, int level) {
-        indent(xml, level);
-        xml.append("<dict>");
-        xml.append(NSObject.NEWLINE);
-        for (String key : dict.keySet()) {
-            NSObject val = objectForKey(key);
-            indent(xml, level + 1);
-            xml.append("<key>");
-            //According to http://www.w3.org/TR/REC-xml/#syntax node values must not
-            //contain the characters < or &. Also the > character should be escaped.
-            if (key.contains("&") || key.contains("<") || key.contains(">")) {
-                xml.append("<![CDATA[");
-                xml.append(key.replaceAll("]]>", "]]]]><![CDATA[>"));
-                xml.append("]]>");
-            } else {
-                xml.append(key);
-            }
-            xml.append("</key>");
-            xml.append(NSObject.NEWLINE);
-            val.toXML(xml, level + 1);
-            xml.append(NSObject.NEWLINE);
-        }
-        indent(xml, level);
-        xml.append("</dict>");
-    }
-
-    @Override
-    void assignIDs(BinaryPropertyListWriter out) {
-        super.assignIDs(out);
-        for (Map.Entry<String, NSObject> entry : dict.entrySet()) {
-            new NSString(entry.getKey()).assignIDs(out);
-        }
-        for (Map.Entry<String, NSObject> entry : dict.entrySet()) {
-            entry.getValue().assignIDs(out);
-        }
-    }
-
-    @Override
-    void toBinary(BinaryPropertyListWriter out) throws IOException {
-        out.writeIntHeader(0xD, dict.size());
-        Set<Map.Entry<String, NSObject>> entries = dict.entrySet();
-        for (Map.Entry<String, NSObject> entry : entries) {
-            out.writeID(out.getID(new NSString(entry.getKey())));
-        }
-        for (Map.Entry<String, NSObject> entry : entries) {
-            out.writeID(out.getID(entry.getValue()));
-        }
-    }
-
-    /**
-     * Generates a valid ASCII property list which has this NSDictionary as its
-     * root object. The generated property list complies with the format as
-     * described in <a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/PropertyLists/OldStylePlists/OldStylePLists.html">
-     * Property List Programming Guide - Old-Style ASCII Property Lists</a>.
-     *
-     * @return ASCII representation of this object.
-     */
-    public String toASCIIPropertyList() {
-        StringBuilder ascii = new StringBuilder();
-        toASCII(ascii, 0);
-        ascii.append(NEWLINE);
-        return ascii.toString();
-    }
-
-    /**
-     * Generates a valid ASCII property list in GnuStep format which has this
-     * NSDictionary as its root object. The generated property list complies with
-     * the format as described in <a href="http://www.gnustep.org/resources/documentation/Developer/Base/Reference/NSPropertyList.html">
-     * GnuStep - NSPropertyListSerialization class documentation
-     * </a>
-     *
-     * @return GnuStep ASCII representation of this object.
-     */
-    public String toGnuStepASCIIPropertyList() {
-        StringBuilder ascii = new StringBuilder();
-        toASCIIGnuStep(ascii, 0);
-        ascii.append(NEWLINE);
-        return ascii.toString();
-    }
-
-    @Override
-    protected void toASCII(StringBuilder ascii, int level) {
-        indent(ascii, level);
-        ascii.append(ASCIIPropertyListParser.DICTIONARY_BEGIN_TOKEN);
-        ascii.append(NEWLINE);
-        String[] keys = allKeys();
-        for (String key : keys) {
-            NSObject val = objectForKey(key);
-            indent(ascii, level + 1);
-            ascii.append("\"");
-            ascii.append(NSString.escapeStringForASCII(key));
-            ascii.append("\" =");
-            Class<?> objClass = val.getClass();
-            if (objClass.equals(NSDictionary.class) || objClass.equals(NSArray.class) || objClass.equals(NSData.class)) {
-                ascii.append(NEWLINE);
-                val.toASCII(ascii, level + 2);
-            } else {
-                ascii.append(" ");
-                val.toASCII(ascii, 0);
-            }
-            ascii.append(ASCIIPropertyListParser.DICTIONARY_ITEM_DELIMITER_TOKEN);
-            ascii.append(NEWLINE);
-        }
-        indent(ascii, level);
-        ascii.append(ASCIIPropertyListParser.DICTIONARY_END_TOKEN);
-    }
-
-    @Override
-    protected void toASCIIGnuStep(StringBuilder ascii, int level) {
-        indent(ascii, level);
-        ascii.append(ASCIIPropertyListParser.DICTIONARY_BEGIN_TOKEN);
-        ascii.append(NEWLINE);
-        String[] keys = dict.keySet().toArray(new String[dict.size()]);
-        for (String key : keys) {
-            NSObject val = objectForKey(key);
-            indent(ascii, level + 1);
-            ascii.append("\"");
-            ascii.append(NSString.escapeStringForASCII(key));
-            ascii.append("\" =");
-            Class<?> objClass = val.getClass();
-            if (objClass.equals(NSDictionary.class) || objClass.equals(NSArray.class) || objClass.equals(NSData.class)) {
-                ascii.append(NEWLINE);
-                val.toASCIIGnuStep(ascii, level + 2);
-            } else {
-                ascii.append(" ");
-                val.toASCIIGnuStep(ascii, 0);
-            }
-            ascii.append(ASCIIPropertyListParser.DICTIONARY_ITEM_DELIMITER_TOKEN);
-            ascii.append(NEWLINE);
-        }
-        indent(ascii, level);
-        ascii.append(ASCIIPropertyListParser.DICTIONARY_END_TOKEN);
-    }
-}
diff --git a/third_party/java/dd_plist/java/com/dd/plist/NSNumber.java b/third_party/java/dd_plist/java/com/dd/plist/NSNumber.java
deleted file mode 100644
index fab7d28..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/NSNumber.java
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * plist - An open source library to parse and generate property lists
- * Copyright (C) 2011 Daniel Dreibrodt, Keith Randall
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.dd.plist;
-
-import java.io.IOException;
-
-/**
- * A number whose value is either an integer, a real number or boolean.
- *
- * @author Daniel Dreibrodt
- */
-public class NSNumber extends NSObject implements Comparable<Object> {
-
-    /**
-     * Indicates that the number's value is an integer.
-     * The number is stored as a Java <code>long</code>.
-     * Its original value could have been char, short, int, long or even long long.
-     */
-    public static final int INTEGER = 0;
-
-    /**
-     * Indicates that the number's value is a real number.
-     * The number is stored as a Java <code>double</code>.
-     * Its original value could have been float or double.
-     */
-    public static final int REAL = 1;
-
-    /**
-     * Indicates that the number's value is boolean.
-     */
-    public static final int BOOLEAN = 2;
-
-    //Holds the current type of this number
-    private int type;
-
-    private long longValue;
-    private double doubleValue;
-    private boolean boolValue;
-
-    /**
-     * Parses integers and real numbers from their binary representation.
-     * <i>Note: real numbers are not yet supported.</i>
-     *
-     * @param bytes The binary representation of only this number
-     * @param type  The type of number
-     * @see #INTEGER
-     * @see #REAL
-     */
-    public NSNumber(byte[] bytes, int type){
-        this(bytes, 0, bytes.length, type);
-    }
-
-    /**
-     * Parses integers and real numbers from their binary representation.
-     * <i>Note: real numbers are not yet supported.</i>
-     *
-     * @param bytes array of bytes that contains this number's binary representation
-     * @param startIndex int with the position where to start reading from the byte array
-     * @param endIndex int with the position where to end reading from the byte array
-     * @param type  The type of number
-     * @see #INTEGER
-     * @see #REAL
-     */
-    public NSNumber(byte[] bytes, final int startIndex, final int endIndex, final int type){
-        switch (type) {
-            case INTEGER: {
-                doubleValue = longValue = BinaryPropertyListParser.parseLong(bytes, startIndex, endIndex);
-                break;
-            }
-            case REAL: {
-                doubleValue = BinaryPropertyListParser.parseDouble(bytes, startIndex, endIndex);
-                longValue = Math.round(doubleValue);
-                break;
-            }
-            default: {
-                throw new IllegalArgumentException("Type argument is not valid.");
-            }
-        }
-        this.type = type;
-    }
-
-    /**
-     * Creates a number from its textual representation.
-     *
-     * @param text The textual representation of the number.
-     * @throws IllegalArgumentException If the text does not represent an integer, real number or boolean value.
-     * @see Boolean#parseBoolean(java.lang.String)
-     * @see Long#parseLong(java.lang.String)
-     * @see Double#parseDouble(java.lang.String)
-     */
-    public NSNumber(String text) {
-        if (text == null)
-            throw new IllegalArgumentException("The given string is null and cannot be parsed as number.");
-        try {
-            long l = Long.parseLong(text);
-            doubleValue = longValue = l;
-            type = INTEGER;
-        } catch (Exception ex) {
-            try {
-                doubleValue = Double.parseDouble(text);
-                longValue = Math.round(doubleValue);
-                type = REAL;
-            } catch (Exception ex2) {
-                try {
-                    boolValue = text.toLowerCase().equals("true") || text.toLowerCase().equals("yes");
-                    if(!boolValue && !(text.toLowerCase().equals("false") || text.toLowerCase().equals("no"))) {
-                        throw new Exception("not a boolean");
-                    }
-                    type = BOOLEAN;
-                    doubleValue = longValue = boolValue ? 1 : 0;
-                } catch (Exception ex3) {
-                    throw new IllegalArgumentException("The given string neither represents a double, an int nor a boolean value.");
-                }
-            }
-        }
-    }
-
-    /**
-     * Creates an integer number.
-     *
-     * @param i The integer value.
-     */
-    public NSNumber(int i) {
-        doubleValue = longValue = i;
-        type = INTEGER;
-    }
-
-    /**
-     * Creates an integer number.
-     *
-     * @param l The long integer value.
-     */
-    public NSNumber(long l) {
-        doubleValue = longValue = l;
-        type = INTEGER;
-    }
-
-    /**
-     * Creates a real number.
-     *
-     * @param d The real value.
-     */
-    public NSNumber(double d) {
-        longValue = (long) (doubleValue = d);
-        type = REAL;
-    }
-
-    /**
-     * Creates a boolean number.
-     *
-     * @param b The boolean value.
-     */
-    public NSNumber(boolean b) {
-        boolValue = b;
-        doubleValue = longValue = b ? 1 : 0;
-        type = BOOLEAN;
-    }
-
-    /**
-     * Gets the type of this number's value.
-     *
-     * @return The type flag.
-     * @see #BOOLEAN
-     * @see #INTEGER
-     * @see #REAL
-     */
-    public int type() {
-        return type;
-    }
-
-    /**
-     * Checks whether the value of this NSNumber is a boolean.
-     *
-     * @return Whether the number's value is a boolean.
-     */
-    public boolean isBoolean() {
-        return type == BOOLEAN;
-    }
-
-    /**
-     * Checks whether the value of this NSNumber is an integer.
-     *
-     * @return Whether the number's value is an integer.
-     */
-    public boolean isInteger() {
-        return type == INTEGER;
-    }
-
-    /**
-     * Checks whether the value of this NSNumber is a real number.
-     *
-     * @return Whether the number's value is a real number.
-     */
-    public boolean isReal() {
-        return type == REAL;
-    }
-
-    /**
-     * The number's boolean value.
-     *
-     * @return <code>true</code> if the value is true or non-zero, <code>false</code> otherwise.
-     */
-    public boolean boolValue() {
-        if (type == BOOLEAN)
-            return boolValue;
-        else
-            return longValue != 0;
-    }
-
-    /**
-     * The number's long value.
-     *
-     * @return The value of the number as long
-     */
-    public long longValue() {
-        return longValue;
-    }
-
-    /**
-     * The number's int value.
-     * <i>Note: Even though the number's type might be INTEGER it can be larger than a Java int.
-     * Use intValue() only if you are certain that it contains a number from the int range.
-     * Otherwise the value might be innaccurate.</i>
-     *
-     * @return The value of the number as int
-     */
-    public int intValue() {
-        return (int) longValue;
-    }
-
-    /**
-     * The number's double value.
-     *
-     * @return The value of the number as double.
-     */
-    public double doubleValue() {
-        return doubleValue;
-    }
-
-    /**
-     * The number's float value.
-     * WARNING: Possible loss of precision if the value is outside the float range.
-     *
-     * @return The value of the number as float.
-     */
-    public float floatValue() {
-        return (float) doubleValue;
-    }
-
-    /**
-     * Checks whether the other object is a NSNumber of the same value.
-     *
-     * @param obj The object to compare to.
-     * @return Whether the objects are equal in terms of numeric value and type.
-     */
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof NSNumber)) return false;
-        NSNumber n = (NSNumber) obj;
-        return type == n.type && longValue == n.longValue && doubleValue == n.doubleValue && boolValue == n.boolValue;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = type;
-        hash = 37 * hash + (int) (this.longValue ^ (this.longValue >>> 32));
-        hash = 37 * hash + (int) (Double.doubleToLongBits(this.doubleValue) ^ (Double.doubleToLongBits(this.doubleValue) >>> 32));
-        hash = 37 * hash + (boolValue() ? 1 : 0);
-        return hash;
-    }
-
-
-    @Override
-    public String toString() {
-        switch (type) {
-            case INTEGER: {
-                return String.valueOf(longValue());
-            }
-            case REAL: {
-                return String.valueOf(doubleValue());
-            }
-            case BOOLEAN: {
-                return String.valueOf(boolValue());
-            }
-            default: {
-                return super.toString();
-            }
-        }
-    }
-
-    @Override
-    void toXML(StringBuilder xml, int level) {
-        indent(xml, level);
-        switch (type) {
-            case INTEGER: {
-                xml.append("<integer>");
-                xml.append(longValue());
-                xml.append("</integer>");
-                break;
-            }
-            case REAL: {
-                xml.append("<real>");
-                xml.append(doubleValue());
-                xml.append("</real>");
-                break;
-            }
-            case BOOLEAN: {
-                if (boolValue())
-                    xml.append("<true/>");
-                else
-                    xml.append("<false/>");
-                break;
-            }
-        }
-    }
-
-    @Override
-    void toBinary(BinaryPropertyListWriter out) throws IOException {
-        switch (type()) {
-            case INTEGER: {
-                if (longValue() < 0) {
-                    out.write(0x13);
-                    out.writeBytes(longValue(), 8);
-                } else if (longValue() <= 0xff) {
-                    out.write(0x10);
-                    out.writeBytes(longValue(), 1);
-                } else if (longValue() <= 0xffff) {
-                    out.write(0x11);
-                    out.writeBytes(longValue(), 2);
-                } else if (longValue() <= 0xffffffffL) {
-                    out.write(0x12);
-                    out.writeBytes(longValue(), 4);
-                } else {
-                    out.write(0x13);
-                    out.writeBytes(longValue(), 8);
-                }
-                break;
-            }
-            case REAL: {
-                out.write(0x23);
-                out.writeDouble(doubleValue());
-                break;
-            }
-            case BOOLEAN: {
-                out.write(boolValue() ? 0x09 : 0x08);
-                break;
-            }
-        }
-    }
-
-    @Override
-    protected void toASCII(StringBuilder ascii, int level) {
-        indent(ascii, level);
-        if (type == BOOLEAN) {
-            ascii.append(boolValue ? "YES" : "NO");
-        } else {
-            ascii.append(toString());
-        }
-    }
-
-    @Override
-    protected void toASCIIGnuStep(StringBuilder ascii, int level) {
-        indent(ascii, level);
-        switch (type) {
-            case INTEGER: {
-                ascii.append("<*I");
-                ascii.append(toString());
-                ascii.append(">");
-                break;
-            }
-            case REAL: {
-                ascii.append("<*R");
-                ascii.append(toString());
-                ascii.append(">");
-                break;
-            }
-            case BOOLEAN: {
-                if (boolValue) {
-                    ascii.append("<*BY>");
-                } else {
-                    ascii.append("<*BN>");
-                }
-            }
-        }
-    }
-
-    public int compareTo(Object o) {
-        double x = doubleValue();
-        double y;
-        if (o instanceof NSNumber) {
-            NSNumber num = (NSNumber) o;
-            y = num.doubleValue();
-            return (x < y) ? -1 : ((x == y) ? 0 : 1);
-        } else if (o instanceof Number) {
-            y = ((Number) o).doubleValue();
-            return (x < y) ? -1 : ((x == y) ? 0 : 1);
-        } else {
-            return -1;
-        }
-    }
-}
diff --git a/third_party/java/dd_plist/java/com/dd/plist/NSObject.java b/third_party/java/dd_plist/java/com/dd/plist/NSObject.java
deleted file mode 100644
index b2c3cf0..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/NSObject.java
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * plist - An open source library to parse and generate property lists
- * Copyright (C) 2014 Daniel Dreibrodt
- *
-* Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package com.dd.plist;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectOutputStream;
-import java.util.*;
-
-/**
- * Abstract interface for any object contained in a property list.
- * The names and functions of the various objects orient themselves
- * towards Apple's Cocoa API.
- *
- * @author Daniel Dreibrodt
- */
-public abstract class NSObject {
-
-    /**
-     * The newline character used for generating the XML output.
-     * This constant will be different depending on the operating system on
-     * which you use this library.
-     */
-    final static String NEWLINE = System.getProperty("line.separator");
-
-    /**
-     * The identation character used for generating the XML output. This is the
-     * tabulator character.
-     */
-    final static String INDENT = "\t";
-
-    /**
-     * The maximum length of the text lines to be used when generating
-     * ASCII property lists. But this number is only a guideline it is not
-     * guaranteed that it will not be overstepped.
-     */
-    final static int ASCII_LINE_LENGTH = 80;
-
-    /**
-     * Generates the XML representation of the object (without XML headers or enclosing plist-tags).
-     *
-     * @param xml   The StringBuilder onto which the XML representation is appended.
-     * @param level The indentation level of the object.
-     */
-    abstract void toXML(StringBuilder xml, int level);
-
-    /**
-     * Assigns IDs to all the objects in this NSObject subtree.
-     *
-     * @param out The writer object that handles the binary serialization.
-     */
-    void assignIDs(BinaryPropertyListWriter out) {
-        out.assignID(this);
-    }
-
-    /**
-     * Generates the binary representation of the object.
-     *
-     * @param out The output stream to serialize the object to.
-     * @throws java.io.IOException When an IO error occurs while writing to the stream or the object structure contains
-     *                             data that cannot be saved.
-     */
-    abstract void toBinary(BinaryPropertyListWriter out) throws IOException;
-
-    /**
-     * Generates a valid XML property list including headers using this object as root.
-     *
-     * @return The XML representation of the property list including XML header and doctype information.
-     */
-    public String toXMLPropertyList() {
-        StringBuilder xml = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
-        xml.append(NSObject.NEWLINE);
-        xml.append("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
-        xml.append(NSObject.NEWLINE);
-        xml.append("<plist version=\"1.0\">");
-        xml.append(NSObject.NEWLINE);
-        toXML(xml, 0);
-        xml.append(NSObject.NEWLINE);
-        xml.append("</plist>");
-        return xml.toString();
-    }
-
-    /**
-     * Generates the ASCII representation of this object.
-     * The generated ASCII representation does not end with a newline.
-     * Complies with https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/PropertyLists/OldStylePlists/OldStylePLists.html
-     *
-     * @param ascii The StringBuilder onto which the ASCII representation is appended.
-     * @param level The indentation level of the object.
-     */
-    protected abstract void toASCII(StringBuilder ascii, int level);
-
-    /**
-     * Generates the ASCII representation of this object in the GnuStep format.
-     * The generated ASCII representation does not end with a newline.
-     *
-     * @param ascii The StringBuilder onto which the ASCII representation is appended.
-     * @param level The indentation level of the object.
-     */
-    protected abstract void toASCIIGnuStep(StringBuilder ascii, int level);
-
-    /**
-     * Helper method that adds correct identation to the xml output.
-     * Calling this method will add <code>level</code> number of tab characters
-     * to the <code>xml</code> string.
-     *
-     * @param xml   The string builder for the XML document.
-     * @param level The level of identation.
-     */
-    void indent(StringBuilder xml, int level) {
-        for (int i = 0; i < level; i++)
-            xml.append(INDENT);
-    }
-
-    /**
-     * Wraps the given value inside a NSObject.
-     *
-     * @param value The value to represent as a NSObject.
-     * @return A NSObject representing the given value.
-     */
-    public static NSNumber wrap(long value) {
-        return new NSNumber(value);
-    }
-
-    /**
-     * Wraps the given value inside a NSObject.
-     *
-     * @param value The value to represent as a NSObject.
-     * @return A NSObject representing the given value.
-     */
-    public static NSNumber wrap(double value) {
-        return new NSNumber(value);
-    }
-
-    /**
-     * Wraps the given value inside a NSObject.
-     *
-     * @param value The value to represent as a NSObject.
-     * @return A NSObject representing the given value.
-     */
-    public static NSNumber wrap(boolean value) {
-        return new NSNumber(value);
-    }
-
-    /**
-     * Wraps the given value inside a NSObject.
-     *
-     * @param value The value to represent as a NSObject.
-     * @return A NSObject representing the given value.
-     */
-    public static NSData wrap(byte[] value) {
-        return new NSData(value);
-    }
-
-    /**
-     * Creates a NSArray with the contents of the given array.
-     *
-     * @param value The value to represent as a NSObject.
-     * @return A NSObject representing the given value.
-     * @throws RuntimeException When one of the objects contained in the array cannot be represented by a NSObject.
-     */
-    public static NSArray wrap(Object[] value) {
-        NSArray arr = new NSArray(value.length);
-        for (int i = 0; i < value.length; i++) {
-            arr.setValue(i, wrap(value[i]));
-        }
-        return arr;
-    }
-
-    /**
-     * Creates a NSDictionary with the contents of the given map.
-     *
-     * @param value The value to represent as a NSObject.
-     * @return A NSObject representing the given value.
-     * @throws RuntimeException When one of the values contained in the map cannot be represented by a NSObject.
-     */
-    public static NSDictionary wrap(Map<String, Object> value) {
-        NSDictionary dict = new NSDictionary();
-        for (String key : value.keySet())
-            dict.put(key, wrap(value.get(key)));
-        return dict;
-    }
-
-    /**
-     * Creates a NSSet with the contents of this set.
-     *
-     * @param value The value to represent as a NSObject.
-     * @return A NSObject representing the given value.
-     * @throws RuntimeException When one of the values contained in the set cannot be represented by a NSObject.
-     */
-    public static NSSet wrap(Set<Object> value) {
-        NSSet set = new NSSet();
-        for (Object o : value.toArray())
-            set.addObject(wrap(o));
-        return set;
-    }
-
-    /**
-     * Creates a NSObject representing the given Java Object.
-     *
-     * Numerics of type bool, int, long, short, byte, float or double are wrapped as NSNumber objects.
-     *
-     * Strings are wrapped as NSString objects abd byte arrays as NSData objects.
-     *
-     * Date objects are wrapped as NSDate objects.
-     *
-     * Serializable classes are serialized and their data is stored in NSData objects.
-     *
-     * Arrays and Collection objects are converted to NSArrays where each array member is wrapped into a NSObject.
-     *
-     * Map objects are converted to NSDictionaries. Each key is converted to a string and each value wrapped into a NSObject.
-     *
-     * @param o The object to represent.
-     * @return A NSObject equivalent to the given object.
-     */
-    public static NSObject wrap(Object o) {
-        if(o == null)
-            return null;
-
-        if(o instanceof NSObject)
-            return (NSObject)o;
-
-        Class<?> c = o.getClass();
-        if (Boolean.class.equals(c)) {
-            return wrap((boolean) (Boolean) o);
-        }
-        if (Byte.class.equals(c)) {
-            return wrap((int) (Byte) o);
-        }
-        if (Short.class.equals(c)) {
-            return wrap((int) (Short) o);
-        }
-        if (Integer.class.equals(c)) {
-            return wrap((int) (Integer) o);
-        }
-        if (Long.class.isAssignableFrom(c)) {
-            return wrap((long) (Long) o);
-        }
-        if (Float.class.equals(c)) {
-            return wrap((double) (Float) o);
-        }
-        if (Double.class.isAssignableFrom(c)) {
-            return wrap((double) (Double) o);
-        }
-        if (String.class.equals(c)) {
-            return new NSString((String)o);
-        }
-        if (Date.class.equals(c)) {
-            return new NSDate((Date)o);
-        }
-        if(c.isArray()) {
-            Class<?> cc = c.getComponentType();
-            if (cc.equals(byte.class)) {
-                return wrap((byte[]) o);
-            }
-            else if(cc.equals(boolean.class)) {
-                boolean[] array = (boolean[])o;
-                NSArray nsa = new NSArray(array.length);
-                for(int i=0;i<array.length;i++)
-                    nsa.setValue(i, wrap(array[i]));
-                return nsa;
-            }
-            else if(float.class.equals(cc)) {
-                float[] array = (float[])o;
-                NSArray nsa = new NSArray(array.length);
-                for(int i=0;i<array.length;i++)
-                    nsa.setValue(i, wrap(array[i]));
-                return nsa;
-            }
-            else if(double.class.equals(cc)) {
-                double[] array = (double[])o;
-                NSArray nsa = new NSArray(array.length);
-                for(int i=0;i<array.length;i++)
-                    nsa.setValue(i, wrap(array[i]));
-                return nsa;
-            }
-            else if(short.class.equals(cc)) {
-                short[] array = (short[])o;
-                NSArray nsa = new NSArray(array.length);
-                for(int i=0;i<array.length;i++)
-                    nsa.setValue(i, wrap(array[i]));
-                return nsa;
-            }
-            else if(int.class.equals(cc)) {
-                int[] array = (int[])o;
-                NSArray nsa = new NSArray(array.length);
-                for(int i=0;i<array.length;i++)
-                    nsa.setValue(i, wrap(array[i]));
-                return nsa;
-            }
-            else if(long.class.equals(cc)) {
-                long[] array = (long[])o;
-                NSArray nsa = new NSArray(array.length);
-                for(int i=0;i<array.length;i++)
-                    nsa.setValue(i, wrap(array[i]));
-                return nsa;
-            }
-            else {
-                return wrap((Object[]) o);
-            }
-        }
-        if (Map.class.isAssignableFrom(c)) {
-            Map map = (Map)o;
-            Set keys = map.keySet();
-            NSDictionary dict = new NSDictionary();
-            for(Object key:keys) {
-                Object val = map.get(key);
-                dict.put(String.valueOf(key), wrap(val));
-            }
-            return dict;
-        }
-        if (Collection.class.isAssignableFrom(c)) {
-            Collection coll = (Collection)o;
-            return wrap(coll.toArray());
-        }
-        return wrapSerialized(o);
-    }
-
-    /**
-     * Serializes the given object using Java's default object serialization
-     * and wraps the serialized object in a NSData object.
-     *
-     * @param o The object to serialize and wrap.
-     * @return A NSData object
-     * @throws RuntimeException When the object could not be serialized.
-     */
-    public static NSData wrapSerialized(Object o) {
-        try {
-            ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            ObjectOutputStream oos = new ObjectOutputStream(baos);
-            oos.writeObject(o);
-            return new NSData(baos.toByteArray());
-        } catch (IOException ex) {
-            throw new RuntimeException("The given object of class " + o.getClass().toString() + " could not be serialized and stored in a NSData object.");
-        }
-    }
-
-    /**
-     * Converts this NSObject into an equivalent object
-     * of the Java Runtime Environment.
-     * <ul>
-     * <li>NSArray objects are converted to arrays.</li>
-     * <li>NSDictionary objects are converted to objects extending the java.util.Map class.</li>
-     * <li>NSSet objects are converted to objects extending the java.util.Set class.</li>
-     * <li>NSNumber objects are converted to primitive number values (int, long, double or boolean).</li>
-     * <li>NSString objects are converted to String objects.</li>
-     * <li>NSData objects are converted to byte arrays.</li>
-     * <li>NSDate objects are converted to java.util.Date objects.</li>
-     * <li>UID objects are converted to byte arrays.</li>
-     * </ul>
-     * @return A native java object representing this NSObject's value.
-     */
-    public Object toJavaObject() {
-        if(this instanceof NSArray) {
-            NSObject[] arrayA = ((NSArray)this).getArray();
-            Object[] arrayB = new Object[arrayA.length];
-            for(int i = 0; i < arrayA.length; i++) {
-                arrayB[i] = arrayA[i].toJavaObject();
-            }
-            return arrayB;
-        } else if (this instanceof NSDictionary) {
-            HashMap<String, NSObject> hashMapA = ((NSDictionary)this).getHashMap();
-            HashMap<String, Object> hashMapB = new HashMap<String, Object>(hashMapA.size());
-            for(String key:hashMapA.keySet()) {
-                hashMapB.put(key, hashMapA.get(key).toJavaObject());
-            }
-            return hashMapB;
-        } else if(this instanceof NSSet) {
-            Set<NSObject> setA = ((NSSet)this).getSet();
-            Set<Object> setB;
-            if(setA instanceof LinkedHashSet) {
-                setB = new LinkedHashSet<Object>(setA.size());
-            } else {
-                setB = new TreeSet<Object>();
-            }
-            for(NSObject o:setA) {
-                setB.add(o.toJavaObject());
-            }
-            return setB;
-        } else if(this instanceof NSNumber) {
-            NSNumber num = (NSNumber)this;
-            switch(num.type()) {
-                case NSNumber.INTEGER : {
-                    long longVal = num.longValue();
-                    if(longVal > Integer.MAX_VALUE || longVal < Integer.MIN_VALUE) {
-                        return longVal;
-                    } else {
-                        return num.intValue();
-                    }
-                }
-                case NSNumber.REAL : {
-                    return num.doubleValue();
-                }
-                case NSNumber.BOOLEAN : {
-                    return num.boolValue();
-                }
-                default : {
-                    return num.doubleValue();
-                }
-            }
-        } else if(this instanceof NSString) {
-            return ((NSString)this).getContent();
-        } else if(this instanceof NSData) {
-            return ((NSData)this).bytes();
-        } else if(this instanceof NSDate) {
-            return ((NSDate)this).getDate();
-        } else if(this instanceof UID) {
-            return ((UID)this).getBytes();
-        } else {
-            return this;
-        }
-    }
-}
diff --git a/third_party/java/dd_plist/java/com/dd/plist/NSSet.java b/third_party/java/dd_plist/java/com/dd/plist/NSSet.java
deleted file mode 100644
index 6e43151..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/NSSet.java
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * plist - An open source library to parse and generate property lists
- * Copyright (C) 2011 Daniel Dreibrodt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.dd.plist;
-
-import java.io.IOException;
-import java.util.*;
-
-/**
- * A set is an interface to an unordered collection of objects.
- * This implementation uses a <code>LinkedHashSet</code> or <code>TreeSet</code>as the underlying
- * data structure.
- *
- * @author Daniel Dreibrodt
- * @see LinkedHashSet
- */
-public class NSSet extends NSObject {
-
-    private Set<NSObject> set;
-
-    private boolean ordered = false;
-
-    /**
-     * Creates an empty unordered set.
-     *
-     * @see java.util.LinkedHashSet
-     */
-    public NSSet() {
-        set = new LinkedHashSet<NSObject>();
-    }
-
-    /**
-     * Creates an empty set.
-     *
-     * @param ordered Indicates whether the created set should be ordered or unordered.
-     * @see java.util.LinkedHashSet
-     * @see java.util.TreeSet
-     */
-    public NSSet(boolean ordered) {
-        this.ordered = ordered;
-        if (!ordered)
-            set = new LinkedHashSet<NSObject>();
-        else
-            set = new TreeSet<NSObject>();
-    }
-
-    /**
-     * Create a set and fill it with the given objects.
-     *
-     * @param objects The objects to populate the set.
-     * @see java.util.LinkedHashSet
-     */
-    public NSSet(NSObject... objects) {
-        set = new LinkedHashSet<NSObject>();
-        set.addAll(Arrays.asList(objects));
-    }
-
-    /**
-     * Create a set and fill it with the given objects.
-     *
-     * @param ordered Indicates whether the created set should be ordered or unordered.
-     * @param objects The objects to populate the set.
-     * @see java.util.LinkedHashSet
-     * @see java.util.TreeSet
-     */
-    public NSSet(boolean ordered, NSObject... objects) {
-        this.ordered = ordered;
-        if (!ordered)
-            set = new LinkedHashSet<NSObject>();
-        else
-            set = new TreeSet<NSObject>();
-        set.addAll(Arrays.asList(objects));
-    }
-
-    /**
-     * Adds an object to the set.
-     *
-     * @param obj The object to add.
-     */
-    public synchronized void addObject(NSObject obj) {
-        set.add(obj);
-    }
-
-    /**
-     * Removes an object from the set.
-     *
-     * @param obj The object to remove.
-     */
-    public synchronized void removeObject(NSObject obj) {
-        set.remove(obj);
-    }
-
-    /**
-     * Returns all objects contained in the set.
-     *
-     * @return An array of all objects in the set.
-     */
-    public synchronized NSObject[] allObjects() {
-        return set.toArray(new NSObject[count()]);
-    }
-
-    /**
-     * Returns one of the objects in the set, or <code>null</code>
-     * if the set contains no objects.
-     *
-     * @return The first object in the set, or <code>null</code> if the set is empty.
-     */
-    public synchronized NSObject anyObject() {
-        if (set.isEmpty())
-            return null;
-        else
-            return set.iterator().next();
-    }
-
-    /**
-     * Finds out whether a given object is contained in the set.
-     *
-     * @param obj The object to look for.
-     * @return <code>true</code>, when the object was found, <code>false</code> otherwise.
-     */
-    public boolean containsObject(NSObject obj) {
-        return set.contains(obj);
-    }
-
-    /**
-     * Determines whether the set contains an object equal to a given object
-     * and returns that object if it is present.
-     *
-     * @param obj The object to look for.
-     * @return The object if it is present, <code>null</code> otherwise.
-     */
-    public synchronized NSObject member(NSObject obj) {
-        for (NSObject o : set) {
-            if (o.equals(obj))
-                return o;
-        }
-        return null;
-    }
-
-    /**
-     * Finds out whether at least one object is present in both sets.
-     *
-     * @param otherSet The other set.
-     * @return <code>false</code> if the intersection of both sets is empty, <code>true</code> otherwise.
-     */
-    public synchronized boolean intersectsSet(NSSet otherSet) {
-        for (NSObject o : set) {
-            if (otherSet.containsObject(o))
-                return true;
-        }
-        return false;
-    }
-
-    /**
-     * Finds out if this set is a subset of the given set.
-     *
-     * @param otherSet The other set.
-     * @return <code>true</code> if all elements in this set are also present in the other set, <code>false</code> otherwise.
-     */
-    public synchronized boolean isSubsetOfSet(NSSet otherSet) {
-        for (NSObject o : set) {
-            if (!otherSet.containsObject(o))
-                return false;
-        }
-        return true;
-    }
-
-    /**
-     * Returns an iterator object that lets you iterate over all elements of the set.
-     * This is the equivalent to <code>objectEnumerator</code> in the Cocoa implementation
-     * of NSSet.
-     *
-     * @return The iterator for the set.
-     */
-    public synchronized Iterator<NSObject> objectIterator() {
-        return set.iterator();
-    }
-
-    /**
-     * Gets the underlying data structure in which this NSSets stores its content.
-     * @return A Set object.
-     */
-    Set<NSObject> getSet() {
-        return set;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 7;
-        hash = 29 * hash + (this.set != null ? this.set.hashCode() : 0);
-        return hash;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        final NSSet other = (NSSet) obj;
-        return !(this.set != other.set && (this.set == null || !this.set.equals(other.set)));
-    }
-
-    /**
-     * Gets the number of elements in the set.
-     *
-     * @return The number of elements in the set.
-     * @see Set#size()
-     */
-    public synchronized int count() {
-        return set.size();
-    }
-
-    /**
-     * Returns the XML representantion for this set.
-     * There is no official XML representation specified for sets.
-     * In this implementation it is represented by an array.
-     *
-     * @param xml   The XML StringBuilder
-     * @param level The indentation level
-     */
-    @Override
-    void toXML(StringBuilder xml, int level) {
-        indent(xml, level);
-        xml.append("<array>");
-        xml.append(NSObject.NEWLINE);
-        for (NSObject o : set) {
-            o.toXML(xml, level + 1);
-            xml.append(NSObject.NEWLINE);
-        }
-        indent(xml, level);
-        xml.append("</array>");
-    }
-
-    @Override
-    void assignIDs(BinaryPropertyListWriter out) {
-        super.assignIDs(out);
-        for (NSObject obj : set) {
-            obj.assignIDs(out);
-        }
-    }
-
-    @Override
-    void toBinary(BinaryPropertyListWriter out) throws IOException {
-        if (ordered) {
-            out.writeIntHeader(0xB, set.size());
-        } else {
-            out.writeIntHeader(0xC, set.size());
-        }
-        for (NSObject obj : set) {
-            out.writeID(out.getID(obj));
-        }
-    }
-
-    /**
-     * Returns the ASCII representation of this set.
-     * There is no official ASCII representation for sets.
-     * In this implementation sets are represented as arrays.
-     *
-     * @param ascii The ASCII file string builder
-     * @param level The indentation level
-     */
-    @Override
-    protected void toASCII(StringBuilder ascii, int level) {
-        indent(ascii, level);
-        NSObject[] array = allObjects();
-        ascii.append(ASCIIPropertyListParser.ARRAY_BEGIN_TOKEN);
-        int indexOfLastNewLine = ascii.lastIndexOf(NEWLINE);
-        for (int i = 0; i < array.length; i++) {
-            Class<?> objClass = array[i].getClass();
-            if ((objClass.equals(NSDictionary.class) || objClass.equals(NSArray.class) || objClass.equals(NSData.class))
-                    && indexOfLastNewLine != ascii.length()) {
-                ascii.append(NEWLINE);
-                indexOfLastNewLine = ascii.length();
-                array[i].toASCII(ascii, level + 1);
-            } else {
-                if (i != 0)
-                    ascii.append(" ");
-                array[i].toASCII(ascii, 0);
-            }
-
-            if (i != array.length - 1)
-                ascii.append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
-
-            if (ascii.length() - indexOfLastNewLine > ASCII_LINE_LENGTH) {
-                ascii.append(NEWLINE);
-                indexOfLastNewLine = ascii.length();
-            }
-        }
-        ascii.append(ASCIIPropertyListParser.ARRAY_END_TOKEN);
-    }
-
-    /**
-     * Returns the ASCII representation of this set according to the GnuStep format.
-     * There is no official ASCII representation for sets.
-     * In this implementation sets are represented as arrays.
-     *
-     * @param ascii The ASCII file string builder
-     * @param level The indentation level
-     */
-    @Override
-    protected void toASCIIGnuStep(StringBuilder ascii, int level) {
-        indent(ascii, level);
-        NSObject[] array = allObjects();
-        ascii.append(ASCIIPropertyListParser.ARRAY_BEGIN_TOKEN);
-        int indexOfLastNewLine = ascii.lastIndexOf(NEWLINE);
-        for (int i = 0; i < array.length; i++) {
-            Class<?> objClass = array[i].getClass();
-            if ((objClass.equals(NSDictionary.class) || objClass.equals(NSArray.class) || objClass.equals(NSData.class))
-                    && indexOfLastNewLine != ascii.length()) {
-                ascii.append(NEWLINE);
-                indexOfLastNewLine = ascii.length();
-                array[i].toASCIIGnuStep(ascii, level + 1);
-            } else {
-                if (i != 0)
-                    ascii.append(" ");
-                array[i].toASCIIGnuStep(ascii, 0);
-            }
-
-            if (i != array.length - 1)
-                ascii.append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN);
-
-            if (ascii.length() - indexOfLastNewLine > ASCII_LINE_LENGTH) {
-                ascii.append(NEWLINE);
-                indexOfLastNewLine = ascii.length();
-            }
-        }
-        ascii.append(ASCIIPropertyListParser.ARRAY_END_TOKEN);
-    }
-
-}
diff --git a/third_party/java/dd_plist/java/com/dd/plist/NSString.java b/third_party/java/dd_plist/java/com/dd/plist/NSString.java
deleted file mode 100644
index e5f5e6c..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/NSString.java
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * plist - An open source library to parse and generate property lists
- * Copyright (C) 2011 Daniel Dreibrodt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package com.dd.plist;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetEncoder;
-
-/**
- * A NSString contains a string.
- *
- * @author Daniel Dreibrodt
- */
-public class NSString extends NSObject implements Comparable<Object> {
-
-    private String content;
-
-    /**
-     * Creates an NSString from its binary representation.
-     *
-     * @param bytes    The binary representation.
-     * @param encoding The encoding of the binary representation, the name of a supported charset.
-     * @throws UnsupportedEncodingException When the given encoding is not supported by the JRE.
-     * @see java.lang.String#String(byte[], String)
-     */
-    public NSString(byte[] bytes, String encoding) throws UnsupportedEncodingException {
-        this(bytes, 0, bytes.length, encoding);
-    }
-
-    /**
-     * Creates an NSString from its binary representation.
-     *
-     * @param bytes The binary representation.
-     * @param startIndex int with the index where to start (offset)
-     * @param endIndex int with the index where to stop reading (offset + string length)
-     * @param encoding The encoding of the binary representation, the name of a supported charset.
-     * @throws UnsupportedEncodingException When the given encoding is not supported by the JRE.
-     * @see java.lang.String#String(byte[], String)
-     */
-    public NSString(byte[] bytes, final int startIndex, final int endIndex, String encoding) throws UnsupportedEncodingException {
-        content = new String(bytes, startIndex, endIndex - startIndex, encoding);
-    }
-
-    /**
-     * Creates a NSString from a string.
-     *
-     * @param string The string that will be contained in the NSString.
-     */
-    public NSString(String string) {
-        content = string;
-    }
-
-    /**
-     * Gets this strings content.
-     *
-     * @return This NSString as Java String object.
-     */
-    public String getContent() {
-        return content;
-    }
-
-    /**
-     * Sets the contents of this string.
-     *
-     * @param c The new content of this string object.
-     */
-    public void setContent(String c) {
-        content = c;
-    }
-
-    /**
-     * Appends a string to this string.
-     *
-     * @param s The string to append.
-     */
-    public void append(NSString s) {
-        append(s.getContent());
-    }
-
-    /**
-     * Appends a string to this string.
-     *
-     * @param s The string to append.
-     */
-    public void append(String s) {
-        content += s;
-    }
-
-    /**
-     * Prepends a string to this string.
-     *
-     * @param s The string to prepend.
-     */
-    public void prepend(String s) {
-        content = s + content;
-    }
-
-    /**
-     * Prepends a string to this string.
-     *
-     * @param s The string to prepend.
-     */
-    public void prepend(NSString s) {
-        prepend(s.getContent());
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof NSString)) return false;
-        return content.equals(((NSString) obj).content);
-    }
-
-    @Override
-    public int hashCode() {
-        return content.hashCode();
-    }
-
-    /**
-     * The textual representation of this NSString.
-     *
-     * @return The NSString's contents.
-     */
-    @Override
-    public String toString() {
-        return content;
-    }
-
-    private static CharsetEncoder asciiEncoder, utf16beEncoder, utf8Encoder;
-
-    @Override
-    void toXML(StringBuilder xml, int level) {
-        indent(xml, level);
-        xml.append("<string>");
-
-        //Make sure that the string is encoded in UTF-8 for the XML output
-        synchronized (NSString.class) {
-            if (utf8Encoder == null)
-                utf8Encoder = Charset.forName("UTF-8").newEncoder();
-            else
-                utf8Encoder.reset();
-
-            try {
-                ByteBuffer byteBuf = utf8Encoder.encode(CharBuffer.wrap(content));
-                byte[] bytes = new byte[byteBuf.remaining()];
-                byteBuf.get(bytes);
-                content = new String(bytes, "UTF-8");
-            } catch (Exception ex) {
-                throw new RuntimeException("Could not encode the NSString into UTF-8: " + String.valueOf(ex.getMessage()));
-            }
-        }
-
-        //According to http://www.w3.org/TR/REC-xml/#syntax node values must not
-        //contain the characters < or &. Also the > character should be escaped.
-        if (content.contains("&") || content.contains("<") || content.contains(">")) {
-            xml.append("<![CDATA[");
-            xml.append(content.replaceAll("]]>", "]]]]><![CDATA[>"));
-            xml.append("]]>");
-        } else {
-            xml.append(content);
-        }
-        xml.append("</string>");
-    }
-
-
-    @Override
-    public void toBinary(BinaryPropertyListWriter out) throws IOException {
-        CharBuffer charBuf = CharBuffer.wrap(content);
-        int kind;
-        ByteBuffer byteBuf;
-        synchronized (NSString.class) {
-            if (asciiEncoder == null)
-                asciiEncoder = Charset.forName("ASCII").newEncoder();
-            else
-                asciiEncoder.reset();
-
-            if (asciiEncoder.canEncode(charBuf)) {
-                kind = 0x5; // standard ASCII
-                byteBuf = asciiEncoder.encode(charBuf);
-            } else {
-                if (utf16beEncoder == null)
-                    utf16beEncoder = Charset.forName("UTF-16BE").newEncoder();
-                else
-                    utf16beEncoder.reset();
-
-                kind = 0x6; // UTF-16-BE
-                byteBuf = utf16beEncoder.encode(charBuf);
-            }
-        }
-        byte[] bytes = new byte[byteBuf.remaining()];
-        byteBuf.get(bytes);
-        out.writeIntHeader(kind, content.length());
-        out.write(bytes);
-    }
-
-    @Override
-    protected void toASCII(StringBuilder ascii, int level) {
-        indent(ascii, level);
-        ascii.append("\"");
-        //According to https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/PropertyLists/OldStylePlists/OldStylePLists.html
-        //non-ASCII characters are not escaped but simply written into the
-        //file, thus actually violating the ASCII plain text format.
-        //We will escape the string anyway because current Xcode project files (ASCII property lists) also escape their strings.
-        ascii.append(escapeStringForASCII(content));
-        ascii.append("\"");
-    }
-
-    @Override
-    protected void toASCIIGnuStep(StringBuilder ascii, int level) {
-        indent(ascii, level);
-        ascii.append("\"");
-        ascii.append(escapeStringForASCII(content));
-        ascii.append("\"");
-    }
-
-    /**
-     * Escapes a string for use in ASCII property lists.
-     *
-     * @param s The unescaped string.
-     * @return The escaped string.
-     */
-    static String escapeStringForASCII(String s) {
-        String out = "";
-        char[] cArray = s.toCharArray();
-        for (int i = 0; i < cArray.length; i++) {
-            char c = cArray[i];
-            if (c > 127) {
-                //non-ASCII Unicode
-                out += "\\U";
-                String hex = Integer.toHexString(c);
-                while (hex.length() < 4)
-                    hex = "0" + hex;
-                out += hex;
-            } else if (c == '\\') {
-                out += "\\\\";
-            } else if (c == '\"') {
-                out += "\\\"";
-            } else if (c == '\b') {
-                out += "\\b";
-            } else if (c == '\n') {
-                out += "\\n";
-            } else if (c == '\r') {
-                out += "\\r";
-            } else if (c == '\t') {
-                out += "\\t";
-            } else {
-                out += c;
-            }
-        }
-        return out;
-    }
-
-    public int compareTo(Object o) {
-        if (o instanceof NSString) {
-            return getContent().compareTo(((NSString) o).getContent());
-        } else if (o instanceof String) {
-            return getContent().compareTo(((String) o));
-        } else {
-            return -1;
-        }
-    }
-}
diff --git a/third_party/java/dd_plist/java/com/dd/plist/PropertyListFormatException.java b/third_party/java/dd_plist/java/com/dd/plist/PropertyListFormatException.java
deleted file mode 100644
index 13988a0..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/PropertyListFormatException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * plist - An open source library to parse and generate property lists
- * Copyright (C) 2014 Daniel Dreibrodt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.dd.plist;
-
-/**
- * A PropertyListFormatException is thrown by the various property list format parsers
- * when an error in the format of the given property list is encountered.
- * @author Daniel Dreibrodt
- */
-public class PropertyListFormatException extends Exception {
-
-    /**
-     * Creates a new exception with the given message.
-     * @param message A message containing information about the nature of the exception.
-     */
-    public PropertyListFormatException(String message) {
-        super(message);
-    }
-}
diff --git a/third_party/java/dd_plist/java/com/dd/plist/PropertyListParser.java b/third_party/java/dd_plist/java/com/dd/plist/PropertyListParser.java
deleted file mode 100644
index 0f307dc..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/PropertyListParser.java
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- * plist - An open source library to parse and generate property lists
- * Copyright (C) 2011-2014 Daniel Dreibrodt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package com.dd.plist;
-
-import org.xml.sax.SAXException;
-
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.text.ParseException;
-
-/**
- * This class provides methods to parse property lists. It can handle files,
- * input streams and byte arrays. All known property list formats are supported.
- *
- * This class also provides methods to save and convert property lists.
- *
- * @author Daniel Dreibrodt
- */
-public class PropertyListParser {
-
-    private static final int TYPE_XML = 0;
-    private static final int TYPE_BINARY = 1;
-    private static final int TYPE_ASCII = 2;
-    private static final int TYPE_ERROR_BLANK = 10;
-    private static final int TYPE_ERROR_UNKNOWN = 11;
-
-    private static final int READ_BUFFER_LENGTH = 2048;
-
-    /**
-     * Prevent instantiation.
-     */
-    protected PropertyListParser() {
-        /** empty **/
-    }
-
-    /**
-     * Determines the type of a property list by means of the first bytes of its data
-     * @param dataBeginning The very first bytes of data of the property list (minus any whitespace) as a string
-     * @return The type of the property list
-     */
-    private static int determineType(String dataBeginning) {
-        dataBeginning = dataBeginning.trim();
-        if(dataBeginning.length() == 0) {
-            return TYPE_ERROR_BLANK;
-        }
-        if(dataBeginning.startsWith("bplist")) {
-            return TYPE_BINARY;
-        }
-        if(dataBeginning.startsWith("(") || dataBeginning.startsWith("{") || dataBeginning.startsWith("/")) {
-            return TYPE_ASCII;
-        }
-        if(dataBeginning.startsWith("<")) {
-            return TYPE_XML;
-        }
-        return TYPE_ERROR_UNKNOWN;
-    }
-
-    /**
-     * Determines the type of a property list by means of the first bytes of its data
-     * @param bytes The very first bytes of data of the property list (minus any whitespace)
-     * @return The type of the property list
-     */
-    private static int determineType(byte[] bytes) {
-        //Skip any possible whitespace at the beginning of the file
-        int offset = 0;
-        if(bytes.length >= 3 && (bytes[0] & 0xFF) == 0xEF && (bytes[1] & 0xFF) == 0xBB && (bytes[2] & 0xFF) == 0xBF) {
-            //Skip Unicode byte order mark (BOM)
-            offset += 3;
-        }
-        while(offset < bytes.length && (bytes[offset] == ' ' || bytes[offset] == '\t' || bytes[offset] == '\r' || bytes[offset] == '\n' || bytes[offset] == '\f')) {
-            offset++;
-        }
-        return determineType(new String(bytes, offset, Math.min(8, bytes.length - offset)));
-    }
-
-    /**
-     * Determines the type of a property list by means of the first bytes of its data
-     * @param is An input stream pointing to the beginning of the property list data.
-     *           If the stream supports marking it will be reset to the beginning of the property
-     *           list data after the type has been determined.
-     * @return The type of the property list
-     */
-    private static int determineType(InputStream is) throws IOException {
-        //Skip any possible whitespace at the beginning of the file
-        byte[] magicBytes = new byte[8];
-        int b;
-        long index = -1;
-        boolean bom = false;
-        do {
-            if(is.markSupported())
-                is.mark(16);
-            b = is.read();
-            index++;
-            //Check if we are reading the Unicode byte order mark (BOM) and skip it
-            bom = index < 3 && ((index == 0 && b == 0xEF) || (bom && ((index == 1 && b == 0xBB) || (index == 2 && b == 0xBF))));
-        }
-        while(b != -1 && b == ' ' || b == '\t' || b == '\r' || b == '\n' || b == '\f' || bom);
-        magicBytes[0] = (byte)b;
-        int read = is.read(magicBytes, 1, 7);
-        int type = determineType(new String(magicBytes, 0, read));
-        if(is.markSupported())
-            is.reset();
-        return type;
-    }
-
-    /**
-     * Reads all bytes from an InputStream and stores them in an array, up to
-     * a maximum count.
-     *
-     * @param in  The InputStream pointing to the data that should be stored in the array.
-     * @return An array containing all bytes that were read from the input stream.
-     * @throws java.io.IOException When an IO error while reading from the input stream.
-     */
-    protected static byte[] readAll(InputStream in) throws IOException {
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        byte[] buf = new byte[READ_BUFFER_LENGTH];
-        int read;
-        while ((read = in.read(buf, 0, READ_BUFFER_LENGTH)) != -1) {
-            outputStream.write(buf, 0, read);
-        }
-        return outputStream.toByteArray();
-    }
-
-    /**
-     * Parses a property list from a file.
-     *
-     * @param filePath Path to the property list file.
-     * @return The root object in the property list. This is usually a NSDictionary but can also be a NSArray.
-     * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list
-     *                                                        could not be created. This should not occur.
-     * @throws java.io.IOException If any IO error occurs while reading the file.
-     * @throws org.xml.sax.SAXException If any parse error occurs.
-     * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format.
-     * @throws java.text.ParseException If a date string could not be parsed.
-     */
-    public static NSObject parse(String filePath) throws ParserConfigurationException, ParseException, SAXException, PropertyListFormatException, IOException {
-        return parse(new File(filePath));
-    }
-
-    /**
-     * Parses a property list from a file.
-     *
-     * @param f The property list file.
-     * @return The root object in the property list. This is usually a NSDictionary but can also be a NSArray.
-     * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list
-     *                                                        could not be created. This should not occur.
-     * @throws java.io.IOException If any IO error occurs while reading the file.
-     * @throws org.xml.sax.SAXException If any parse error occurs.
-     * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format.
-     * @throws java.text.ParseException If a date string could not be parsed.
-     */
-    public static NSObject parse(File f) throws IOException, PropertyListFormatException, ParseException, ParserConfigurationException, SAXException {
-        FileInputStream fis = new FileInputStream(f);
-        int type = determineType(fis);
-        fis.close();
-        switch(type) {
-            case TYPE_BINARY:
-                return BinaryPropertyListParser.parse(f);
-            case TYPE_XML:
-                return XMLPropertyListParser.parse(f);
-            case TYPE_ASCII:
-                return ASCIIPropertyListParser.parse(f);
-            default:
-                throw new PropertyListFormatException("The given file is not a property list of a supported format.");
-        }
-    }
-
-    /**
-     * Parses a property list from a byte array.
-     *
-     * @param bytes The property list data as a byte array.
-     * @return The root object in the property list. This is usually a NSDictionary but can also be a NSArray.
-     * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list
-     *                                                        could not be created. This should not occur.
-     * @throws java.io.IOException If any IO error occurs while reading the byte array.
-     * @throws org.xml.sax.SAXException If any parse error occurs.
-     * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format.
-     * @throws java.text.ParseException If a date string could not be parsed.
-     */
-    public static NSObject parse(byte[] bytes) throws IOException, PropertyListFormatException, ParseException, ParserConfigurationException, SAXException {
-        switch(determineType(bytes)) {
-            case TYPE_BINARY:
-                return BinaryPropertyListParser.parse(bytes);
-            case TYPE_XML:
-                return XMLPropertyListParser.parse(bytes);
-            case TYPE_ASCII:
-                return ASCIIPropertyListParser.parse(bytes);
-            default:
-                throw new PropertyListFormatException("The given data is not a property list of a supported format.");
-        }
-    }
-
-    /**
-     * Parses a property list from an InputStream.
-     *
-     * @param is The InputStream delivering the property list data.
-     * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray.
-     * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list
-     *                                                        could not be created. This should not occur.
-     * @throws java.io.IOException If any IO error occurs while reading the input stream.
-     * @throws org.xml.sax.SAXException If any parse error occurs.
-     * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format.
-     * @throws java.text.ParseException If a date string could not be parsed.
-     */
-    public static NSObject parse(InputStream is) throws IOException, PropertyListFormatException, ParseException, ParserConfigurationException, SAXException {
-        return parse(readAll(is));
-    }
-
-    /**
-     * Saves a property list with the given object as root into a XML file.
-     *
-     * @param root The root object.
-     * @param out  The output file.
-     * @throws IOException When an error occurs during the writing process.
-     */
-    public static void saveAsXML(NSObject root, File out) throws IOException {
-        File parent = out.getParentFile();
-        if (!parent.exists())
-            if(!parent.mkdirs())
-                throw new IOException("The output directory does not exist and could not be created.");
-        FileOutputStream fous = new FileOutputStream(out);
-        saveAsXML(root, fous);
-        fous.close();
-    }
-
-    /**
-     * Saves a property list with the given object as root in XML format into an output stream.
-     *
-     * @param root The root object.
-     * @param out  The output stream.
-     * @throws IOException When an error occurs during the writing process.
-     */
-    public static void saveAsXML(NSObject root, OutputStream out) throws IOException {
-        OutputStreamWriter w = new OutputStreamWriter(out, "UTF-8");
-        w.write(root.toXMLPropertyList());
-        w.close();
-    }
-
-    /**
-     * Converts a given property list file into the OS X and iOS XML format.
-     *
-     * @param in  The source file.
-     * @param out The target file.
-     *
-     * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list
-     *                                                        could not be created. This should not occur.
-     * @throws java.io.IOException If any IO error occurs while reading the input file or writing the output file.
-     * @throws org.xml.sax.SAXException If any parse error occurs.
-     * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format.
-     * @throws java.text.ParseException If a date string could not be parsed.
-     */
-    public static void convertToXml(File in, File out) throws ParserConfigurationException, ParseException, SAXException, PropertyListFormatException, IOException {
-        NSObject root = parse(in);
-        saveAsXML(root, out);
-    }
-
-    /**
-     * Saves a property list with the given object as root into a binary file.
-     *
-     * @param root The root object.
-     * @param out  The output file.
-     * @throws IOException When an error occurs during the writing process.
-     */
-    public static void saveAsBinary(NSObject root, File out) throws IOException {
-        File parent = out.getParentFile();
-        if (!parent.exists())
-            if(!parent.mkdirs())
-                throw new IOException("The output directory does not exist and could not be created.");
-        BinaryPropertyListWriter.write(out, root);
-    }
-
-    /**
-     * Saves a property list with the given object as root in binary format into an output stream.
-     *
-     * @param root The root object.
-     * @param out  The output stream.
-     * @throws IOException When an error occurs during the writing process.
-     */
-    public static void saveAsBinary(NSObject root, OutputStream out) throws IOException {
-        BinaryPropertyListWriter.write(out, root);
-    }
-
-    /**
-     * Converts a given property list file into the OS X and iOS binary format.
-     *
-     * @param in  The source file.
-     * @param out The target file.
-     * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list
-     *                                                        could not be created. This should not occur.
-     * @throws java.io.IOException If any IO error occurs while reading the input file or writing the output file.
-     * @throws org.xml.sax.SAXException If any parse error occurs.
-     * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format.
-     * @throws java.text.ParseException If a date string could not be parsed.
-     */
-    public static void convertToBinary(File in, File out) throws IOException, ParserConfigurationException, ParseException, SAXException, PropertyListFormatException {
-        NSObject root = parse(in);
-        saveAsBinary(root, out);
-    }
-
-    /**
-     * Saves a property list with the given object as root into a ASCII file.
-     *
-     * @param root The root object.
-     * @param out  The output file.
-     * @throws IOException When an error occurs during the writing process.
-     */
-    public static void saveAsASCII(NSDictionary root, File out) throws IOException {
-        File parent = out.getParentFile();
-        if (!parent.exists())
-            if(!parent.mkdirs())
-                throw new IOException("The output directory does not exist and could not be created.");
-        OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(out), "ASCII");
-        w.write(root.toASCIIPropertyList());
-        w.close();
-    }
-
-    /**
-     * Saves a property list with the given object as root into a ASCII file.
-     *
-     * @param root The root object.
-     * @param out  The output file.
-     * @throws IOException When an error occurs during the writing process.
-     */
-    public static void saveAsASCII(NSArray root, File out) throws IOException {
-        OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(out), "ASCII");
-        w.write(root.toASCIIPropertyList());
-        w.close();
-    }
-
-    /**
-     * Converts a given property list file into ASCII format.
-     *
-     * @param in  The source file.
-     * @param out The target file.
-     * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list
-     *                                                        could not be created. This should not occur.
-     * @throws java.io.IOException If any IO error occurs while reading the input file or writing the output file.
-     * @throws org.xml.sax.SAXException If any parse error occurs.
-     * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format.
-     * @throws java.text.ParseException If a date string could not be parsed.
-     */
-    public static void convertToASCII(File in, File out) throws ParserConfigurationException, ParseException, SAXException, PropertyListFormatException, IOException {
-        NSObject root = parse(in);
-        if(root instanceof NSDictionary) {
-            saveAsASCII((NSDictionary) root, out);
-        }
-        else if(root instanceof NSArray) {
-            saveAsASCII((NSArray) root, out);
-        }
-        else {
-            throw new PropertyListFormatException("The root of the given input property list "
-                    + "is neither a Dictionary nor an Array!");
-        }
-    }
-
-    /**
-     * Saves a property list with the given object as root into a ASCII file.
-     *
-     * @param root The root object.
-     * @param out  The output file.
-     * @throws IOException When an error occurs during the writing process.
-     */
-    public static void saveAsGnuStepASCII(NSDictionary root, File out) throws IOException {
-        File parent = out.getParentFile();
-        if (!parent.exists())
-            if(!parent.mkdirs())
-                throw new IOException("The output directory does not exist and could not be created.");
-        OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(out), "ASCII");
-        w.write(root.toGnuStepASCIIPropertyList());
-        w.close();
-    }
-
-    /**
-     * Saves a property list with the given object as root into a ASCII file.
-     *
-     * @param root The root object.
-     * @param out  The output file.
-     * @throws IOException When an error occurs during the writing process.
-     */
-    public static void saveAsGnuStepASCII(NSArray root, File out) throws IOException {
-        File parent = out.getParentFile();
-        if (!parent.exists())
-            if(!parent.mkdirs())
-                throw new IOException("The output directory does not exist and could not be created.");
-        OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(out), "ASCII");
-        w.write(root.toGnuStepASCIIPropertyList());
-        w.close();
-    }
-
-    /**
-     * Converts a given property list file into ASCII format.
-     *
-     * @param in  The source file.
-     * @param out The target file.
-     * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list
-     *                                                        could not be created. This should not occur.
-     * @throws java.io.IOException If any IO error occurs while reading the input file or writing the output file.
-     * @throws org.xml.sax.SAXException If any parse error occurs.
-     * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format.
-     * @throws java.text.ParseException If a date string could not be parsed.
-     */
-    public static void convertToGnuStepASCII(File in, File out) throws ParserConfigurationException, ParseException, SAXException, PropertyListFormatException, IOException {
-        NSObject root = parse(in);
-        if(root instanceof NSDictionary) {
-            saveAsGnuStepASCII((NSDictionary) root, out);
-        }
-        else if(root instanceof NSArray) {
-            saveAsGnuStepASCII((NSArray) root, out);
-        }
-        else {
-            throw new PropertyListFormatException("The root of the given input property list "
-                    + "is neither a Dictionary nor an Array!");
-        }
-    }
-}
diff --git a/third_party/java/dd_plist/java/com/dd/plist/UID.java b/third_party/java/dd_plist/java/com/dd/plist/UID.java
deleted file mode 100644
index 9dde01c..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/UID.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * plist - An open source library to parse and generate property lists
- * Copyright (C) 2011 Daniel Dreibrodt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package com.dd.plist;
-
-import java.io.IOException;
-
-/**
- * A UID. Only found in binary property lists that are keyed archives.
- *
- * @author Daniel Dreibrodt
- */
-public class UID extends NSObject {
-
-    private byte[] bytes;
-    private String name;
-
-    public UID(String name, byte[] bytes) {
-        this.name = name;
-        this.bytes = bytes;
-    }
-
-    public byte[] getBytes() {
-        return bytes;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * There is no XML representation specified for UIDs.
-     * In this implementation UIDs are represented as strings in the XML output.
-     *
-     * @param xml   The xml StringBuilder
-     * @param level The indentation level
-     */
-    @Override
-    void toXML(StringBuilder xml, int level) {
-        indent(xml, level);
-        xml.append("<string>");
-        for (int i = 0; i < bytes.length; i++) {
-            byte b = bytes[i];
-            if (b < 16)
-                xml.append("0");
-            xml.append(Integer.toHexString(b));
-        }
-        xml.append("</string>");
-    }
-
-    @Override
-    void toBinary(BinaryPropertyListWriter out) throws IOException {
-        out.write(0x80 + bytes.length - 1);
-        out.write(bytes);
-    }
-
-    @Override
-    protected void toASCII(StringBuilder ascii, int level) {
-        indent(ascii, level);
-        ascii.append("\"");
-        for (int i = 0; i < bytes.length; i++) {
-            byte b = bytes[i];
-            if (b < 16)
-                ascii.append("0");
-            ascii.append(Integer.toHexString(b));
-        }
-        ascii.append("\"");
-    }
-
-    @Override
-    protected void toASCIIGnuStep(StringBuilder ascii, int level) {
-        toASCII(ascii, level);
-    }
-}
diff --git a/third_party/java/dd_plist/java/com/dd/plist/XMLPropertyListParser.java b/third_party/java/dd_plist/java/com/dd/plist/XMLPropertyListParser.java
deleted file mode 100644
index 6fcb7f9..0000000
--- a/third_party/java/dd_plist/java/com/dd/plist/XMLPropertyListParser.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * plist - An open source library to parse and generate property lists
- * Copyright (C) 2014 Daniel Dreibrodt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package com.dd.plist;
-
-import org.w3c.dom.*;
-import org.xml.sax.EntityResolver;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Parses XML property lists.
- *
- * @author Daniel Dreibrodt
- */
-public class XMLPropertyListParser {
-
-    /**
-     * Instantiation is prohibited by outside classes.
-     */
-    protected XMLPropertyListParser() {
-        /** empty **/
-    }
-
-    private static DocumentBuilderFactory docBuilderFactory = null;
-
-    /**
-     * Initialize the document builder factory so that it can be reused and does not need to
-     * be reinitialized for each parse action.
-     */
-    private static synchronized void initDocBuilderFactory() {
-        docBuilderFactory = DocumentBuilderFactory.newInstance();
-        docBuilderFactory.setIgnoringComments(true);
-        docBuilderFactory.setCoalescing(true);
-    }
-
-    /**
-     * Gets a DocumentBuilder to parse a XML property list.
-     * As DocumentBuilders are not thread-safe a new DocBuilder is generated for each request.
-     *
-     * @return A new DocBuilder that can parse property lists w/o an internet connection.
-     * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list
-     *                                                        could not be created. This should not occur.
-     */
-    private static synchronized DocumentBuilder getDocBuilder() throws ParserConfigurationException {
-        if (docBuilderFactory == null)
-            initDocBuilderFactory();
-        DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
-        docBuilder.setEntityResolver(new EntityResolver() {
-            public InputSource resolveEntity(String publicId, String systemId) {
-                if ("-//Apple Computer//DTD PLIST 1.0//EN".equals(publicId) || // older publicId
-                        "-//Apple//DTD PLIST 1.0//EN".equals(publicId)) { // newer publicId
-                    // return a dummy, zero length DTD so we don't have to fetch
-                    // it from the network.
-                    return new InputSource(new ByteArrayInputStream(new byte[0]));
-                }
-                return null;
-            }
-        });
-        return docBuilder;
-    }
-
-    /**
-     * Parses a XML property list file.
-     *
-     * @param f The XML property list file.
-     * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray.
-     * @see javax.xml.parsers.DocumentBuilder#parse(java.io.File)
-     * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list
-     *                                                        could not be created. This should not occur.
-     * @throws java.io.IOException If any IO error occurs while reading the file.
-     * @throws org.xml.sax.SAXException If any parse error occurs.
-     * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format.
-     * @throws java.text.ParseException If a date string could not be parsed.
-     */
-    public static NSObject parse(File f) throws ParserConfigurationException, IOException, SAXException, PropertyListFormatException, ParseException {
-        DocumentBuilder docBuilder = getDocBuilder();
-
-        Document doc = docBuilder.parse(f);
-
-        return parse(doc);
-    }
-
-    /**
-     * Parses a XML property list from a byte array.
-     *
-     * @param bytes The byte array containing the property list's data.
-     * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray.
-     * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list
-     *                                                        could not be created. This should not occur.
-     * @throws java.io.IOException If any IO error occurs while reading the file.
-     * @throws org.xml.sax.SAXException If any parse error occurs.
-     * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format.
-     * @throws java.text.ParseException If a date string could not be parsed.
-     */
-    public static NSObject parse(final byte[] bytes) throws ParserConfigurationException, ParseException, SAXException, PropertyListFormatException, IOException {
-        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
-        return parse(bis);
-    }
-
-    /**
-     * Parses a XML property list from an input stream.
-     *
-     * @param is The input stream pointing to the property list's data.
-     * @return The root object of the property list. This is usually a NSDictionary but can also be a NSArray.
-     * @see javax.xml.parsers.DocumentBuilder#parse(java.io.InputStream)
-     * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list
-     *                                                        could not be created. This should not occur.
-     * @throws java.io.IOException If any IO error occurs while reading the file.
-     * @throws org.xml.sax.SAXException If any parse error occurs.
-     * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format.
-     * @throws java.text.ParseException If a date string could not be parsed.
-     */
-    public static NSObject parse(InputStream is) throws ParserConfigurationException, IOException, SAXException, PropertyListFormatException, ParseException {
-        DocumentBuilder docBuilder = getDocBuilder();
-
-        Document doc = docBuilder.parse(is);
-
-        return parse(doc);
-    }
-
-    /**
-     * Parses a property list from an XML document.
-     *
-     * @param doc The XML document.
-     * @return The root NSObject of the property list contained in the XML document.
-     * @throws java.io.IOException If any IO error occurs while reading the file.
-     * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format.
-     * @throws java.text.ParseException If a date string could not be parsed.
-     */
-    public static NSObject parse(Document doc) throws PropertyListFormatException, IOException, ParseException {
-        DocumentType docType = doc.getDoctype();
-        if (docType == null) {
-            if (!doc.getDocumentElement().getNodeName().equals("plist")) {
-                throw new UnsupportedOperationException("The given XML document is not a property list.");
-            }
-        } else if (!docType.getName().equals("plist")) {
-            throw new UnsupportedOperationException("The given XML document is not a property list.");
-        }
-
-        Node rootNode;
-
-        if (doc.getDocumentElement().getNodeName().equals("plist")) {
-            //Root element wrapped in plist tag
-            List<Node> rootNodes = filterElementNodes(doc.getDocumentElement().getChildNodes());
-            if (rootNodes.isEmpty()) {
-                throw new PropertyListFormatException("The given XML property list has no root element!");
-            } else if (rootNodes.size() == 1) {
-                rootNode = rootNodes.get(0);
-            } else {
-                throw new PropertyListFormatException("The given XML property list has more than one root element!");
-            }
-        } else {
-            //Root NSObject not wrapped in plist-tag
-            rootNode = doc.getDocumentElement();
-        }
-
-        return parseObject(rootNode);
-    }
-
-    /**
-     * Parses a node in the XML structure and returns the corresponding NSObject
-     *
-     * @param n The XML node.
-     * @return The corresponding NSObject.
-     * @throws java.io.IOException If any IO error occurs while parsing a Base64 encoded NSData object.
-     * @throws java.text.ParseException If a date string could not be parsed.
-     */
-    private static NSObject parseObject(Node n) throws ParseException, IOException {
-        String type = n.getNodeName();
-        if (type.equals("dict")) {
-            NSDictionary dict = new NSDictionary();
-            List<Node> children = filterElementNodes(n.getChildNodes());
-            for (int i = 0; i < children.size(); i += 2) {
-                Node key = children.get(i);
-                Node val = children.get(i + 1);
-
-                String keyString = getNodeTextContents(key);
-
-                dict.put(keyString, parseObject(val));
-            }
-            return dict;
-        } else if (type.equals("array")) {
-            List<Node> children = filterElementNodes(n.getChildNodes());
-            NSArray array = new NSArray(children.size());
-            for (int i = 0; i < children.size(); i++) {
-                array.setValue(i, parseObject(children.get(i)));
-            }
-            return array;
-        } else if (type.equals("true")) {
-            return new NSNumber(true);
-        } else if (type.equals("false")) {
-            return new NSNumber(false);
-        } else if (type.equals("integer")) {
-            return new NSNumber(getNodeTextContents(n));
-        } else if (type.equals("real")) {
-            return new NSNumber(getNodeTextContents(n));
-        } else if (type.equals("string")) {
-            return new NSString(getNodeTextContents(n));
-        } else if (type.equals("data")) {
-            return new NSData(getNodeTextContents(n));
-        } else if (type.equals("date")) {
-            return new NSDate(getNodeTextContents(n));
-        }
-        return null;
-    }
-
-    /**
-     * Returns all element nodes that are contained in a list of nodes.
-     *
-     * @param list The list of nodes to search.
-     * @return The sub-list containing only nodes representing actual elements.
-     */
-    private static List<Node> filterElementNodes(NodeList list) {
-        List<Node> result = new ArrayList<Node>(list.getLength());
-        for (int i = 0; i < list.getLength(); i++) {
-            if (list.item(i).getNodeType() == Node.ELEMENT_NODE) {
-                result.add(list.item(i));
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Returns a node's text content.
-     * This method will return the text value represented by the node's direct children.
-     * If the given node is a TEXT or CDATA node, then its value is returned.
-     *
-     * @param n The node.
-     * @return The node's text content.
-     */
-    private static String getNodeTextContents(Node n) {
-        if (n.getNodeType() == Node.TEXT_NODE || n.getNodeType() == Node.CDATA_SECTION_NODE) {
-            Text txtNode = (Text) n;
-            String content = txtNode.getWholeText(); //This concatenates any adjacent text/cdata/entity nodes
-            if (content == null)
-                return "";
-            else
-                return content;
-        } else {
-            if (n.hasChildNodes()) {
-                NodeList children = n.getChildNodes();
-
-                for (int i = 0; i < children.getLength(); i++) {
-                    //Skip any non-text nodes, like comments or entities
-                    Node child = children.item(i);
-                    if (child.getNodeType() == Node.TEXT_NODE || child.getNodeType() == Node.CDATA_SECTION_NODE) {
-                        Text txtNode = (Text) child;
-                        String content = txtNode.getWholeText(); //This concatenates any adjacent text/cdata/entity nodes
-                        if (content == null)
-                            return "";
-                        else
-                            return content;
-                    }
-                }
-
-                return "";
-            } else {
-                return "";
-            }
-        }
-    }
-}