// Path: src/com/crossbowffs/quotelock/modules/vnaas/model/VnaasCharacter.java
// public class VnaasCharacter {
//     private final long mId;
//     private final String mName;
//     private final VnaasNovel[] mNovels;
// 
//     public VnaasCharacter(long id, String name, VnaasNovel[] novels) {
//         mId = id;
//         mName = name;
//         mNovels = novels;
//     }
// 
//     public long getId() {
//         return mId;
//     }
// 
//     public String getName() {
//         return mName;
//     }
// 
//     public VnaasNovel[] getNovels() {
//         return mNovels;
//     }
// }
// 
// Path: src/com/crossbowffs/quotelock/modules/vnaas/model/VnaasNovel.java
// public class VnaasNovel {
//     private final long mId;
//     private final String mName;
//     private final VnaasCharacter[] mCharacters;
// 
//     public VnaasNovel(long id, String name, VnaasCharacter[] characters) {
//         mId = id;
//         mName = name;
//         mCharacters = characters;
//     }
// 
//     public long getId() {
//         return mId;
//     }
// 
//     public String getName() {
//         return mName;
//     }
// 
//     public VnaasCharacter[] getCharacters() {
//         return mCharacters;
//     }
// }
// 
// Path: src/com/crossbowffs/quotelock/modules/vnaas/model/VnaasQuote.java
// public class VnaasQuote {
//     private final String mText;
//     private final VnaasCharacter mCharacter;
//     private final VnaasNovel mNovel;
// 
//     public VnaasQuote(String text, VnaasCharacter character, VnaasNovel novel) {
//         mText = text;
//         mCharacter = character;
//         mNovel = novel;
//     }
// 
//     public String getText() {
//         return mText;
//     }
// 
//     public VnaasCharacter getCharacter() {
//         return mCharacter;
//     }
// 
//     public VnaasNovel getNovel() {
//         return mNovel;
//     }
// }
// 
// Path: src/com/crossbowffs/quotelock/utils/IOUtils.java
// public class IOUtils {
//     public static String streamToString(InputStream inputStream, String encoding, int bufferSize) throws IOException {
//         char[] buffer = new char[bufferSize];
//         StringBuilder sb = new StringBuilder();
//         try (InputStreamReader reader = new InputStreamReader(inputStream, encoding)) {
//             while (true) {
//                 int count = reader.read(buffer, 0, bufferSize);
//                 if (count < 0) break;
//                 sb.append(buffer, 0, count);
//             }
//         }
//         return sb.toString();
//     }
// 
//     public static String streamToString(InputStream inputStream) throws IOException {
//         return streamToString(inputStream, "UTF-8", 2048);
//     }
// 
//     public static String downloadString(String urlString) throws IOException {
//         URL url = new URL(urlString);
//         String ua = String.format("QuoteLock/%s (+%s)", BuildConfig.VERSION_NAME, Urls.GITHUB_QUOTELOCK);
//         HttpURLConnection connection = (HttpURLConnection)url.openConnection();
//         try {
//             connection.setRequestProperty("User-Agent",  ua);
//             int responseCode = connection.getResponseCode();
//             if (responseCode == 200) {
//                 return streamToString(connection.getInputStream());
//             } else {
//                 throw new IOException("Server returned non-200 status code: " + responseCode);
//             }
//         } finally {
//             connection.disconnect();
//         }
//     }
// }


