class TapasticRipper extends AbstractHTMLRipper {

    private List<TapasticEpisode> episodes= new ArrayList<>();

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

    @Override
    public String getDomain() {
        return "tapas.io";
    }

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

    @Override
    public Document getFirstPage() throws IOException {
        return Http.url(url).get();
    }

    @Override
    public List<String> getURLsFromPage(Document page) {
        List<String> urls = new ArrayList<>();
        String html = page.data();
        if (!html.contains("episodeList : ")) {
            LOGGER.error("No 'episodeList' found at " + this.url);
            return urls;
        }
        String jsonString = Utils.between(html, "episodeList : ", ",\n").get(0);
        JSONArray json = new JSONArray(jsonString);
        for (int i = 0; i < json.length(); i++) {
            JSONObject obj = json.getJSONObject(i);
            TapasticEpisode episode = new TapasticEpisode(i, obj.getInt("id"), obj.getString("title"));
            episodes.add(episode);
            urls.add("http://tapastic.com/episode/" + episode.id);
        }
        return urls;
    }

    @Override
    public void downloadURL(URL url, int index) {<FILL_FUNCTION_BODY>}

    @Override
    public String getGID(URL url) throws MalformedURLException {
        Pattern p = Pattern.compile("^https?://tapas.io/series/([^/?]+).*$");
        Matcher m = p.matcher(url.toExternalForm());
        if (m.matches()) {
            return "series_ " + m.group(1);
        }
        p = Pattern.compile("^https?://tapas.io/episode/([^/?]+).*$");
        m = p.matcher(url.toExternalForm());
        if (m.matches()) {
            return "ep_" + m.group(1);
        }
        throw new MalformedURLException("Expected tapastic.com URL format: "
                + "tapastic.com/[series|episode]/name - got " + url + " instead");
    }
}

        try {
            Document doc = Http.url(url).get();
            Elements images = doc.select("article.ep-contents img");
            // Find maximum # of images for optimal filename indexing
            int epiLog = (int) (Math.floor(Math.log10(episodes.size())) + 1),
                imgLog = (int) (Math.floor(Math.log10(images.size()  )) + 1);
            for (int i = 0; i < images.size(); i++) {
                String link = images.get(i).attr("src");
                TapasticEpisode episode = episodes.get(index - 1);
                // Build elaborate filename prefix
                StringBuilder prefix = new StringBuilder();
                prefix.append(String.format("ep%0" + epiLog + "d", index));
                prefix.append(String.format("-%0" + imgLog + "dof%0" + imgLog + "d-", i + 1, images.size()));
                prefix.append(episode.filename.replace(" ", "-"));
                prefix.append("-");
                addURLToDownload(new URL(link), prefix.toString());
                if (isThisATest()) {
                    break;
                }
            }
        } catch (IOException e) {
            LOGGER.error("[!] Exception while downloading " + url, e);
        }

    
<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