*  @param end fetch edits no older than this date
     *  @param ns a list of namespaces to filter by, empty = all namespaces.
     *  @param prefix a prefix of usernames. Overrides <tt>user</tt>.  Use "" to
     *  not specify one.
     *  @return contributions of this user
     *  @throws IOException if a network error occurs
     *  @since 0.17
     */
    public Wiki.Revision[] contribs(String user, String prefix, Calendar end, Calendar start, int... ns) throws IOException
    {
        // prepare the url
        StringBuilder temp = new StringBuilder(query);
        temp.append("list=usercontribs&uclimit=max&ucprop=title%7Ctimestamp%7Cflags%7Ccomment%7Cids%7Csize%7Csizediff&");
        if (prefix.isEmpty())
        {
            temp.append("ucuser=");
            temp.append(URLEncoder.encode(normalize(user), "UTF-8"));
        }
        else
        {
            temp.append("ucuserprefix=");
            temp.append(prefix);
        }
        constructNamespaceString(temp, "uc", ns);
        // end refers to the *oldest* allowable edit and vice versa
        if (end != null)
        {
            temp.append("&ucend=");
            temp.append(calendarToTimestamp(end));
        }
        if (start != null)
        {
            temp.append("&ucstart=");
            temp.append(calendarToTimestamp(start));
        }
        ArrayList<Wiki.Revision> revisions = new ArrayList<Wiki.Revision>(7500);
        String uccontinue = "";

        // fetch data
        do
        {
            String line = fetch(temp.toString() + uccontinue, "contribs");

            // set offset parameter
            if (line.contains("uccontinue"))
                uccontinue = "&uccontinue=" + URLEncoder.encode(parseAttribute(line, "uccontinue", 0), "UTF-8");
            else
                uccontinue = null; // depleted list
            
            // xml form: <item user="Wizardman" ... size="59460" />
            for (int a = line.indexOf("<item "); a > 0; a = line.indexOf("<item ", ++a))
            {
                int b = line.indexOf(" />", a);
                revisions.add(parseRevision(line.substring(a, b), ""));
            }
        }
        while (uccontinue != null);

        // clean up
        int size = revisions.size();
        log(Level.INFO, "Successfully retrived contributions for " + (prefix.isEmpty() ? user : prefix) + " (" + size + " edits)", "contribs");
        return revisions.toArray(new Wiki.Revision[size]);
    }