From 424fe1b372d225d65eb42e6125b24cbb982c5969 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Wed, 1 Jun 2011 19:51:41 -0400
Subject: Stats -> Metrics. Docs in distribution zip. Created MetricUtils.

---
 build.xml                                        | 138 +++++++++++++----
 docs/00_index.mkd                                |   2 +-
 src/com/gitblit/Build.java                       |   3 +-
 src/com/gitblit/BuildSite.java                   |  64 ++++----
 src/com/gitblit/utils/JGitUtils.java             | 144 +----------------
 src/com/gitblit/utils/MetricUtils.java           | 179 +++++++++++++++++++++
 src/com/gitblit/wicket/GitBlitWebApp.java        |   4 +-
 src/com/gitblit/wicket/GitBlitWebApp.properties  |   2 +-
 src/com/gitblit/wicket/pages/MetricsPage.html    |  23 +++
 src/com/gitblit/wicket/pages/MetricsPage.java    | 189 +++++++++++++++++++++++
 src/com/gitblit/wicket/pages/RepositoryPage.html |   2 +-
 src/com/gitblit/wicket/pages/RepositoryPage.java |   4 +-
 src/com/gitblit/wicket/pages/StatsPage.html      |  23 ---
 src/com/gitblit/wicket/pages/StatsPage.java      | 189 -----------------------
 src/com/gitblit/wicket/pages/SummaryPage.html    |   2 +-
 src/com/gitblit/wicket/pages/SummaryPage.java    |   7 +-
 tests/com/gitblit/tests/JGitUtilsTest.java       |   3 +-
 17 files changed, 550 insertions(+), 428 deletions(-)
 create mode 100644 src/com/gitblit/utils/MetricUtils.java
 create mode 100644 src/com/gitblit/wicket/pages/MetricsPage.html
 create mode 100644 src/com/gitblit/wicket/pages/MetricsPage.java
 delete mode 100644 src/com/gitblit/wicket/pages/StatsPage.html
 delete mode 100644 src/com/gitblit/wicket/pages/StatsPage.java

diff --git a/build.xml b/build.xml
index 4b279101..7b22a6ba 100644
--- a/build.xml
+++ b/build.xml
@@ -89,36 +89,6 @@
 			</manifest>
 		</jar>
 
-		<!-- Delete the deploy folder -->
-		<delete dir="${basedir}/deploy" />
-
-		<!-- Create deployment folder structure -->
-		<mkdir dir="${basedir}/deploy" />
-		<copy todir="${basedir}/deploy" file="${project.jar}" />
-		<copy todir="${basedir}/deploy">
-			<fileset dir="${basedir}/distrib">
-				<include name="**/*" />
-			</fileset>
-		</copy>
-
-		<!-- Create Zip deployment -->
-		<property name="distribution.zipfile" value="gitblit-${gb.version}.zip" />
-		<zip destfile="${distribution.zipfile}">
-			<fileset dir="${basedir}/deploy">
-				<include name="**/*" />
-			</fileset>
-		</zip>
-
-		<!-- Delete the deploy folder -->
-		<delete dir="${basedir}/deploy" />
-
-		<!-- Cleanup builds -->
-		<delete>
-			<fileset dir="${basedir}">
-				<include name="${project.jar}" />
-			</fileset>
-		</delete>
-
 		<!-- Build Site -->
 		<delete dir="${basedir}/site" />
 		<mkdir dir="${basedir}/site" />
@@ -195,7 +165,7 @@
 
 			<arg value="--alias" />
 			<arg value="index=overview" />
-			
+
 			<arg value="--alias" />
 			<arg value="properties=gitblit.properties" />
 
@@ -216,6 +186,112 @@
 
 		</java>
 
+		<!-- Delete the deploy folder -->
+		<delete dir="${basedir}/deploy" />
+
+		<!-- Create deployment folder structure -->
+		<mkdir dir="${basedir}/deploy" />
+		<copy todir="${basedir}/deploy" file="${project.jar}" />
+		<copy todir="${basedir}/deploy">
+			<fileset dir="${basedir}/distrib">
+				<include name="**/*" />
+			</fileset>
+		</copy>
+
+		<!-- Build Deployment Docs -->
+		<mkdir dir="${basedir}/deploy/docs" />
+		<copy todir="${basedir}/deploy/docs">
+			<!-- Copy selected Gitblit resources -->
+			<fileset dir="${basedir}/src/com/gitblit/wicket/resources">
+				<include name="background.png" />
+				<include name="gitblit.css" />
+				<include name="markdown.css" />
+				<include name="gitblt_25.png" />
+				<include name="gitblt-favicon.png" />
+				<include name="lock_go_16x16.png" />
+				<include name="lock_pull_16x16.png" />
+				<include name="shield_16x16.png" />
+				<include name="cold_16x16.png" />
+				<include name="bug_16x16.png" />
+				<include name="book_16x16.png" />
+				<include name="blank.png" />
+			</fileset>
+
+			<!-- Copy Doc images -->
+			<fileset dir="${basedir}/docs">
+				<include name="*.png" />
+			</fileset>
+		</copy>
+
+		<!-- Copy google-code-prettify -->
+		<mkdir dir="${basedir}/src/com/gitblit/wicket/pages/prettify" />
+		<copy todir="${basedir}/deploy/docs/prettify">
+			<fileset dir="${basedir}/src/com/gitblit/wicket/pages/prettify">
+				<exclude name="thumbs.db" />
+			</fileset>
+		</copy>
+
+		<!-- Build deployment doc pages -->
+		<java classpath="${project.build.dir}" classname="com.gitblit.BuildSite">
+			<classpath refid="master-classpath" />
+			<arg value="--sourceFolder" />
+			<arg value="${basedir}/docs" />
+
+			<arg value="--outputFolder" />
+			<arg value="${basedir}/deploy/docs" />
+
+			<arg value="--pageHeader" />
+			<arg value="${basedir}/docs/page_header.html" />
+
+			<arg value="--pageFooter" />
+			<arg value="${basedir}/docs/page_footer.html" />
+
+			<arg value="--skip" />
+			<arg value="screenshots" />
+
+			<arg value="--skip" />
+			<arg value="releases" />
+
+			<arg value="--alias" />
+			<arg value="index=overview" />
+
+			<arg value="--alias" />
+			<arg value="properties=gitblit.properties" />
+
+			<arg value="--substitute" />
+			<arg value="%VERSION%=${gb.version}" />
+
+			<arg value="--substitute" />
+			<arg value="%DISTRIBUTION%=${distribution.zipfile}" />
+
+			<arg value="--substitute" />
+			<arg value="%BUILDDATE%=${gb.buildDate}" />
+
+			<arg value="--substitute" />
+			<arg value="%JGIT%=${jgit.version}" />
+
+			<arg value="--load" />
+			<arg value="%PROPERTIES%=${basedir}/distrib/gitblit.properties" />
+
+		</java>
+
+		<!-- Create Zip deployment -->
+		<property name="distribution.zipfile" value="gitblit-${gb.version}.zip" />
+		<zip destfile="${distribution.zipfile}">
+			<fileset dir="${basedir}/deploy">
+				<include name="**/*" />
+			</fileset>
+		</zip>
+
+		<!-- Delete the deploy folder -->
+		<delete dir="${basedir}/deploy" />
+
+		<!-- Cleanup builds -->
+		<delete>
+			<fileset dir="${basedir}">
+				<include name="${project.jar}" />
+			</fileset>
+		</delete>
 		<!-- Cleanup -->
 		<delete dir="${project.build.dir}" />
 	</target>
