*  the list of urls (instance of <tt>java.net.URL</tt>)
     *  @since 0.24
     */
    @SuppressWarnings("rawtypes")
    public ArrayList[] linksearch(String pattern, String protocol, int... ns) throws IOException
    {
        // FIXME: Change return type to ArrayList<Object[]> or Object[][]
        // First index refers to item number, linksearch()[x][0] = page title

        // set it up
        StringBuilder url = new StringBuilder(query);
        // no reason for more than 500 links
        ArrayList<String> pagetitles = new ArrayList<String>(667);
        ArrayList<URL> pageurls = new ArrayList<URL>(667);
        url.append("list=exturlusage&euprop=title%7curl&euquery=");
        url.append(pattern);
        url.append("&euprotocol=");
        url.append(protocol);
        url.append("&eulimit=max");
        constructNamespaceString(url, "eu", ns);
        url.append("&euoffset=");

        // some variables we need later
        boolean done = false;

        // begin
        while (!done)
        {
            // if this is the last page of results then there is no euoffset parameter
            String line = fetch(url.toString() + pagetitles.size(), "linksearch");
            if (!line.contains("euoffset=\""))
                done = true;

            // xml form: <eu ns="0" title="Main Page" url="http://example.com" />
            for (int x = line.indexOf("<eu"); x > 0; x = line.indexOf("<eu ", ++x))
            {
                String link = parseAttribute(line, "url", x);
                pagetitles.add(decode(parseAttribute(line, "title", x)));
                if (link.charAt(0) == '/') // protocol relative url
                    pageurls.add(new URL(protocol + ":" + link));
                else
                    pageurls.add(new URL(link));
            }
        }

        // return value
        log(Level.INFO, "Successfully returned instances of external link " + pattern + " (" + pagetitles.size() + " links)", "linksearch");
        return new ArrayList[]{ pagetitles, pageurls };
    }