@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("head"),
            new CssSelectorNodeFilter("title")});
        String problemName = fb.getText();
        // remove extra info from problem name
        problemName = problemName.replaceAll("Jutge :: Problem P(.*)[_ca|_en|_es]: ","");
        if (problemName.isEmpty()) {
            throw new ParserException("Problem name not extracted (probably incorrect url).");
        }
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        // extract inputs
        ArrayList<String> inputs = extractInputsOrOutputs(fb, true);

        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        
        // extract outputs
        ArrayList<String> outputs = extractInputsOrOutputs(fb, false);
        
        if (inputs.size() != outputs.size()) {
            throw new ParserException("Number of inputs is not equal to number of outputs.");
        }
        
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        
        // as far as I know, Jutge sets time limit automatically as 2*official_solution_time and is not public
        int timeLimit = Testcase.DEFAULT_TIME_LIMIT;
        
        // add test cases
        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.Jutge);
        return problem;
    }