class FuskatorRipper extends AbstractHTMLRipper {

    private String jsonurl = "https://fuskator.com/ajax/gal.aspx";
    private String xAuthUrl = "https://fuskator.com/ajax/auth.aspx";
    private String xAuthToken;
    private Map<String, String> cookies;

    public FuskatorRipper(URL url) throws IOException {
        super(url);
    }

    @Override
    public String getHost() {
        return "fuskator";
    }

    @Override
    public String getDomain() {
        return "fuskator.com";
    }

    @Override
    public URL sanitizeURL(URL url) throws MalformedURLException {
        String u = url.toExternalForm();
        if (u.contains("/thumbs/")) {
            u = u.replace("/thumbs/", "/full/");
        }
        if (u.contains("/expanded/")) {
            u = u.replaceAll("/expanded/", "/full/");
        }
        return new URL(u);
    }

    @Override
    public String getGID(URL url) throws MalformedURLException {
        Pattern p = Pattern.compile("^.*fuskator.com/full/([a-zA-Z0-9\\-~]+).*$");
        Matcher m = p.matcher(url.toExternalForm());
        if (m.matches()) {
            return m.group(1);
        }
        throw new MalformedURLException(
                "Expected fuskator.com gallery formats: " + "fuskator.com/full/id/..." + " Got: " + url);
    }

    @Override
    public Document getFirstPage() throws IOException {
        // return Http.url(url).get();
        Response res = Http.url(url).response();
        cookies = res.cookies();
        return res.parse();
    }

    @Override
    public List<String> getURLsFromPage(Document doc) {
        List<String> imageURLs = new ArrayList<>();
        JSONObject json;

        try {
            getXAuthToken();
            if (xAuthToken == null || xAuthToken.isEmpty()) {
                throw new IOException("No xAuthToken found.");
            }

            // All good. Fetch JSON data from jsonUrl.
            json = Http.url(jsonurl).cookies(cookies).data("X-Auth", xAuthToken).data("hash", getGID(url))
                    .data("_", Long.toString(System.currentTimeMillis())).getJSON();
        } catch (IOException e) {
            LOGGER.error("Couldnt fetch images.", e.getCause());
            return imageURLs;
        }

        JSONArray imageArray = json.getJSONArray("images");
        for (int i = 0; i < imageArray.length(); i++) {
            imageURLs.add("https:" + imageArray.getJSONObject(i).getString("imageUrl"));
        }

        return imageURLs;
    }

    @Override
    public void downloadURL(URL url, int index) {
        addURLToDownload(url, getPrefix(index));
    }

    private void getXAuthToken() throws IOException {<FILL_FUNCTION_BODY>}
}

        if (cookies == null || cookies.isEmpty()) {
            throw new IOException("Null cookies or no cookies found.");
        }
        Response res = Http.url(xAuthUrl).cookies(cookies).method(Method.POST).response();
        xAuthToken = res.body();
    
<methods>public boolean addURLToDownload(java.net.URL, java.io.File, java.lang.String, Map<java.lang.String,java.lang.String>, java.lang.Boolean) ,public boolean addURLToDownload(java.net.URL, java.io.File) ,public boolean canRip(java.net.URL) ,public void downloadCompleted(java.net.URL, java.io.File) ,public void downloadErrored(java.net.URL, java.lang.String) ,public void downloadExists(java.net.URL, java.io.File) ,public int getCompletionPercentage() ,public int getCount() ,public abstract java.lang.String getHost() ,public Document getNextPage(Document) throws java.io.IOException,public java.lang.String getStatusText() ,public void rip() throws java.io.IOException,public java.net.URL sanitizeURL(java.net.URL) throws java.net.MalformedURLException,public boolean saveText(java.net.URL, java.lang.String, java.lang.String, int) ,public void setWorkingDir(java.net.URL) throws java.io.IOException<variables>private Map<java.net.URL,java.io.File> itemsCompleted,private Map<java.net.URL,java.lang.String> itemsErrored,private Map<java.net.URL,java.io.File> itemsPending