diff --git a/docs/00_index.mkd b/docs/00_index.mkd
index 9ad1c4e8..0211be6e 100644
--- a/docs/00_index.mkd
+++ b/docs/00_index.mkd
@@ -101,10 +101,10 @@ The following dependencies are automatically downloaded from the Apache Maven re
 - [Log4j](http://logging.apache.org/log4j) (Apache 2.0) 
 - [JCommander](http://jcommander.org) (Apache 2.0)
 - [BouncyCastle](http://www.bouncycastle.org) (MIT/X11)
+- [JSch - Java Secure Channel](http://www.jcraft.com/jsch) (BSD)
 
 ### Other Build Dependencies
 - [Fancybox image viewer](http://fancybox.net) (MIT and GPL dual-licensed)
-- [JSch - Java Secure Channel](http://www.jcraft.com/jsch) (BSD)
 - [JUnit](http://junit.org) (Common Public License)
 
 ## Building from Source
diff --git a/src/com/gitblit/Build.java b/src/com/gitblit/Build.java
index a6d5bb02..3948fd18 100644
--- a/src/com/gitblit/Build.java
+++ b/src/com/gitblit/Build.java
@@ -60,6 +60,7 @@ public class Build {
 		downloadFromApache(MavenObject.MARKDOWNPAPERS, BuildType.RUNTIME);
 		downloadFromApache(MavenObject.BOUNCYCASTLE, BuildType.RUNTIME);
 		downloadFromApache(MavenObject.BOUNCYCASTLE_MAIL, BuildType.RUNTIME);
+		downloadFromApache(MavenObject.JSCH, BuildType.RUNTIME);
 
 		downloadFromEclipse(MavenObject.JGIT, BuildType.RUNTIME);
 		downloadFromEclipse(MavenObject.JGIT_HTTP, BuildType.RUNTIME);
@@ -80,8 +81,6 @@ public class Build {
 		downloadFromApache(MavenObject.MARKDOWNPAPERS, BuildType.COMPILETIME);
 		downloadFromApache(MavenObject.BOUNCYCASTLE, BuildType.COMPILETIME);
 		downloadFromApache(MavenObject.BOUNCYCASTLE_MAIL, BuildType.COMPILETIME);
-
-		downloadFromApache(MavenObject.JSCH, BuildType.RUNTIME);
 		downloadFromApache(MavenObject.JSCH, BuildType.COMPILETIME);
 
 		downloadFromEclipse(MavenObject.JGIT, BuildType.COMPILETIME);
diff --git a/src/com/gitblit/BuildSite.java b/src/com/gitblit/BuildSite.java
index 890cec1e..d96ca6e2 100644
--- a/src/com/gitblit/BuildSite.java
+++ b/src/com/gitblit/BuildSite.java
@@ -73,13 +73,15 @@ public class BuildSite {
 		StringBuilder sb = new StringBuilder();
 		for (File file : markdownFiles) {
 			String documentName = getDocumentName(file);
-			String displayName = documentName;
-			if (aliasMap.containsKey(documentName)) {
-				displayName = aliasMap.get(documentName);
+			if (!params.skips.contains(documentName)) {
+				String displayName = documentName;
+				if (aliasMap.containsKey(documentName)) {
+					displayName = aliasMap.get(documentName);
+				}
+				String fileName = documentName + ".html";
+				sb.append(MessageFormat.format(linkPattern, fileName, displayName));
+				sb.append(" | ");
 			}
-			String fileName = documentName + ".html";
-			sb.append(MessageFormat.format(linkPattern, fileName, displayName));
-			sb.append(" | ");
 		}
 		sb.setLength(sb.length() - 3);
 		sb.trimToSize();
@@ -93,29 +95,32 @@ public class BuildSite {
 		for (File file : markdownFiles) {
 			try {
 				String documentName = getDocumentName(file);
-				String fileName = documentName + ".html";
-				System.out.println(MessageFormat.format("  {0} => {1}", file.getName(), fileName));
-				InputStreamReader reader = new InputStreamReader(new FileInputStream(file),
-						Charset.forName("UTF-8"));
-				String content = MarkdownUtils.transformMarkdown(reader);
-				for (String token : params.substitutions) {
-					String[] kv = token.split("=");
-					content = content.replace(kv[0], kv[1]);
+				if (!params.skips.contains(documentName)) {
+					String fileName = documentName + ".html";
+					System.out.println(MessageFormat.format("  {0} => {1}", file.getName(),
+							fileName));
+					InputStreamReader reader = new InputStreamReader(new FileInputStream(file),
+							Charset.forName("UTF-8"));
+					String content = MarkdownUtils.transformMarkdown(reader);
+					for (String token : params.substitutions) {
+						String[] kv = token.split("=");
+						content = content.replace(kv[0], kv[1]);
+					}
+					for (String alias : params.loads) {
+						String[] kv = alias.split("=");
+						String loadedContent = readContent(new File(kv[1]), "\n");
+						loadedContent = StringUtils.escapeForHtml(loadedContent, false);
+						loadedContent = StringUtils.breakLinesForHtml(loadedContent);
+						content = content.replace(kv[0], loadedContent);
+					}
+					OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(
+							new File(destinationFolder, fileName)), Charset.forName("UTF-8"));
+					writer.write(header);
+					writer.write(content);
+					writer.write(footer);
+					reader.close();
+					writer.close();
 				}
-				for (String alias : params.loads) {
-					String[] kv = alias.split("=");
-					String loadedContent = readContent(new File(kv[1]), "\n");
-					loadedContent = StringUtils.escapeForHtml(loadedContent, false);
-					loadedContent = StringUtils.breakLinesForHtml(loadedContent);
-					content = content.replace(kv[0], loadedContent);
-				}
-				OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(new File(
-						destinationFolder, fileName)), Charset.forName("UTF-8"));
-				writer.write(header);
-				writer.write(content);
-				writer.write(footer);
-				reader.close();
-				writer.close();
 			} catch (Throwable t) {
 				System.err.println("Failed to transform " + file.getName());
 				t.printStackTrace();
@@ -179,6 +184,9 @@ public class BuildSite {
 		@Parameter(names = { "--pageFooter" }, description = "Page Footer HTML Snippet", required = true)
 		public String pageFooter;
 
+		@Parameter(names = { "--skip" }, description = "Filename to skip", required = false)
+		public List<String> skips = new ArrayList<String>();
+
 		@Parameter(names = { "--alias" }, description = "Filename=Linkname aliases", required = false)
 		public List<String> aliases = new ArrayList<String>();
 
diff --git a/src/com/gitblit/utils/JGitUtils.java b/src/com/gitblit/utils/JGitUtils.java
index 4c7f14f6..5f72c9a2 100644
--- a/src/com/gitblit/utils/JGitUtils.java
+++ b/src/com/gitblit/utils/JGitUtils.java
@@ -21,9 +21,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.charset.Charset;
-import java.text.DateFormat;
 import java.text.ParseException;
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -73,7 +71,6 @@ import org.eclipse.jgit.util.io.DisabledOutputStream;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.gitblit.models.Metric;
 import com.gitblit.models.PathModel;
 import com.gitblit.models.PathModel.PathChangeModel;
 import com.gitblit.models.RefModel;
@@ -82,7 +79,7 @@ import com.gitblit.models.TicketModel.Comment;
 
 public class JGitUtils {
 
-	private static final Logger LOGGER = LoggerFactory.getLogger(JGitUtils.class);
+	static final Logger LOGGER = LoggerFactory.getLogger(JGitUtils.class);
 
 	public static Repository createRepository(File repositoriesFolder, String name, boolean bare) {
 		Git git = Git.init().setDirectory(new File(repositoriesFolder, name)).setBare(bare).call();
@@ -780,145 +777,6 @@ public class JGitUtils {
 		return false;
 	}
 
-	public static List<Metric> getDateMetrics(Repository r, boolean includeTotal, String format) {
-		Metric total = new Metric("TOTAL");
-		final Map<String, Metric> metricMap = new HashMap<String, Metric>();
-
-		if (hasCommits(r)) {			
-			try {
-				RevWalk walk = new RevWalk(r);
-				ObjectId object = r.resolve(Constants.HEAD);
-				RevCommit lastCommit = walk.parseCommit(object);
-				walk.markStart(lastCommit);
-				SimpleDateFormat df = new SimpleDateFormat(format);
-				Iterable<RevCommit> revlog = walk;
-				for (RevCommit rev : revlog) {
-					Date d = getCommitDate(rev);
-					String p = df.format(d);
-					if (!metricMap.containsKey(p)) {
-						metricMap.put(p, new Metric(p));
-					}
-					Metric m = metricMap.get(p);
-					m.count++;
-					total.count++;					
-				}
-			} catch (Throwable t) {
-				LOGGER.error("Failed to mine log history for metrics", t);
-			}
-		}
-		List<String> keys = new ArrayList<String>(metricMap.keySet());
-		Collections.sort(keys);
-		List<Metric> metrics = new ArrayList<Metric>();
-		for (String key : keys) {
-			metrics.add(metricMap.get(key));
-		}
-		if (includeTotal) {
-			metrics.add(0, total);
-		}
-		return metrics;
-	}
-
-	public static List<Metric> getDateMetrics(Repository r, boolean includeTotal) {
-		Metric total = new Metric("TOTAL");
-		final Map<String, Metric> metricMap = new HashMap<String, Metric>();
-
-		if (hasCommits(r)) {
-			final List<RefModel> tags = getTags(r, -1);
-			final Map<ObjectId, RefModel> tagMap = new HashMap<ObjectId, RefModel>();
-			for (RefModel tag : tags) {
-				tagMap.put(tag.getCommitId(), tag);
-			}
-			try {
-				RevWalk walk = new RevWalk(r);
-				ObjectId object = r.resolve(Constants.HEAD);
-
-				RevCommit firstCommit = getFirstCommit(r, Constants.HEAD);
-				RevCommit lastCommit = walk.parseCommit(object);
-				int diffDays = (lastCommit.getCommitTime() - firstCommit.getCommitTime())
-						/ (60 * 60 * 24);
-				total.duration = diffDays;
-				DateFormat df;
-				if (diffDays <= 90) {
-					// Days
-					df = new SimpleDateFormat("yyyy-MM-dd");
-				} else if (diffDays > 90 && diffDays < 365) {
-					// Weeks
-					df = new SimpleDateFormat("yyyy-MM (w)");
-				} else {
-					// Months
-					df = new SimpleDateFormat("yyyy-MM");
-				}
-				walk.markStart(lastCommit);
-
-				Iterable<RevCommit> revlog = walk;
-				for (RevCommit rev : revlog) {
-					Date d = getCommitDate(rev);
-					String p = df.format(d);
-					if (!metricMap.containsKey(p)) {
-						metricMap.put(p, new Metric(p));
-					}
-					Metric m = metricMap.get(p);
-					m.count++;
-					total.count++;
-					if (tagMap.containsKey(rev.getId())) {
-						m.tag++;
-						total.tag++;
-					}
-				}
-			} catch (Throwable t) {
-				LOGGER.error("Failed to mine log history for metrics", t);
-			}
-		}
-		List<String> keys = new ArrayList<String>(metricMap.keySet());
-		Collections.sort(keys);
-		List<Metric> metrics = new ArrayList<Metric>();
-		for (String key : keys) {
-			metrics.add(metricMap.get(key));
-		}
-		if (includeTotal) {
-			metrics.add(0, total);
-		}
-		return metrics;
-	}
-	
-	public static List<Metric> getAuthorMetrics(Repository r) {
-		Metric total = new Metric("TOTAL");
-		final Map<String, Metric> metricMap = new HashMap<String, Metric>();
-
-		if (hasCommits(r)) {
-			try {
-				RevWalk walk = new RevWalk(r);
-				ObjectId object = r.resolve(Constants.HEAD);
-				RevCommit lastCommit = walk.parseCommit(object);
-				walk.markStart(lastCommit);
-
-				Iterable<RevCommit> revlog = walk;
-				for (RevCommit rev : revlog) {
-					String p = rev.getAuthorIdent().getName();
-					if (StringUtils.isEmpty(p)) {
-						p = rev.getAuthorIdent().getEmailAddress();
-					}
-					if (!metricMap.containsKey(p)) {
-						metricMap.put(p, new Metric(p));
-					}
-					Metric m = metricMap.get(p);
-					m.count++;
-					total.count++;
-				}
-			} catch (Throwable t) {
-				LOGGER.error("Failed to mine log history for metrics", t);
-			}
-		}
-		List<String> keys = new ArrayList<String>(metricMap.keySet());
-		Collections.sort(keys);
-		List<Metric> metrics = new ArrayList<Metric>();
-		for (String key : keys) {
-			metrics.add(metricMap.get(key));
-		}
-		return metrics;
-	}
-
-
 	public static RefModel getTicketsBranch(Repository r) {
 		RefModel ticgitBranch = null;
 		try {
diff --git a/src/com/gitblit/utils/MetricUtils.java b/src/com/gitblit/utils/MetricUtils.java
new file mode 100644
index 00000000..b1da2738
--- /dev/null
+++ b/src/com/gitblit/utils/MetricUtils.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2011 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.utils;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.models.Metric;
+import com.gitblit.models.RefModel;
+
+public class MetricUtils {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(MetricUtils.class);
+
+	public static List<Metric> getDateMetrics(Repository r, boolean includeTotal, String format) {
+		Metric total = new Metric("TOTAL");
+		final Map<String, Metric> metricMap = new HashMap<String, Metric>();
+	
+		if (JGitUtils.hasCommits(r)) {			
+			try {
+				RevWalk walk = new RevWalk(r);
+				ObjectId object = r.resolve(Constants.HEAD);
+				RevCommit lastCommit = walk.parseCommit(object);
+				walk.markStart(lastCommit);
+				SimpleDateFormat df = new SimpleDateFormat(format);
+				Iterable<RevCommit> revlog = walk;
+				for (RevCommit rev : revlog) {
+					Date d = JGitUtils.getCommitDate(rev);
+					String p = df.format(d);
+					if (!metricMap.containsKey(p)) {
+						metricMap.put(p, new Metric(p));
+					}
+					Metric m = metricMap.get(p);
+					m.count++;
+					total.count++;					
+				}
+			} catch (Throwable t) {
+				JGitUtils.LOGGER.error("Failed to mine log history for metrics", t);
+			}
+		}
+		List<String> keys = new ArrayList<String>(metricMap.keySet());
+		Collections.sort(keys);
+		List<Metric> metrics = new ArrayList<Metric>();
+		for (String key : keys) {
+			metrics.add(metricMap.get(key));
+		}
+		if (includeTotal) {
+			metrics.add(0, total);
+		}
+		return metrics;
+	}
+
+	public static List<Metric> getDateMetrics(Repository r, boolean includeTotal) {
+		Metric total = new Metric("TOTAL");
+		final Map<String, Metric> metricMap = new HashMap<String, Metric>();
+	
+		if (JGitUtils.hasCommits(r)) {
+			final List<RefModel> tags = JGitUtils.getTags(r, -1);
+			final Map<ObjectId, RefModel> tagMap = new HashMap<ObjectId, RefModel>();
+			for (RefModel tag : tags) {
+				tagMap.put(tag.getCommitId(), tag);
+			}
+			try {
+				RevWalk walk = new RevWalk(r);
+				ObjectId object = r.resolve(Constants.HEAD);
+	
+				RevCommit firstCommit = JGitUtils.getFirstCommit(r, Constants.HEAD);
+				RevCommit lastCommit = walk.parseCommit(object);
+				int diffDays = (lastCommit.getCommitTime() - firstCommit.getCommitTime())
+						/ (60 * 60 * 24);
+				total.duration = diffDays;
+				DateFormat df;
+				if (diffDays <= 90) {
+					// Days
+					df = new SimpleDateFormat("yyyy-MM-dd");
+				} else if (diffDays > 90 && diffDays < 365) {
+					// Weeks
+					df = new SimpleDateFormat("yyyy-MM (w)");
+				} else {
+					// Months
+					df = new SimpleDateFormat("yyyy-MM");
+				}
+				walk.markStart(lastCommit);
+	
+				Iterable<RevCommit> revlog = walk;
+				for (RevCommit rev : revlog) {
+					Date d = JGitUtils.getCommitDate(rev);
+					String p = df.format(d);
+					if (!metricMap.containsKey(p)) {
+						metricMap.put(p, new Metric(p));
+					}
+					Metric m = metricMap.get(p);
+					m.count++;
+					total.count++;
+					if (tagMap.containsKey(rev.getId())) {
+						m.tag++;
+						total.tag++;
+					}
+				}
+			} catch (Throwable t) {
+				JGitUtils.LOGGER.error("Failed to mine log history for metrics", t);
+			}
+		}
+		List<String> keys = new ArrayList<String>(metricMap.keySet());
+		Collections.sort(keys);
+		List<Metric> metrics = new ArrayList<Metric>();
+		for (String key : keys) {
+			metrics.add(metricMap.get(key));
+		}
+		if (includeTotal) {
+			metrics.add(0, total);
+		}
+		return metrics;
+	}
+
+	public static List<Metric> getAuthorMetrics(Repository r) {
+		Metric total = new Metric("TOTAL");
+		final Map<String, Metric> metricMap = new HashMap<String, Metric>();
+	
+		if (JGitUtils.hasCommits(r)) {
+			try {
+				RevWalk walk = new RevWalk(r);
+				ObjectId object = r.resolve(Constants.HEAD);
+				RevCommit lastCommit = walk.parseCommit(object);
+				walk.markStart(lastCommit);
+	
+				Iterable<RevCommit> revlog = walk;
+				for (RevCommit rev : revlog) {
+					String p = rev.getAuthorIdent().getName();
+					if (StringUtils.isEmpty(p)) {
+						p = rev.getAuthorIdent().getEmailAddress();
+					}
+					if (!metricMap.containsKey(p)) {
+						metricMap.put(p, new Metric(p));
+					}
+					Metric m = metricMap.get(p);
+					m.count++;
+					total.count++;
+				}
+			} catch (Throwable t) {
+				JGitUtils.LOGGER.error("Failed to mine log history for metrics", t);
+			}
+		}
+		List<String> keys = new ArrayList<String>(metricMap.keySet());
+		Collections.sort(keys);
+		List<Metric> metrics = new ArrayList<Metric>();
+		for (String key : keys) {
+			metrics.add(metricMap.get(key));
+		}
+		return metrics;
+	}
+}
diff --git a/src/com/gitblit/wicket/GitBlitWebApp.java b/src/com/gitblit/wicket/GitBlitWebApp.java
index 71f5aada..61b51e86 100644
--- a/src/com/gitblit/wicket/GitBlitWebApp.java
+++ b/src/com/gitblit/wicket/GitBlitWebApp.java
@@ -41,7 +41,7 @@ import com.gitblit.wicket.pages.PatchPage;
 import com.gitblit.wicket.pages.RawPage;
 import com.gitblit.wicket.pages.RepositoriesPage;
 import com.gitblit.wicket.pages.SearchPage;
-import com.gitblit.wicket.pages.StatsPage;
+import com.gitblit.wicket.pages.MetricsPage;
 import com.gitblit.wicket.pages.SummaryPage;
 import com.gitblit.wicket.pages.TagPage;
 import com.gitblit.wicket.pages.TagsPage;
@@ -84,7 +84,7 @@ public class GitBlitWebApp extends WebApplication {
 		mount("/patch", PatchPage.class, "r", "h", "f");
 		mount("/history", HistoryPage.class, "r", "h", "f");
 		mount("/search", SearchPage.class);
-		mount("/stats", StatsPage.class, "r");
+		mount("/metrics", MetricsPage.class, "r");
 		
 		// setup ticket urls
 		mount("/tickets", TicketsPage.class, "r");
diff --git a/src/com/gitblit/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties
index 45e4503b..ac45a257 100644
--- a/src/com/gitblit/wicket/GitBlitWebApp.properties
+++ b/src/com/gitblit/wicket/GitBlitWebApp.properties
@@ -54,7 +54,7 @@ gb.addition = addition
 gb.modification = modification
 gb.deletion = deletion
 gb.rename = rename
-gb.stats = stats
+gb.metrics = metrics
 gb.markdown = markdown
 gb.changedFiles = changed files 
 gb.filesAdded = {0} files added
diff --git a/src/com/gitblit/wicket/pages/MetricsPage.html b/src/com/gitblit/wicket/pages/MetricsPage.html
new file mode 100644
index 00000000..d6f23e01
--- /dev/null
+++ b/src/com/gitblit/wicket/pages/MetricsPage.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"  
+      xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"  
+      xml:lang="en"  
+      lang="en">
+      
+<body>
+<wicket:extend>
+		<h2>Commit Activity</h2>
+		<div><img wicket:id="commitsChart" /></div>
+		
+		<h2>Commit Activity by Day of Week</h2>
+		<div><img wicket:id="dayOfWeekChart" /></div>
+		
+		<h2>Commit Activity by Time of Day</h2>
+		<div><img wicket:id="timeOfDayChart" /></div>
+
+		<h2>Most Prolific Authors</h2>
+		<div><img wicket:id="authorsChart" /></div>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/com/gitblit/wicket/pages/MetricsPage.java b/src/com/gitblit/wicket/pages/MetricsPage.java
new file mode 100644
index 00000000..2186ae37
--- /dev/null
+++ b/src/com/gitblit/wicket/pages/MetricsPage.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2011 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.wicket.pages;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.eclipse.jgit.lib.Repository;
+import org.wicketstuff.googlecharts.Chart;
+import org.wicketstuff.googlecharts.ChartAxis;
+import org.wicketstuff.googlecharts.ChartAxisType;
+import org.wicketstuff.googlecharts.ChartProvider;
+import org.wicketstuff.googlecharts.ChartType;
+import org.wicketstuff.googlecharts.IChartData;
+import org.wicketstuff.googlecharts.LineStyle;
+import org.wicketstuff.googlecharts.MarkerType;
+import org.wicketstuff.googlecharts.ShapeMarker;
+
+import com.gitblit.models.Metric;
+import com.gitblit.utils.MetricUtils;
+import com.gitblit.wicket.WicketUtils;
+
+public class MetricsPage extends RepositoryPage {
+
+	public MetricsPage(PageParameters params) {
+		super(params);
+		Repository r = getRepository();
+		insertLinePlot("commitsChart", MetricUtils.getDateMetrics(r, false));
+		insertBarPlot("dayOfWeekChart", getDayOfWeekMetrics(r));
+		insertLinePlot("timeOfDayChart", getTimeOfDayMetrics(r));
+		insertPieChart("authorsChart", getAuthorMetrics(r));
+	}
+
+	private void insertLinePlot(String wicketId, List<Metric> metrics) {
+		if ((metrics != null) && (metrics.size() > 0)) {
+			IChartData data = WicketUtils.getChartData(metrics);
+
+			ChartProvider provider = new ChartProvider(new Dimension(400, 100), ChartType.LINE,
+					data);
+			ChartAxis dateAxis = new ChartAxis(ChartAxisType.BOTTOM);
+			dateAxis.setLabels(new String[] { metrics.get(0).name,
+					metrics.get(metrics.size() / 2).name, metrics.get(metrics.size() - 1).name });
+			provider.addAxis(dateAxis);
+
+			ChartAxis commitAxis = new ChartAxis(ChartAxisType.LEFT);
+			commitAxis.setLabels(new String[] { "",
+					String.valueOf((int) WicketUtils.maxValue(metrics)) });
+			provider.addAxis(commitAxis);
+
+			provider.setLineStyles(new LineStyle[] { new LineStyle(2, 4, 0), new LineStyle(0, 4, 1) });
+			provider.addShapeMarker(new ShapeMarker(MarkerType.CIRCLE, Color.BLUE, 1, -1, 5));
+
+			add(new Chart(wicketId, provider));
+		} else {
+			add(WicketUtils.newBlankImage(wicketId));
+		}
+	}
+
+	private void insertBarPlot(String wicketId, List<Metric> metrics) {
+		if ((metrics != null) && (metrics.size() > 0)) {
+			IChartData data = WicketUtils.getChartData(metrics);
+
+			ChartProvider provider = new ChartProvider(new Dimension(400, 100),
+					ChartType.BAR_VERTICAL_SET, data);
+			ChartAxis dateAxis = new ChartAxis(ChartAxisType.BOTTOM);
+			List<String> labels = new ArrayList<String>();
+			for (Metric metric : metrics) {
+				labels.add(metric.name);
+			}
+			dateAxis.setLabels(labels.toArray(new String[labels.size()]));
+			provider.addAxis(dateAxis);
+
+			ChartAxis commitAxis = new ChartAxis(ChartAxisType.LEFT);
+			commitAxis.setLabels(new String[] { "",
+					String.valueOf((int) WicketUtils.maxValue(metrics)) });
+			provider.addAxis(commitAxis);
+
+			add(new Chart(wicketId, provider));
+		} else {
+			add(WicketUtils.newBlankImage(wicketId));
+		}
+	}
+
+	private void insertPieChart(String wicketId, List<Metric> metrics) {
+		if ((metrics != null) && (metrics.size() > 0)) {
+			IChartData data = WicketUtils.getChartData(metrics);
+			List<String> labels = new ArrayList<String>();
+			for (Metric metric : metrics) {
+				labels.add(metric.name);
+			}
+			ChartProvider provider = new ChartProvider(new Dimension(400, 200), ChartType.PIE, data);
+			provider.setPieLabels(labels.toArray(new String[labels.size()]));
+			add(new Chart(wicketId, provider));
+		} else {
+			add(WicketUtils.newBlankImage(wicketId));
+		}
+	}
+
+	private List<Metric> getDayOfWeekMetrics(Repository repository) {
+		List<Metric> list = MetricUtils.getDateMetrics(repository, false, "E");
+		SimpleDateFormat sdf = new SimpleDateFormat("E");
+		Calendar cal = Calendar.getInstance();
+
+		List<Metric> sorted = new ArrayList<Metric>(7);
+		int firstDayOfWeek = cal.getFirstDayOfWeek();
+		int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
+
+		// rewind date to first day of week
+		cal.add(Calendar.DATE, firstDayOfWeek - dayOfWeek);
+		for (int i = 0; i < 7; i++) {
+			String day = sdf.format(cal.getTime());
+			for (Metric metric : list) {
+				if (metric.name.equals(day)) {
+					sorted.add(i, metric);
+					list.remove(metric);
+					break;
+				}
+			}
+			cal.add(Calendar.DATE, 1);
+		}
+		return sorted;
+	}
+
+	private List<Metric> getTimeOfDayMetrics(Repository repository) {
+		SimpleDateFormat ndf = new SimpleDateFormat("yyyy-MM-dd");
+		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+		List<Metric> list = MetricUtils.getDateMetrics(repository, false, "yyyy-MM-dd HH:mm");
+		Calendar cal = Calendar.getInstance();
+
+		for (Metric metric : list) {
+			try {
+				Date date = sdf.parse(metric.name);
+				cal.setTime(date);
+				double y = cal.get(Calendar.HOUR_OF_DAY) + (cal.get(Calendar.MINUTE) / 60d);
+				metric.duration = (int) (date.getTime() / 60000L);
+				metric.count = y;
+				metric.name = ndf.format(date);
+			} catch (ParseException p) {
+			}
+		}
+		return list;
+	}
+
+	private List<Metric> getAuthorMetrics(Repository repository) {
+		List<Metric> authors = MetricUtils.getAuthorMetrics(repository);
+		Collections.sort(authors, new Comparator<Metric>() {
+			@Override
+			public int compare(Metric o1, Metric o2) {
+				if (o1.count > o2.count) {
+					return -1;
+				} else if (o1.count < o2.count) {
+					return 1;					
+				}
+				return 0;
+			}
+		});
+		if (authors.size() > 10) {
+			return authors.subList(0, 9);
+		}
+		return authors;
+	}
+
+	@Override
+	protected String getPageName() {
+		return getString("gb.metrics");
+	}
+}
diff --git a/src/com/gitblit/wicket/pages/RepositoryPage.html b/src/com/gitblit/wicket/pages/RepositoryPage.html
index 0f245eff..ffb484f1 100644
--- a/src/com/gitblit/wicket/pages/RepositoryPage.html
+++ b/src/com/gitblit/wicket/pages/RepositoryPage.html
@@ -18,7 +18,7 @@
 		
 			<!-- page nav links -->
 			<div class="page_nav">		
-				<a wicket:id="summary"><wicket:message key="gb.summary"></wicket:message></a> | <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a> | <a wicket:id="branches"><wicket:message key="gb.branches"></wicket:message></a> | <a wicket:id="tags"><wicket:message key="gb.tags"></wicket:message></a> | <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a>  | <a wicket:id="stats"><wicket:message key="gb.stats"></wicket:message></a> <span wicket:id="extra"><span wicket:id="extraSeparator"></span><span wicket:id="extraLink"></span></span>
+				<a wicket:id="summary"><wicket:message key="gb.summary"></wicket:message></a> | <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a> | <a wicket:id="branches"><wicket:message key="gb.branches"></wicket:message></a> | <a wicket:id="tags"><wicket:message key="gb.tags"></wicket:message></a> | <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a>  | <a wicket:id="metrics"><wicket:message key="gb.metrics"></wicket:message></a> <span wicket:id="extra"><span wicket:id="extraSeparator"></span><span wicket:id="extraLink"></span></span>
 			</div>
 		</div>
 		
diff --git a/src/com/gitblit/wicket/pages/RepositoryPage.java b/src/com/gitblit/wicket/pages/RepositoryPage.java
index 2610c4c6..143d885a 100644
--- a/src/com/gitblit/wicket/pages/RepositoryPage.java
+++ b/src/com/gitblit/wicket/pages/RepositoryPage.java
@@ -75,7 +75,7 @@ public abstract class RepositoryPage extends BasePage {
 			put("branches", "gb.branches");
 			put("tags", "gb.tags");
 			put("tree", "gb.tree");
-			put("stats", "gb.stats");
+			put("metrics", "gb.metrics");
 			put("tickets", "gb.tickets");
 			put("edit", "gb.edit");
 		}
@@ -104,7 +104,7 @@ public abstract class RepositoryPage extends BasePage {
 				WicketUtils.newRepositoryParameter(repositoryName)));
 		add(new BookmarkablePageLink<Void>("tree", TreePage.class,
 				WicketUtils.newRepositoryParameter(repositoryName)));
-		add(new BookmarkablePageLink<Void>("stats", StatsPage.class,
+		add(new BookmarkablePageLink<Void>("metrics", MetricsPage.class,
 				WicketUtils.newRepositoryParameter(repositoryName)));
 
 		// per-repository extra page links
diff --git a/src/com/gitblit/wicket/pages/StatsPage.html b/src/com/gitblit/wicket/pages/StatsPage.html
deleted file mode 100644
index d6f23e01..00000000
--- a/src/com/gitblit/wicket/pages/StatsPage.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml"  
-      xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"  
-      xml:lang="en"  
-      lang="en">
-      
-<body>
-<wicket:extend>
-		<h2>Commit Activity</h2>
-		<div><img wicket:id="commitsChart" /></div>
-		
-		<h2>Commit Activity by Day of Week</h2>
-		<div><img wicket:id="dayOfWeekChart" /></div>
-		
-		<h2>Commit Activity by Time of Day</h2>
-		<div><img wicket:id="timeOfDayChart" /></div>
-
-		<h2>Most Prolific Authors</h2>
-		<div><img wicket:id="authorsChart" /></div>
-
-</wicket:extend>
-</body>
-</html>
\ No newline at end of file
diff --git a/src/com/gitblit/wicket/pages/StatsPage.java b/src/com/gitblit/wicket/pages/StatsPage.java
deleted file mode 100644
index 0b16211e..00000000
--- a/src/com/gitblit/wicket/pages/StatsPage.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright 2011 gitblit.com.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.gitblit.wicket.pages;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.List;
-
-import org.apache.wicket.PageParameters;
-import org.eclipse.jgit.lib.Repository;
-import org.wicketstuff.googlecharts.Chart;
-import org.wicketstuff.googlecharts.ChartAxis;
-import org.wicketstuff.googlecharts.ChartAxisType;
-import org.wicketstuff.googlecharts.ChartProvider;
-import org.wicketstuff.googlecharts.ChartType;
-import org.wicketstuff.googlecharts.IChartData;
-import org.wicketstuff.googlecharts.LineStyle;
-import org.wicketstuff.googlecharts.MarkerType;
-import org.wicketstuff.googlecharts.ShapeMarker;
-
-import com.gitblit.models.Metric;
-import com.gitblit.utils.JGitUtils;
-import com.gitblit.wicket.WicketUtils;
-
-public class StatsPage extends RepositoryPage {
-
-	public StatsPage(PageParameters params) {
-		super(params);
-		Repository r = getRepository();
-		insertLinePlot("commitsChart", JGitUtils.getDateMetrics(r, false));
-		insertBarPlot("dayOfWeekChart", getDayOfWeekMetrics(r));
-		insertLinePlot("timeOfDayChart", getTimeOfDayMetrics(r));
-		insertPieChart("authorsChart", getAuthorMetrics(r));
-	}
-
-	private void insertLinePlot(String wicketId, List<Metric> metrics) {
-		if ((metrics != null) && (metrics.size() > 0)) {
-			IChartData data = WicketUtils.getChartData(metrics);
-
-			ChartProvider provider = new ChartProvider(new Dimension(400, 100), ChartType.LINE,
-					data);
-			ChartAxis dateAxis = new ChartAxis(ChartAxisType.BOTTOM);
-			dateAxis.setLabels(new String[] { metrics.get(0).name,
-					metrics.get(metrics.size() / 2).name, metrics.get(metrics.size() - 1).name });
-			provider.addAxis(dateAxis);
-
-			ChartAxis commitAxis = new ChartAxis(ChartAxisType.LEFT);
-			commitAxis.setLabels(new String[] { "",
-					String.valueOf((int) WicketUtils.maxValue(metrics)) });
-			provider.addAxis(commitAxis);
-
-			provider.setLineStyles(new LineStyle[] { new LineStyle(2, 4, 0), new LineStyle(0, 4, 1) });
-			provider.addShapeMarker(new ShapeMarker(MarkerType.CIRCLE, Color.BLUE, 1, -1, 5));
-
-			add(new Chart(wicketId, provider));
-		} else {
-			add(WicketUtils.newBlankImage(wicketId));
-		}
-	}
-
-	private void insertBarPlot(String wicketId, List<Metric> metrics) {
-		if ((metrics != null) && (metrics.size() > 0)) {
-			IChartData data = WicketUtils.getChartData(metrics);
-
-			ChartProvider provider = new ChartProvider(new Dimension(400, 100),
-					ChartType.BAR_VERTICAL_SET, data);
-			ChartAxis dateAxis = new ChartAxis(ChartAxisType.BOTTOM);
-			List<String> labels = new ArrayList<String>();
-			for (Metric metric : metrics) {
-				labels.add(metric.name);
-			}
-			dateAxis.setLabels(labels.toArray(new String[labels.size()]));
-			provider.addAxis(dateAxis);
-
-			ChartAxis commitAxis = new ChartAxis(ChartAxisType.LEFT);
-			commitAxis.setLabels(new String[] { "",
-					String.valueOf((int) WicketUtils.maxValue(metrics)) });
-			provider.addAxis(commitAxis);
-
-			add(new Chart(wicketId, provider));
-		} else {
-			add(WicketUtils.newBlankImage(wicketId));
-		}
-	}
-
-	private void insertPieChart(String wicketId, List<Metric> metrics) {
-		if ((metrics != null) && (metrics.size() > 0)) {
-			IChartData data = WicketUtils.getChartData(metrics);
-			List<String> labels = new ArrayList<String>();
-			for (Metric metric : metrics) {
-				labels.add(metric.name);
-			}
-			ChartProvider provider = new ChartProvider(new Dimension(400, 200), ChartType.PIE, data);
-			provider.setPieLabels(labels.toArray(new String[labels.size()]));
-			add(new Chart(wicketId, provider));
-		} else {
-			add(WicketUtils.newBlankImage(wicketId));
-		}
-	}
-
-	private List<Metric> getDayOfWeekMetrics(Repository repository) {
-		List<Metric> list = JGitUtils.getDateMetrics(repository, false, "E");
-		SimpleDateFormat sdf = new SimpleDateFormat("E");
-		Calendar cal = Calendar.getInstance();
-
-		List<Metric> sorted = new ArrayList<Metric>(7);
-		int firstDayOfWeek = cal.getFirstDayOfWeek();
-		int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
-
-		// rewind date to first day of week
-		cal.add(Calendar.DATE, firstDayOfWeek - dayOfWeek);
-		for (int i = 0; i < 7; i++) {
-			String day = sdf.format(cal.getTime());
-			for (Metric metric : list) {
-				if (metric.name.equals(day)) {
-					sorted.add(i, metric);
-					list.remove(metric);
-					break;
-				}
-			}
-			cal.add(Calendar.DATE, 1);
-		}
-		return sorted;
-	}
-
-	private List<Metric> getTimeOfDayMetrics(Repository repository) {
-		SimpleDateFormat ndf = new SimpleDateFormat("yyyy-MM-dd");
-		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
-		List<Metric> list = JGitUtils.getDateMetrics(repository, false, "yyyy-MM-dd HH:mm");
-		Calendar cal = Calendar.getInstance();
-
-		for (Metric metric : list) {
-			try {
-				Date date = sdf.parse(metric.name);
-				cal.setTime(date);
-				double y = cal.get(Calendar.HOUR_OF_DAY) + (cal.get(Calendar.MINUTE) / 60d);
-				metric.duration = (int) (date.getTime() / 60000L);
-				metric.count = y;
-				metric.name = ndf.format(date);
-			} catch (ParseException p) {
-			}
-		}
-		return list;
-	}
-
-	private List<Metric> getAuthorMetrics(Repository repository) {
-		List<Metric> authors = JGitUtils.getAuthorMetrics(repository);
-		Collections.sort(authors, new Comparator<Metric>() {
-			@Override
-			public int compare(Metric o1, Metric o2) {
-				if (o1.count > o2.count) {
-					return -1;
-				} else if (o1.count < o2.count) {
-					return 1;					
-				}
-				return 0;
-			}
-		});
-		if (authors.size() > 10) {
-			return authors.subList(0, 9);
-		}
-		return authors;
-	}
-
-	@Override
-	protected String getPageName() {
-		return getString("gb.stats");
-	}
-}
diff --git a/src/com/gitblit/wicket/pages/SummaryPage.html b/src/com/gitblit/wicket/pages/SummaryPage.html
index 1a90c998..ed94192a 100644
--- a/src/com/gitblit/wicket/pages/SummaryPage.html
+++ b/src/com/gitblit/wicket/pages/SummaryPage.html
@@ -19,7 +19,7 @@
 				<tr><th><wicket:message key="gb.description">[description]</wicket:message></th><td><span wicket:id="repositoryDescription">[repository description]</span></td></tr>
 				<tr><th><wicket:message key="gb.owner">[owner]</wicket:message></th><td><span wicket:id="repositoryOwner">[repository owner]</span></td></tr>
 				<tr><th><wicket:message key="gb.lastChange">[last change]</wicket:message></th><td><span wicket:id="repositoryLastChange">[repository last change]</span></td></tr>
-				<tr><th><wicket:message key="gb.stats">[stats]</wicket:message></th><td><span wicket:id="repositoryStats">[repository stats]</span></td></tr>
+				<tr><th><wicket:message key="gb.metrics">[metrics]</wicket:message></th><td><span wicket:id="repositoryMetrics">[repository metrics]</span></td></tr>
 				<tr><th valign="top"><wicket:message key="gb.url">[URL]</wicket:message></th><td><img style="vertical-align: top; padding-right:5px;" wicket:id="accessRestrictionIcon" /><span wicket:id="repositoryCloneUrl">[repository clone url]</span></td></tr>
 			</table>
 		</div>
diff --git a/src/com/gitblit/wicket/pages/SummaryPage.java b/src/com/gitblit/wicket/pages/SummaryPage.java
index 1157d30c..f8206941 100644
--- a/src/com/gitblit/wicket/pages/SummaryPage.java
+++ b/src/com/gitblit/wicket/pages/SummaryPage.java
@@ -43,6 +43,7 @@ import com.gitblit.GitBlit;
 import com.gitblit.Keys;
 import com.gitblit.models.Metric;
 import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.MetricUtils;
 import com.gitblit.utils.StringUtils;
 import com.gitblit.utils.TimeUtils;
 import com.gitblit.wicket.WicketUtils;
@@ -72,7 +73,7 @@ public class SummaryPage extends RepositoryPage {
 		List<Metric> metrics = null;
 		Metric metricsTotal = null;
 		if (GitBlit.getBoolean(Keys.web.generateActivityGraph, true)) {
-			metrics = JGitUtils.getDateMetrics(r, true);
+			metrics = MetricUtils.getDateMetrics(r, true);
 			metricsTotal = metrics.remove(0);
 		}
 
@@ -83,9 +84,9 @@ public class SummaryPage extends RepositoryPage {
 		add(WicketUtils.createTimestampLabel("repositoryLastChange", JGitUtils.getLastChange(r),
 				getTimeZone()));
 		if (metricsTotal == null) {
-			add(new Label("repositoryStats", ""));
+			add(new Label("repositoryMetrics", ""));
 		} else {
-			add(new Label("repositoryStats", MessageFormat.format(
+			add(new Label("repositoryMetrics", MessageFormat.format(
 					"{0} commits and {1} tags in {2}", metricsTotal.count, metricsTotal.tag,
 					TimeUtils.duration(metricsTotal.duration))));
 		}
diff --git a/tests/com/gitblit/tests/JGitUtilsTest.java b/tests/com/gitblit/tests/JGitUtilsTest.java
index 9007b42e..14d318f3 100644
--- a/tests/com/gitblit/tests/JGitUtilsTest.java
+++ b/tests/com/gitblit/tests/JGitUtilsTest.java
@@ -36,6 +36,7 @@ import com.gitblit.models.RefModel;
 import com.gitblit.models.TicketModel;
 import com.gitblit.models.TicketModel.Comment;
 import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.MetricUtils;
 
 public class JGitUtilsTest extends TestCase {
 
@@ -184,7 +185,7 @@ public class JGitUtilsTest extends TestCase {
 
 	public void testMetrics() throws Exception {
 		Repository repository = GitBlitSuite.getHelloworldRepository();
-		List<Metric> metrics = JGitUtils.getDateMetrics(repository, true);
+		List<Metric> metrics = MetricUtils.getDateMetrics(repository, true);
 		repository.close();
 		assertTrue("No metrics found!", metrics.size() > 0);
 	}
-- 
cgit v1.2.3