class ExtractorImpliedURI extends Extractor {

    @SuppressWarnings("unused")
    private static final long serialVersionUID = 3L;

    private static Logger LOGGER =
        Logger.getLogger(ExtractorImpliedURI.class.getName());
   
    
    {
        setRegex(Pattern.compile("^(.*)$"));
    }
    public Pattern getRegex() {
        return (Pattern) kp.get("regex");
    }
    /**
     * Triggering regular expression. When a discovered URI matches this
     * pattern, the 'implied' URI will be built. The capturing groups of this
     * expression are available for the build replacement pattern.
     */
    public void setRegex(Pattern regex) {
        kp.put("regex",regex);
    }

    
    {
        setFormat("");
    }
    public String getFormat() {
        return (String) kp.get("format");
    }
    /**
     * Replacement pattern to build 'implied' URI, using captured groups of
     * trigger expression.
     */
    public void setFormat(String format) {
        kp.put("format",format);
    }

    {
        setRemoveTriggerUris(false);
    }
    public boolean getRemoveTriggerUris() {
        return (Boolean) kp.get("removeTriggerUris");
    }
    /**
     * If true, all URIs that match trigger regular expression are removed
     * from the list of extracted URIs. Default is false.
     */
    public void setRemoveTriggerUris(boolean remove) {
        kp.put("removeTriggerUris",remove);
    }
 
    /**
     * Constructor.
     */
    public ExtractorImpliedURI() {
    }

    
    @Override
    protected boolean shouldProcess(CrawlURI uri) {
        return true;
    }

    /**
     * Perform usual extraction on a CrawlURI
     * 
     * @param curi Crawl URI to process.
     */
    @Override
    public void extract(CrawlURI curi) {<FILL_FUNCTION_BODY>}
    
    /**
     * Utility method for extracting 'implied' URI given a source uri, 
     * trigger pattern, and build pattern. 
     * 
     * @param uri source to check for implied URI
     * @param trigger regex pattern which if matched implies another URI
     * @param build replacement pattern to build the implied URI
     * @return implied URI, or null if none
     */
    protected static String extractImplied(CharSequence uri, Pattern trigger, String build) {
        if (trigger == null) {
            return null;
        }
        Matcher m = trigger.matcher(uri);
        if(m.matches()) {
            String result = m.replaceFirst(build);
            return result; 
        }
        return null; 
    }
}

        List<CrawlURI> links = new ArrayList<CrawlURI>(curi.getOutLinks());
        int max = links.size();
        for (int i = 0; i < max; i++) {
        	CrawlURI link = links.get(i);
            Pattern trigger = getRegex();
            String build = getFormat();
            CharSequence dest = link.getUURI();
            String implied = extractImplied(dest, trigger, build);
            if (implied != null) {
                try {
                    UURI target = UURIFactory.getInstance(implied);
                    LinkContext lc = LinkContext.INFERRED_MISC;
                    Hop hop = Hop.INFERRED;
                    addOutlink(curi, target, lc, hop);
                    numberOfLinksExtracted.incrementAndGet();

                    boolean removeTriggerURI = getRemoveTriggerUris();
                    // remove trigger URI from the outlinks if configured so.
                    if (removeTriggerURI) {
                       if (curi.getOutLinks().remove(link)) {
                               LOGGER.log(Level.FINE, link.getURI() + 
                                     " has been removed from " + 
                                     curi.getURI() + " outlinks list.");
                               numberOfLinksExtracted.decrementAndGet();
                       } else {
                               LOGGER.log(Level.FINE, "Failed to remove " + 
                                      link.getURI() + " from " + 
                                      curi.getURI() + " outlinks list.");
                       }
                    }
                } catch (URIException e) {
                    LOGGER.log(Level.FINE, "bad URI", e);
                }
            }
        }
    
<methods>public non-sealed void <init>() ,public static void add(org.archive.modules.CrawlURI, int, java.lang.String, org.archive.modules.extractor.LinkContext, org.archive.modules.extractor.Hop) throws URIException,public static org.archive.modules.CrawlURI addRelativeToBase(org.archive.modules.CrawlURI, int, java.lang.CharSequence, org.archive.modules.extractor.LinkContext, org.archive.modules.extractor.Hop) throws URIException,public static org.archive.modules.CrawlURI addRelativeToVia(org.archive.modules.CrawlURI, int, java.lang.String, org.archive.modules.extractor.LinkContext, org.archive.modules.extractor.Hop) throws URIException,public org.archive.modules.extractor.ExtractorParameters getExtractorParameters() ,public org.archive.modules.extractor.UriErrorLoggerModule getLoggerModule() ,public void logUriError(URIException, org.archive.net.UURI, java.lang.CharSequence) ,public java.lang.String report() ,public void setExtractorParameters(org.archive.modules.extractor.ExtractorParameters) ,public void setLoggerModule(org.archive.modules.extractor.UriErrorLoggerModule) <variables>public static final org.archive.modules.extractor.ExtractorParameters DEFAULT_PARAMETERS,private static final java.util.logging.Logger LOGGER,protected transient org.archive.modules.extractor.ExtractorParameters extractorParameters,private static final java.util.logging.Logger logger,protected transient org.archive.modules.extractor.UriErrorLoggerModule loggerModule,protected java.util.concurrent.atomic.AtomicLong numberOfLinksExtracted