import com.crossbowffs.quotelock.modules.vnaas.model.VnaasCharacter;
import com.crossbowffs.quotelock.modules.vnaas.model.VnaasNovel;
import com.crossbowffs.quotelock.modules.vnaas.model.VnaasQuote;
import com.crossbowffs.quotelock.utils.IOUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
        try {
            return jsonToNovel(json);
        } catch (JSONException e) {
            throw new IOException(e);
        }
    }

    public VnaasCharacter[] getCharacters(VnaasCharacterQueryParams params) throws IOException {
        String url = params.buildUrl(mBaseUrl + CHARACTERS_URL);
        JSONArray json = fetchJsonArray(url);
        try {
            return jsonArrayToCharacters(json);
        } catch (JSONException e) {
            throw new IOException(e);
        }
    }

    public VnaasCharacter getCharacter(long characterId) throws IOException {
        String url = mBaseUrl + CHARACTERS_URL + "/" + characterId;
        JSONObject json = fetchJsonObject(url);
        try {
            return jsonToCharacter(json);
        } catch (JSONException e) {
            throw new IOException(e);
        }
    }

    public VnaasQuote getRandomQuote(VnaasQuoteQueryParams params) throws IOException {
        String url = params.buildUrl(mBaseUrl + RANDOM_QUOTE_URL);
        JSONObject json = fetchJsonObject(url);
// Path: src/com/crossbowffs/quotelock/modules/vnaas/model/VnaasCharacter.java
// public class VnaasCharacter {
//     private final long mId;
//     private final String mName;
//     private final VnaasNovel[] mNovels;
// 
//     public VnaasCharacter(long id, String name, VnaasNovel[] novels) {
//         mId = id;
//         mName = name;
//         mNovels = novels;
//     }
// 
//     public long getId() {
//         return mId;
//     }
// 
//     public String getName() {
//         return mName;
//     }
// 
//     public VnaasNovel[] getNovels() {
//         return mNovels;
//     }
// }
// 
// Path: src/com/crossbowffs/quotelock/modules/vnaas/model/VnaasNovel.java
// public class VnaasNovel {
//     private final long mId;
//     private final String mName;
//     private final VnaasCharacter[] mCharacters;
// 
//     public VnaasNovel(long id, String name, VnaasCharacter[] characters) {
//         mId = id;
//         mName = name;
//         mCharacters = characters;
//     }
// 
//     public long getId() {
//         return mId;
//     }
// 
//     public String getName() {
//         return mName;
//     }
// 
//     public VnaasCharacter[] getCharacters() {
//         return mCharacters;
//     }
// }
// 
// Path: src/com/crossbowffs/quotelock/modules/vnaas/model/VnaasQuote.java
// public class VnaasQuote {
//     private final String mText;
//     private final VnaasCharacter mCharacter;
//     private final VnaasNovel mNovel;
// 
//     public VnaasQuote(String text, VnaasCharacter character, VnaasNovel novel) {
//         mText = text;
//         mCharacter = character;
//         mNovel = novel;
//     }
// 
//     public String getText() {
//         return mText;
//     }
// 
//     public VnaasCharacter getCharacter() {
//         return mCharacter;
//     }
// 
//     public VnaasNovel getNovel() {
//         return mNovel;
//     }
// }
// 
// Path: src/com/crossbowffs/quotelock/utils/IOUtils.java
// public class IOUtils {
//     public static String streamToString(InputStream inputStream, String encoding, int bufferSize) throws IOException {
//         char[] buffer = new char[bufferSize];
//         StringBuilder sb = new StringBuilder();
//         try (InputStreamReader reader = new InputStreamReader(inputStream, encoding)) {
//             while (true) {
//                 int count = reader.read(buffer, 0, bufferSize);
//                 if (count < 0) break;
//                 sb.append(buffer, 0, count);
//             }
//         }
//         return sb.toString();
//     }
// 
//     public static String streamToString(InputStream inputStream) throws IOException {
//         return streamToString(inputStream, "UTF-8", 2048);
//     }
// 
//     public static String downloadString(String urlString) throws IOException {
//         URL url = new URL(urlString);
//         String ua = String.format("QuoteLock/%s (+%s)", BuildConfig.VERSION_NAME, Urls.GITHUB_QUOTELOCK);
//         HttpURLConnection connection = (HttpURLConnection)url.openConnection();
//         try {
//             connection.setRequestProperty("User-Agent",  ua);
//             int responseCode = connection.getResponseCode();
//             if (responseCode == 200) {
//                 return streamToString(connection.getInputStream());
//             } else {
//                 throw new IOException("Server returned non-200 status code: " + responseCode);
//             }
//         } finally {
//             connection.disconnect();
//         }
//     }
// }


// Path: src/com/crossbowffs/quotelock/modules/vnaas/api/VnaasApiManager.java
import com.crossbowffs.quotelock.modules.vnaas.model.VnaasCharacter;
import com.crossbowffs.quotelock.modules.vnaas.model.VnaasNovel;
import com.crossbowffs.quotelock.modules.vnaas.model.VnaasQuote;
import com.crossbowffs.quotelock.utils.IOUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;

        try {
            return jsonToNovel(json);
        } catch (JSONException e) {
            throw new IOException(e);
        }
    }

    public VnaasCharacter[] getCharacters(VnaasCharacterQueryParams params) throws IOException {
        String url = params.buildUrl(mBaseUrl + CHARACTERS_URL);
        JSONArray json = fetchJsonArray(url);
        try {
            return jsonArrayToCharacters(json);
        } catch (JSONException e) {
            throw new IOException(e);
        }
    }

    public VnaasCharacter getCharacter(long characterId) throws IOException {
        String url = mBaseUrl + CHARACTERS_URL + "/" + characterId;
        JSONObject json = fetchJsonObject(url);
        try {
            return jsonToCharacter(json);
        } catch (JSONException e) {
            throw new IOException(e);
        }
    }

    public VnaasQuote getRandomQuote(VnaasQuoteQueryParams params) throws IOException {
        String url = params.buildUrl(mBaseUrl + RANDOM_QUOTE_URL);
        JSONObject json = fetchJsonObject(url);
        try {