class CrawlSummaryReport extends Report {

    @Override
    public void write(PrintWriter writer, StatisticsTracker stats) {<FILL_FUNCTION_BODY>}

    @Override
    public String getFilename() {
        return "crawl-report.txt";
    }

}

        CrawlStatSnapshot snapshot = stats.getLastSnapshot(); 
        writer.println("crawl name: " + stats.getCrawlController().getMetadata().getJobName());
        String crawlStatus = stats.getCrawlController().getCrawlExitStatus().desc;
        if (stats.getCrawlController().isRunning() ) {
        	crawlStatus = StringUtils.capitalize(stats.getCrawlController().getState().toString().toLowerCase()) + " - Active"; 
        } 
        writer.println("crawl status: " + crawlStatus);
        writer.println("duration: " +
                ArchiveUtils.formatMillisecondsToConventional(stats.getCrawlElapsedTime()));
        writer.println();
        
        // seeds summary
        stats.tallySeeds();
        writer.println("seeds crawled: " + stats.seedsCrawled);
        writer.println("seeds uncrawled: " + (stats.seedsTotal - stats.seedsCrawled));
        writer.println();

        // hostsDistribution contains all hosts crawled plus an entry for dns.
        writer.println("hosts visited: " + (stats.serverCache.hostKeys().size()-1));
        writer.println();

        // URI totals
        writer.println("URIs processed: " + snapshot.finishedUriCount);
        writer.println("URI successes: " + snapshot.downloadedUriCount);
        writer.println("URI failures: " + snapshot.downloadFailures);
        writer.println("URI disregards: " + snapshot.downloadDisregards);
        writer.println();
        
        // novel/duplicate/not-modified URI counts
        writer.println("novel URIs: " + stats.crawledBytes.get(
                CrawledBytesHistotable.NOVELCOUNT));
        if(stats.crawledBytes.containsKey(CrawledBytesHistotable.
                DUPLICATECOUNT)) {
            writer.println("duplicate-by-hash URIs: " + 
                    stats.crawledBytes.get(CrawledBytesHistotable.
                            DUPLICATECOUNT));
        }
        if(stats.crawledBytes.containsKey(CrawledBytesHistotable.
                NOTMODIFIEDCOUNT)) {
            writer.println("not-modified URIs: " +
                    stats.crawledBytes.get(CrawledBytesHistotable.
                            NOTMODIFIEDCOUNT)); 
        }
        writer.println();
        
        // total bytes 'crawled' (which includes the size of 
        // refetched-but-unwritten-duplicates and reconsidered-but-not-modified
        writer.println("total crawled bytes: " + snapshot.bytesProcessed +
                " (" + ArchiveUtils.formatBytesForDisplay(snapshot.bytesProcessed) +
                ") ");
        // novel/duplicate/not-modified byte counts
        writer.println("novel crawled bytes: " 
                + stats.crawledBytes.get(CrawledBytesHistotable.NOVEL)
                + " (" + ArchiveUtils.formatBytesForDisplay(
                        stats.crawledBytes.get(CrawledBytesHistotable.NOVEL))
                +  ")");
        if(stats.crawledBytes.containsKey(CrawledBytesHistotable.DUPLICATE)) {
            writer.println("duplicate-by-hash crawled bytes: " 
                    + stats.crawledBytes.get(CrawledBytesHistotable.DUPLICATE)
                    + " (" + ArchiveUtils.formatBytesForDisplay(
                            stats.crawledBytes.get(CrawledBytesHistotable.DUPLICATE))
                    +  ") ");
        }
        if(stats.crawledBytes.containsKey(CrawledBytesHistotable.NOTMODIFIED)) {
            writer.println("not-modified crawled bytes: " 
                    + stats.crawledBytes.get(CrawledBytesHistotable.NOTMODIFIED)
                    + " (" + ArchiveUtils.formatBytesForDisplay(
                            stats.crawledBytes.get(CrawledBytesHistotable.NOTMODIFIED))
                    +  ") ");
        }
        writer.println();
        
        // rates
        writer.println("URIs/sec: " +
                ArchiveUtils.doubleToString(snapshot.docsPerSecond,2));
        writer.println("KB/sec: " + snapshot.totalKiBPerSec);
    
<methods>public void <init>() ,public abstract java.lang.String getFilename() ,public boolean getShouldReportAtEndOfCrawl() ,public boolean getShouldReportDuringCrawl() ,public void setShouldReportAtEndOfCrawl(boolean) ,public void setShouldReportDuringCrawl(boolean) ,public abstract void write(java.io.PrintWriter, org.archive.crawler.reporting.StatisticsTracker) <variables>private boolean shouldReportAtEndOfCrawl,private boolean shouldReportDuringCrawl