@Override
    public Problem parse(String URL) throws ParserException, InterruptedException {

        URL = URL.trim();
        
        FilterBean fb = new FilterBean();
        fb.setURL(URL);
        
        // extract problem name
        fb.setFilters(new NodeFilter[] {
            new CssSelectorNodeFilter("div.header"),
            new CssSelectorNodeFilter("div.title")});
        String problemName = fb.getText();
        if (problemName.isEmpty()) {
            throw new ParserException("Problem name not extracted (probably incorrect url).");
        }
        problemName = String.valueOf(problemName.charAt(0));
        
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        
        // extract inputs
        ArrayList<String> inputs = extractInputsOrOutputs(fb, "div.input");

        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        
        // extract outputs
        ArrayList<String> outputs = extractInputsOrOutputs(fb, "div.output");
        
        if (inputs.size() != outputs.size()) {
            throw new ParserException("Number of inputs is not equal to number of outputs.");
        }
        
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        
        // extract time limit
        fb.setFilters(new NodeFilter[] {new CssSelectorNodeFilter("div.time-limit")});
        String timeLimitText = fb.getText(); // should be "time limit per testXXX second"
        Pattern pattern = Pattern.compile("\\d+(\\.\\d+)?");
        Matcher matcher = pattern.matcher(timeLimitText);
        int timeLimit = Testcase.DEFAULT_TIME_LIMIT;
        if (matcher.find()) {
            timeLimit = (int) (Double.valueOf(matcher.group()) * 1000);
        }
        
        
        TestcaseSet testcaseSet = new TestcaseSet();
        for (int i = 0; i < inputs.size(); ++i) {
            testcaseSet.add(new Testcase(inputs.get(i).trim(), outputs.get(i).trim(), timeLimit));
        }
        
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        
        Problem problem = new Problem(problemName, testcaseSet, SupportedSites.CodeForces);
        
        return problem;
    }