From 8ef71343dfef8914e9383e159915baa6a341eeef Mon Sep 17 00:00:00 2001
From: slene <vslene@gmail.com>
Date: Thu, 20 Mar 2014 17:25:04 +0800
Subject: [PATCH 01/41] fix link

---
 routers/repo/single.go | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/routers/repo/single.go b/routers/repo/single.go
index c10d30a7d6..2bc77c1c01 100644
--- a/routers/repo/single.go
+++ b/routers/repo/single.go
@@ -137,10 +137,9 @@ func Single(ctx *middleware.Context, params martini.Params) {
 				return
 			} else {
 				// current repo branch link
-				urlPrefix := "http://" + base.Domain + branchLink
 
 				ctx.Data["FileName"] = readmeFile.Name
-				ctx.Data["FileContent"] = string(base.RenderMarkdown(blob.Contents(), urlPrefix))
+				ctx.Data["FileContent"] = string(base.RenderMarkdown(blob.Contents(), branchLink))
 			}
 		}
 	}

From c3532718a79f102f4e19c11868a2c618b482eb6a Mon Sep 17 00:00:00 2001
From: slene <vslene@gmail.com>
Date: Thu, 20 Mar 2014 17:25:48 +0800
Subject: [PATCH 02/41] add anchor

---
 public/css/markdown.css | 59 ++++++++++++++++++++++++++++++++++++++---
 public/js/app.js        | 21 ++++++++++++++-
 2 files changed, 76 insertions(+), 4 deletions(-)

diff --git a/public/css/markdown.css b/public/css/markdown.css
index 9283fb847c..1edc3b626c 100644
--- a/public/css/markdown.css
+++ b/public/css/markdown.css
@@ -15,7 +15,8 @@
   line-height: 1.7;
   padding: 15px 0 0;
   margin: 0 0 15px;
-  color: #666;
+  color: #444;
+  font-weight: bold;
 }
 
 .markdown h1,
@@ -86,6 +87,10 @@
   margin-top: 6px;
 }
 
+.markdown li:first-child {
+  margin-top: 0;
+}
+
 .markdown dl dt {
   font-style: italic;
   margin-top: 9px;
@@ -130,11 +135,11 @@
 }
 
 .markdown > pre > ol.linenums > li:first-child {
-  padding-top: 6px;
+  padding-top: 12px;
 }
 
 .markdown > pre > ol.linenums > li:last-child {
-  padding-bottom: 6px;
+  padding-bottom: 12px;
 }
 
 .markdown > pre > ol.linenums > li {
@@ -163,6 +168,54 @@
   color: #fff;
 }
 
+.markdown .anchor-wrap {
+  /*margin-top: -50px;*/
+  /*padding-top: 50px;*/
+}
+
+.markdown h1 a, .markdown h2 a, .markdown h3 a {
+  text-decoration: none;
+}
+
+.markdown h1 a.anchor,
+.markdown h2 a.anchor,
+.markdown h3 a.anchor,
+.markdown h4 a.anchor,
+.markdown h5 a.anchor,
+.markdown h6 a.anchor {
+  text-decoration:none;
+  line-height:1;
+  padding-left:0;
+  margin-left:5px;
+  top:15%;
+}
+.markdown a span.octicon {
+  font-size: 16px;
+  font-family: "FontAwesome";
+  line-height: 1;
+  display: inline-block;
+  text-decoration: none;
+  -webkit-font-smoothing: antialiased;
+}
+
+.markdown a span.octicon-link {
+  display: none;
+  color: #000;
+}
+
+.markdown a span.octicon-link:before {
+  content: "\f0c1";
+}
+
+.markdown h1:hover .octicon-link,
+.markdown h2:hover .octicon-link,
+.markdown h3:hover .octicon-link,
+.markdown h4:hover .octicon-link,
+.markdown h5:hover .octicon-link,
+.markdown h6:hover .octicon-link {
+  display:inline-block
+}
+
 /* Author: jmblog */
 /* Project: https://github.com/jmblog/color-themes-for-google-code-prettify */
 /* GitHub Theme */
diff --git a/public/js/app.js b/public/js/app.js
index 30296bc337..f3e8d6d1d2 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -66,9 +66,28 @@ var Gogits = {
 
     // render markdown
     Gogits.renderMarkdown = function () {
-        var $pre = $('.markdown').find('pre > code').parent();
+        var $md = $('.markdown');
+        var $pre = $md.find('pre > code').parent();
         $pre.addClass("prettyprint");
         prettyPrint();
+
+        // Set anchor.
+        var headers = {};
+        $md.find('h1, h2, h3, h4, h5, h6').each(function () {
+            var node = $(this);
+            var val = encodeURIComponent(node.text().toLowerCase().replace(/[^\w\- ]/g, '').replace(/[ ]/g, '-'));
+            var name = val;
+            if(headers[val] > 0){
+                name = val + '-' + headers[val];
+            }
+            if(headers[val] == undefined){
+                headers[val] = 1;
+            }else{
+                headers[val] += 1;
+            }
+            node = node.wrap('<div id="' + name + '" class="anchor-wrap" ></div>');
+            node.append('<a class="anchor" href="#' + name + '"><span class="octicon octicon-link"></span></a>');
+        });
     }
 
 })(jQuery);

From 21379e30a18fed473ae2bbeb41332919ff80497d Mon Sep 17 00:00:00 2001
From: slene <vslene@gmail.com>
Date: Thu, 20 Mar 2014 17:31:18 +0800
Subject: [PATCH 03/41] fix link

---
 modules/base/markdown.go        |  4 ++--
 public/css/gogs.css             |  8 ++++++++
 templates/repo/single_file.tmpl | 10 +++++++---
 3 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/modules/base/markdown.go b/modules/base/markdown.go
index a9f4cbf0d7..e49e111c0e 100644
--- a/modules/base/markdown.go
+++ b/modules/base/markdown.go
@@ -36,7 +36,7 @@ func isLink(link []byte) bool {
 func IsMarkdownFile(name string) bool {
 	name = strings.ToLower(name)
 	switch filepath.Ext(name) {
-	case "md", "markdown":
+	case "md", "markdown", "mdown":
 		return true
 	}
 	return false
@@ -61,7 +61,7 @@ type CustomRender struct {
 func (options *CustomRender) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
 	if len(link) > 0 && !isLink(link) {
 		if link[0] == '#' {
-			link = append([]byte(options.urlPrefix), link...)
+			// link = append([]byte(options.urlPrefix), link...)
 		} else {
 			link = []byte(path.Join(options.urlPrefix, string(link)))
 		}
diff --git a/public/css/gogs.css b/public/css/gogs.css
index a4767c1c8b..83d1b96fe2 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -647,6 +647,14 @@ html, body {
     padding: 30px 30px 50px;
 }
 
+.file-content .file-body.file-code {
+    padding: 0;
+}
+
+.file-content .file-body.file-code > pre {
+    border: none;
+}
+
 .branch-list th, .commit-list th {
     background-color: #FFF;
     line-height: 28px !important;
diff --git a/templates/repo/single_file.tmpl b/templates/repo/single_file.tmpl
index b4626053fd..0c1c3713f6 100644
--- a/templates/repo/single_file.tmpl
+++ b/templates/repo/single_file.tmpl
@@ -1,6 +1,10 @@
 <div class="panel panel-default file-content">
     <div class="panel-heading file-head">
-        <i class="icon fa fa-book"></i> {{.FileName}}
+        {{if .ReadmeExist}}
+            <i class="icon fa fa-book"></i>
+        {{else}}
+            <i class="icon fa fa-file-text-o"></i>
+        {{end}}{{.FileName}}
     </div>
     {{if .FileIsLarge}}
         <div class="panel-footer">
@@ -12,8 +16,8 @@
                 {{.FileContent|str2html}}
             </div>
         {{else}}
-            <div class="panel-body file-body markdown">
-                <pre><code>{{.FileContent}}</code></pre>
+            <div class="panel-body file-body file-code markdown">
+                <pre class="linenums"><code>{{.FileContent}}</code></pre>
             </div>
         {{end}}
     {{end}}

From 9f9cd6bfc61d82ee0a3d31cee112be7975b8ca86 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Thu, 20 Mar 2014 07:50:26 -0400
Subject: [PATCH 04/41] Work on admin

---
 .gitignore                     |  4 +++-
 conf/app.ini                   |  4 ++++
 models/user.go                 |  1 +
 modules/base/conf.go           |  2 ++
 modules/middleware/auth.go     | 14 +++++++++++++-
 modules/middleware/context.go  | 16 +++++++++++++---
 routers/admin/admin.go         | 24 ++++++++++++++++++++++++
 routers/dashboard.go           |  4 ++--
 routers/dev/template.go        |  2 +-
 routers/repo/repo.go           |  4 ++--
 routers/repo/single.go         | 16 ++++++++--------
 routers/user/setting.go        | 18 +++++++++---------
 routers/user/user.go           | 28 ++++++++++++++--------------
 templates/admin/dashboard.tmpl | 24 ++++++++++++++++++++++++
 templates/admin/repos.tmpl     | 23 +++++++++++++++++++++++
 templates/admin/users.tmpl     | 23 +++++++++++++++++++++++
 templates/base/navbar.tmpl     |  1 +
 templates/repo/setting.tmpl    |  4 ++++
 web.go                         |  6 ++++++
 19 files changed, 177 insertions(+), 41 deletions(-)
 create mode 100644 routers/admin/admin.go
 create mode 100644 templates/admin/dashboard.tmpl
 create mode 100644 templates/admin/repos.tmpl
 create mode 100644 templates/admin/users.tmpl

diff --git a/.gitignore b/.gitignore
index 3e550c3fc7..ad27cc8be8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,6 @@ gogs
 *.db
 *.log
 custom/
-.vendor/
\ No newline at end of file
+.vendor/
+.idea/
+*.iml
\ No newline at end of file
diff --git a/conf/app.ini b/conf/app.ini
index 658f7c0151..21090ceba5 100644
--- a/conf/app.ini
+++ b/conf/app.ini
@@ -27,6 +27,10 @@ PASSWD =
 ; For "postgres" only, either "disable", "require" or "verify-full"
 SSL_MODE = disable
 
+[admin]
+; Administor's name, which should be same as the user name you want to authorize
+NAME = admin
+
 [security]
 ; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!!
 SECRET_KEY = !#@FDEWREWR&*(
diff --git a/models/user.go b/models/user.go
index 76cf2d20ce..8f74fd53fb 100644
--- a/models/user.go
+++ b/models/user.go
@@ -51,6 +51,7 @@ type User struct {
 	Location      string
 	Website       string
 	IsActive      bool
+	IsAdmin       bool
 	Rands         string    `xorm:"VARCHAR(10)"`
 	Created       time.Time `xorm:"created"`
 	Updated       time.Time `xorm:"updated"`
diff --git a/modules/base/conf.go b/modules/base/conf.go
index fdbf3ad385..c904c5b39c 100644
--- a/modules/base/conf.go
+++ b/modules/base/conf.go
@@ -32,6 +32,7 @@ var (
 	AppUrl      string
 	Domain      string
 	SecretKey   string
+	AdminName   string
 	Cfg         *goconfig.ConfigFile
 	MailService *Mailer
 )
@@ -173,6 +174,7 @@ func init() {
 	AppUrl = Cfg.MustValue("server", "ROOT_URL")
 	Domain = Cfg.MustValue("server", "DOMAIN")
 	SecretKey = Cfg.MustValue("security", "SECRET_KEY")
+	AdminName = strings.ToLower(Cfg.MustValue("admin", "NAME"))
 }
 
 func NewServices() {
diff --git a/modules/middleware/auth.go b/modules/middleware/auth.go
index d45a21e988..b67f766bd7 100644
--- a/modules/middleware/auth.go
+++ b/modules/middleware/auth.go
@@ -20,7 +20,7 @@ func SignInRequire(redirect bool) martini.Handler {
 			return
 		} else if !ctx.User.IsActive && base.Service.RegisterEmailConfirm {
 			ctx.Data["Title"] = "Activate Your Account"
-			ctx.Render.HTML(200, "user/active", ctx.Data)
+			ctx.HTML(200, "user/active")
 			return
 		}
 	}
@@ -31,6 +31,18 @@ func SignOutRequire() martini.Handler {
 	return func(ctx *Context) {
 		if ctx.IsSigned {
 			ctx.Redirect("/")
+			return
 		}
 	}
 }
+
+// AdminRequire requires user signed in as administor.
+func AdminRequire() martini.Handler {
+	return func(ctx *Context) {
+		if ctx.User.LowerName != base.AdminName && !ctx.User.IsAdmin {
+			ctx.Error(403)
+			return
+		}
+		ctx.Data["PageIsAdmin"] = true
+	}
+}
diff --git a/modules/middleware/context.go b/modules/middleware/context.go
index 6ac87de3be..744cdfc10c 100644
--- a/modules/middleware/context.go
+++ b/modules/middleware/context.go
@@ -14,6 +14,7 @@ import (
 
 	"github.com/gogits/gogs/models"
 	"github.com/gogits/gogs/modules/auth"
+	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/log"
 )
 
@@ -61,24 +62,29 @@ func (ctx *Context) HasError() bool {
 	return hasErr.(bool)
 }
 
+// HTML calls render.HTML underlying but reduce one argument.
+func (ctx *Context) HTML(status int, name string, htmlOpt ...HTMLOptions) {
+	ctx.Render.HTML(status, name, ctx.Data, htmlOpt...)
+}
+
 // RenderWithErr used for page has form validation but need to prompt error to users.
 func (ctx *Context) RenderWithErr(msg, tpl string, form auth.Form) {
 	ctx.Data["HasError"] = true
 	ctx.Data["ErrorMsg"] = msg
 	auth.AssignForm(form, ctx.Data)
-	ctx.HTML(200, tpl, ctx.Data)
+	ctx.HTML(200, tpl)
 }
 
 // Handle handles and logs error by given status.
 func (ctx *Context) Handle(status int, title string, err error) {
 	log.Error("%s: %v", title, err)
 	if martini.Dev == martini.Prod {
-		ctx.HTML(500, "status/500", ctx.Data)
+		ctx.HTML(500, "status/500")
 		return
 	}
 
 	ctx.Data["ErrorMsg"] = err
-	ctx.HTML(status, fmt.Sprintf("status/%d", status), ctx.Data)
+	ctx.HTML(status, fmt.Sprintf("status/%d", status))
 }
 
 // InitContext initializes a classic context for a request.
@@ -106,6 +112,10 @@ func InitContext() martini.Handler {
 			ctx.Data["SignedUser"] = user
 			ctx.Data["SignedUserId"] = user.Id
 			ctx.Data["SignedUserName"] = user.LowerName
+
+			if ctx.User.IsAdmin || ctx.User.LowerName == base.AdminName {
+				ctx.Data["IsAdmin"] = true
+			}
 		}
 
 		ctx.Data["PageStartTime"] = time.Now()
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
new file mode 100644
index 0000000000..c7523b7f59
--- /dev/null
+++ b/routers/admin/admin.go
@@ -0,0 +1,24 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package admin
+
+import (
+	"github.com/gogits/gogs/modules/middleware"
+)
+
+func Dashboard(ctx *middleware.Context) {
+	ctx.Data["Title"] = "Admin Dashboard"
+	ctx.HTML(200, "admin/dashboard")
+}
+
+func Users(ctx *middleware.Context) {
+	ctx.Data["Title"] = "User Management"
+	ctx.HTML(200, "admin/users")
+}
+
+func Repositories(ctx *middleware.Context) {
+	ctx.Data["Title"] = "Repository Management"
+	ctx.HTML(200, "admin/repos")
+}
diff --git a/routers/dashboard.go b/routers/dashboard.go
index 6c194ad9e5..f61d67b7de 100644
--- a/routers/dashboard.go
+++ b/routers/dashboard.go
@@ -15,10 +15,10 @@ func Home(ctx *middleware.Context) {
 		return
 	}
 	ctx.Data["PageIsHome"] = true
-	ctx.HTML(200, "home", ctx.Data)
+	ctx.HTML(200, "home")
 }
 
 func Help(ctx *middleware.Context) {
 	ctx.Data["PageIsHelp"] = true
-	ctx.HTML(200, "help", ctx.Data)
+	ctx.HTML(200, "help")
 }
diff --git a/routers/dev/template.go b/routers/dev/template.go
index 7d5225ece7..d2f77ac4d5 100644
--- a/routers/dev/template.go
+++ b/routers/dev/template.go
@@ -21,5 +21,5 @@ func TemplatePreview(ctx *middleware.Context, params martini.Params) {
 	ctx.Data["Code"] = "2014031910370000009fff6782aadb2162b4a997acb69d4400888e0b9274657374"
 	ctx.Data["ActiveCodeLives"] = base.Service.ActiveCodeLives / 60
 	ctx.Data["ResetPwdCodeLives"] = base.Service.ResetPwdCodeLives / 60
-	ctx.HTML(200, params["_1"], ctx.Data)
+	ctx.HTML(200, params["_1"])
 }
diff --git a/routers/repo/repo.go b/routers/repo/repo.go
index b38473b18a..556cc4343c 100644
--- a/routers/repo/repo.go
+++ b/routers/repo/repo.go
@@ -18,7 +18,7 @@ func Create(ctx *middleware.Context, form auth.CreateRepoForm) {
 	ctx.Data["Licenses"] = models.Licenses
 
 	if ctx.Req.Method == "GET" {
-		ctx.HTML(200, "repo/create", ctx.Data)
+		ctx.HTML(200, "repo/create")
 		return
 	}
 
@@ -45,7 +45,7 @@ func SettingPost(ctx *middleware.Context) {
 	case "delete":
 		if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") {
 			ctx.Data["ErrorMsg"] = "Please make sure you entered repository name is correct."
-			ctx.HTML(200, "repo/setting", ctx.Data)
+			ctx.HTML(200, "repo/setting")
 			return
 		}
 
diff --git a/routers/repo/single.go b/routers/repo/single.go
index c10d30a7d6..ebf64dc665 100644
--- a/routers/repo/single.go
+++ b/routers/repo/single.go
@@ -38,7 +38,7 @@ func Branches(ctx *middleware.Context, params martini.Params) {
 	ctx.Data["Branches"] = brs
 	ctx.Data["IsRepoToolbarBranches"] = true
 
-	ctx.HTML(200, "repo/branches", ctx.Data)
+	ctx.HTML(200, "repo/branches")
 }
 
 func Single(ctx *middleware.Context, params martini.Params) {
@@ -67,7 +67,7 @@ func Single(ctx *middleware.Context, params martini.Params) {
 		return
 	} else if len(brs) == 0 {
 		ctx.Data["IsBareRepo"] = true
-		ctx.HTML(200, "repo/single", ctx.Data)
+		ctx.HTML(200, "repo/single")
 		return
 	}
 
@@ -178,7 +178,7 @@ func Single(ctx *middleware.Context, params martini.Params) {
 	ctx.Data["Treenames"] = treenames
 	ctx.Data["IsRepoToolbarSource"] = true
 	ctx.Data["BranchLink"] = branchLink
-	ctx.HTML(200, "repo/single", ctx.Data)
+	ctx.HTML(200, "repo/single")
 }
 
 func Setting(ctx *middleware.Context, params martini.Params) {
@@ -195,7 +195,7 @@ func Setting(ctx *middleware.Context, params martini.Params) {
 		return
 	} else if len(brs) == 0 {
 		ctx.Data["IsBareRepo"] = true
-		ctx.HTML(200, "repo/setting", ctx.Data)
+		ctx.HTML(200, "repo/setting")
 		return
 	}
 
@@ -206,7 +206,7 @@ func Setting(ctx *middleware.Context, params martini.Params) {
 
 	ctx.Data["Title"] = title + " - settings"
 	ctx.Data["IsRepoToolbarSetting"] = true
-	ctx.HTML(200, "repo/setting", ctx.Data)
+	ctx.HTML(200, "repo/setting")
 }
 
 func Commits(ctx *middleware.Context, params martini.Params) {
@@ -230,17 +230,17 @@ func Commits(ctx *middleware.Context, params martini.Params) {
 	ctx.Data["Reponame"] = params["reponame"]
 	ctx.Data["CommitCount"] = commits.Len()
 	ctx.Data["Commits"] = commits
-	ctx.HTML(200, "repo/commits", ctx.Data)
+	ctx.HTML(200, "repo/commits")
 }
 
 func Issues(ctx *middleware.Context) {
 	ctx.Data["IsRepoToolbarIssues"] = true
-	ctx.HTML(200, "repo/issues", ctx.Data)
+	ctx.HTML(200, "repo/issues")
 }
 
 func Pulls(ctx *middleware.Context) {
 	ctx.Data["IsRepoToolbarPulls"] = true
-	ctx.HTML(200, "repo/pulls", ctx.Data)
+	ctx.HTML(200, "repo/pulls")
 }
 
 func Action(ctx *middleware.Context, params martini.Params) {
diff --git a/routers/user/setting.go b/routers/user/setting.go
index 053f327f0f..f0c7a8a5b1 100644
--- a/routers/user/setting.go
+++ b/routers/user/setting.go
@@ -24,13 +24,13 @@ func Setting(ctx *middleware.Context, form auth.UpdateProfileForm) {
 	ctx.Data["Owner"] = user
 
 	if ctx.Req.Method == "GET" {
-		ctx.HTML(200, "user/setting", ctx.Data)
+		ctx.HTML(200, "user/setting")
 		return
 	}
 
 	// below is for POST requests
 	if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) {
-		ctx.HTML(200, "user/setting", ctx.Data)
+		ctx.HTML(200, "user/setting")
 		return
 	}
 
@@ -45,7 +45,7 @@ func Setting(ctx *middleware.Context, form auth.UpdateProfileForm) {
 	}
 
 	ctx.Data["IsSuccess"] = true
-	ctx.HTML(200, "user/setting", ctx.Data)
+	ctx.HTML(200, "user/setting")
 	log.Trace("%s User setting updated: %s", ctx.Req.RequestURI, ctx.User.LowerName)
 }
 
@@ -55,7 +55,7 @@ func SettingPassword(ctx *middleware.Context, form auth.UpdatePasswdForm) {
 	ctx.Data["IsUserPageSettingPasswd"] = true
 
 	if ctx.Req.Method == "GET" {
-		ctx.HTML(200, "user/password", ctx.Data)
+		ctx.HTML(200, "user/password")
 		return
 	}
 
@@ -82,7 +82,7 @@ func SettingPassword(ctx *middleware.Context, form auth.UpdatePasswdForm) {
 	}
 
 	ctx.Data["Owner"] = user
-	ctx.HTML(200, "user/password", ctx.Data)
+	ctx.HTML(200, "user/password")
 	log.Trace("%s User password updated: %s", ctx.Req.RequestURI, ctx.User.LowerName)
 }
 
@@ -123,7 +123,7 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) {
 	// Add new SSH key.
 	if ctx.Req.Method == "POST" {
 		if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) {
-			ctx.HTML(200, "user/publickey", ctx.Data)
+			ctx.HTML(200, "user/publickey")
 			return
 		}
 
@@ -155,7 +155,7 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) {
 	ctx.Data["PageIsUserSetting"] = true
 	ctx.Data["IsUserPageSettingSSH"] = true
 	ctx.Data["Keys"] = keys
-	ctx.HTML(200, "user/publickey", ctx.Data)
+	ctx.HTML(200, "user/publickey")
 }
 
 func SettingNotification(ctx *middleware.Context) {
@@ -163,7 +163,7 @@ func SettingNotification(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Notification"
 	ctx.Data["PageIsUserSetting"] = true
 	ctx.Data["IsUserPageSettingNotify"] = true
-	ctx.HTML(200, "user/notification", ctx.Data)
+	ctx.HTML(200, "user/notification")
 }
 
 func SettingSecurity(ctx *middleware.Context) {
@@ -171,5 +171,5 @@ func SettingSecurity(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Security"
 	ctx.Data["PageIsUserSetting"] = true
 	ctx.Data["IsUserPageSettingSecurity"] = true
-	ctx.HTML(200, "user/security", ctx.Data)
+	ctx.HTML(200, "user/security")
 }
diff --git a/routers/user/user.go b/routers/user/user.go
index f495cb13ab..2b759e4192 100644
--- a/routers/user/user.go
+++ b/routers/user/user.go
@@ -34,7 +34,7 @@ func Dashboard(ctx *middleware.Context) {
 		return
 	}
 	ctx.Data["Feeds"] = feeds
-	ctx.HTML(200, "user/dashboard", ctx.Data)
+	ctx.HTML(200, "user/dashboard")
 }
 
 func Profile(ctx *middleware.Context, params martini.Params) {
@@ -70,19 +70,19 @@ func Profile(ctx *middleware.Context, params martini.Params) {
 	}
 
 	ctx.Data["PageIsUserProfile"] = true
-	ctx.HTML(200, "user/profile", ctx.Data)
+	ctx.HTML(200, "user/profile")
 }
 
 func SignIn(ctx *middleware.Context, form auth.LogInForm) {
 	ctx.Data["Title"] = "Log In"
 
 	if ctx.Req.Method == "GET" {
-		ctx.HTML(200, "user/signin", ctx.Data)
+		ctx.HTML(200, "user/signin")
 		return
 	}
 
 	if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) {
-		ctx.HTML(200, "user/signin", ctx.Data)
+		ctx.HTML(200, "user/signin")
 		return
 	}
 
@@ -113,7 +113,7 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) {
 	ctx.Data["PageIsSignUp"] = true
 
 	if ctx.Req.Method == "GET" {
-		ctx.HTML(200, "user/signup", ctx.Data)
+		ctx.HTML(200, "user/signup")
 		return
 	}
 
@@ -126,7 +126,7 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) {
 	}
 
 	if ctx.HasError() {
-		ctx.HTML(200, "user/signup", ctx.Data)
+		ctx.HTML(200, "user/signup")
 		return
 	}
 
@@ -158,7 +158,7 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) {
 		ctx.Data["IsSendRegisterMail"] = true
 		ctx.Data["Email"] = u.Email
 		ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60
-		ctx.Render.HTML(200, "user/active", ctx.Data)
+		ctx.HTML(200, "user/active")
 		return
 	}
 	ctx.Redirect("/user/login")
@@ -170,7 +170,7 @@ func Delete(ctx *middleware.Context) {
 	ctx.Data["IsUserPageSettingDelete"] = true
 
 	if ctx.Req.Method == "GET" {
-		ctx.HTML(200, "user/delete", ctx.Data)
+		ctx.HTML(200, "user/delete")
 		return
 	}
 
@@ -195,7 +195,7 @@ func Delete(ctx *middleware.Context) {
 		}
 	}
 
-	ctx.HTML(200, "user/delete", ctx.Data)
+	ctx.HTML(200, "user/delete")
 }
 
 const (
@@ -218,15 +218,15 @@ func Feeds(ctx *middleware.Context, form auth.FeedsForm) {
 }
 
 func Issues(ctx *middleware.Context) {
-	ctx.HTML(200, "user/issues", ctx.Data)
+	ctx.HTML(200, "user/issues")
 }
 
 func Pulls(ctx *middleware.Context) {
-	ctx.HTML(200, "user/pulls", ctx.Data)
+	ctx.HTML(200, "user/pulls")
 }
 
 func Stars(ctx *middleware.Context) {
-	ctx.HTML(200, "user/stars", ctx.Data)
+	ctx.HTML(200, "user/stars")
 }
 
 func Activate(ctx *middleware.Context) {
@@ -244,7 +244,7 @@ func Activate(ctx *middleware.Context) {
 		} else {
 			ctx.Data["ServiceNotEnabled"] = true
 		}
-		ctx.Render.HTML(200, "user/active", ctx.Data)
+		ctx.HTML(200, "user/active")
 		return
 	}
 
@@ -263,5 +263,5 @@ func Activate(ctx *middleware.Context) {
 	}
 
 	ctx.Data["IsActivateFailed"] = true
-	ctx.Render.HTML(200, "user/active", ctx.Data)
+	ctx.HTML(200, "user/active")
 }
diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl
new file mode 100644
index 0000000000..84456c85b8
--- /dev/null
+++ b/templates/admin/dashboard.tmpl
@@ -0,0 +1,24 @@
+{{template "base/head" .}}
+{{template "base/navbar" .}}
+<div id="gogs-body" class="container" data-page="admin">
+    <div id="gogs-user-setting-nav" class="col-md-3">
+        <ul class="list-group" data-init="tabs">
+            <li class="list-group-item active"><a href="/admin"><i class="fa fa-tachometer fa-lg"></i> Dashboard</a></li>
+            <li class="list-group-item"><a href="/admin/users"><i class="fa fa-users fa-lg"></i> Users</a></li>
+            <li class="list-group-item"><a href="/admin/repos"><i class="fa fa-book fa-lg"></i> Repositories</a></li>
+        </ul>
+    </div>
+
+    <div id="gogs-admin-container" class="col-md-9">
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                Statistic
+            </div>
+
+            <div class="panel-body">
+                Gogs database has 4 users, 3 repositories, 4 SSH keys.
+            </div>
+        </div>
+    </div>
+</div>
+{{template "base/footer" .}}
\ No newline at end of file
diff --git a/templates/admin/repos.tmpl b/templates/admin/repos.tmpl
new file mode 100644
index 0000000000..ec7f47e090
--- /dev/null
+++ b/templates/admin/repos.tmpl
@@ -0,0 +1,23 @@
+{{template "base/head" .}}
+{{template "base/navbar" .}}
+<div id="gogs-body" class="container" data-page="admin">
+    <div id="gogs-user-setting-nav" class="col-md-3">
+        <ul class="list-group" data-init="tabs">
+            <li class="list-group-item"><a href="/admin"><i class="fa fa-tachometer fa-lg"></i> Dashboard</a></li>
+            <li class="list-group-item"><a href="/admin/users"><i class="fa fa-users fa-lg"></i> Users</a></li>
+            <li class="list-group-item active"><a href="/admin/repos"><i class="fa fa-book fa-lg"></i> Repositories</a></li>
+        </ul>
+    </div>
+
+    <div id="gogs-admin-container" class="col-md-9">
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                Repository Management
+            </div>
+
+            <div class="panel-body">
+            </div>
+        </div>
+    </div>
+</div>
+{{template "base/footer" .}}
\ No newline at end of file
diff --git a/templates/admin/users.tmpl b/templates/admin/users.tmpl
new file mode 100644
index 0000000000..8acf256d05
--- /dev/null
+++ b/templates/admin/users.tmpl
@@ -0,0 +1,23 @@
+{{template "base/head" .}}
+{{template "base/navbar" .}}
+<div id="gogs-body" class="container" data-page="admin">
+    <div id="gogs-user-setting-nav" class="col-md-3">
+        <ul class="list-group" data-init="tabs">
+            <li class="list-group-item"><a href="/admin"><i class="fa fa-tachometer fa-lg"></i> Dashboard</a></li>
+            <li class="list-group-item active"><a href="/admin/users"><i class="fa fa-users fa-lg"></i> Users</a></li>
+            <li class="list-group-item"><a href="/admin/repos"><i class="fa fa-book fa-lg"></i> Repositories</a></li>
+        </ul>
+    </div>
+
+    <div id="gogs-admin-container" class="col-md-9">
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                User Management
+            </div>
+
+            <div class="panel-body">
+            </div>
+        </div>
+    </div>
+</div>
+{{template "base/footer" .}}
\ No newline at end of file
diff --git a/templates/base/navbar.tmpl b/templates/base/navbar.tmpl
index e0d796a87b..9c064d07e7 100644
--- a/templates/base/navbar.tmpl
+++ b/templates/base/navbar.tmpl
@@ -10,6 +10,7 @@
             </a>
             <a class="navbar-right gogs-nav-item{{if .PageIsNewRepo}} active{{end}}" href="/repo/create" data-toggle="tooltip" data-placement="bottom" title="New Repository"><i class="fa fa-plus fa-lg"></i></a>
             <a class="navbar-right gogs-nav-item{{if .PageIsUserSetting}} active{{end}}" href="/user/setting"  data-toggle="tooltip" data-placement="bottom" title="Setting"><i class="fa fa-cogs fa-lg"></i></a>
+            {{if .IsAdmin}}<a class="navbar-right gogs-nav-item{{if .PageIsAdmin}} active{{end}}" href="/admin"  data-toggle="tooltip" data-placement="bottom" title="Admin"><i class="fa fa-gear fa-lg"></i></a>{{end}}
             {{else}}<a id="gogs-nav-signin" class="gogs-nav-item navbar-right navbar-btn btn btn-danger" href="/user/login/">Sign in</a>{{end}}
         </nav>
     </div>
diff --git a/templates/repo/setting.tmpl b/templates/repo/setting.tmpl
index 06f0ed4d50..a2fb1771d4 100644
--- a/templates/repo/setting.tmpl
+++ b/templates/repo/setting.tmpl
@@ -10,20 +10,24 @@
             <li class="list-group-item"><a href="#">Notifications</a></li>-->
         </ul>
     </div>
+
     <div id="gogs-repo-setting-container" class="col-md-9">
         {{if .ErrorMsg}}<p class="alert alert-danger">{{.ErrorMsg}}</p>{{end}}
         <div class="panel panel-default">
             <div class="panel-heading">
                 Repository Options
             </div>
+
             <div class="panel-body">
                 
             </div>
         </div>
+
         <div class="panel panel-warning">
             <div class="panel-heading">
                 Danger Zone
             </div>
+            
             <div class="panel-body">
                 <button type="button" class="btn btn-default pull-right" href="#delete-repository-modal" data-toggle="modal">
                     Delete this repository
diff --git a/web.go b/web.go
index ceb193e6fd..a5a8305aee 100644
--- a/web.go
+++ b/web.go
@@ -21,6 +21,7 @@ import (
 	"github.com/gogits/gogs/modules/log"
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/routers"
+	"github.com/gogits/gogs/routers/admin"
 	"github.com/gogits/gogs/routers/dev"
 	"github.com/gogits/gogs/routers/repo"
 	"github.com/gogits/gogs/routers/user"
@@ -99,6 +100,11 @@ func runWeb(*cli.Context) {
 
 	m.Get("/help", routers.Help)
 
+	adminReq := middleware.AdminRequire()
+	m.Any("/admin", reqSignIn, adminReq, admin.Dashboard)
+	m.Any("/admin/users", reqSignIn, adminReq, admin.Users)
+	m.Any("/admin/repos", reqSignIn, adminReq, admin.Repositories)
+
 	m.Post("/:username/:reponame/settings", reqSignIn, middleware.RepoAssignment(true), repo.SettingPost)
 	m.Get("/:username/:reponame/settings", reqSignIn, middleware.RepoAssignment(true), repo.Setting)
 

From 4cf6cc63b0679aaf5fe8b74a2aaf0bd92b1f12d3 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Thu, 20 Mar 2014 08:02:14 -0400
Subject: [PATCH 05/41] Work on admin

---
 conf/app.ini                  | 4 ----
 models/user.go                | 8 +++++++-
 modules/base/conf.go          | 2 --
 modules/middleware/auth.go    | 2 +-
 modules/middleware/context.go | 6 +-----
 routers/user/user.go          | 2 +-
 6 files changed, 10 insertions(+), 14 deletions(-)

diff --git a/conf/app.ini b/conf/app.ini
index 21090ceba5..658f7c0151 100644
--- a/conf/app.ini
+++ b/conf/app.ini
@@ -27,10 +27,6 @@ PASSWD =
 ; For "postgres" only, either "disable", "require" or "verify-full"
 SSL_MODE = disable
 
-[admin]
-; Administor's name, which should be same as the user name you want to authorize
-NAME = admin
-
 [security]
 ; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!!
 SECRET_KEY = !#@FDEWREWR&*(
diff --git a/models/user.go b/models/user.go
index 8f74fd53fb..fd89af6b3f 100644
--- a/models/user.go
+++ b/models/user.go
@@ -137,7 +137,13 @@ func RegisterUser(user *User) (*User, error) {
 		}
 		return nil, err
 	}
-	return user, nil
+
+	if user.Id == 1 {
+		user.IsAdmin = true
+		user.IsActive = true
+		_, err = orm.Id(user.Id).UseBool().Update(user)
+	}
+	return user, err
 }
 
 // get user by erify code
diff --git a/modules/base/conf.go b/modules/base/conf.go
index c904c5b39c..fdbf3ad385 100644
--- a/modules/base/conf.go
+++ b/modules/base/conf.go
@@ -32,7 +32,6 @@ var (
 	AppUrl      string
 	Domain      string
 	SecretKey   string
-	AdminName   string
 	Cfg         *goconfig.ConfigFile
 	MailService *Mailer
 )
@@ -174,7 +173,6 @@ func init() {
 	AppUrl = Cfg.MustValue("server", "ROOT_URL")
 	Domain = Cfg.MustValue("server", "DOMAIN")
 	SecretKey = Cfg.MustValue("security", "SECRET_KEY")
-	AdminName = strings.ToLower(Cfg.MustValue("admin", "NAME"))
 }
 
 func NewServices() {
diff --git a/modules/middleware/auth.go b/modules/middleware/auth.go
index b67f766bd7..44033abb8f 100644
--- a/modules/middleware/auth.go
+++ b/modules/middleware/auth.go
@@ -39,7 +39,7 @@ func SignOutRequire() martini.Handler {
 // AdminRequire requires user signed in as administor.
 func AdminRequire() martini.Handler {
 	return func(ctx *Context) {
-		if ctx.User.LowerName != base.AdminName && !ctx.User.IsAdmin {
+		if !ctx.User.IsAdmin {
 			ctx.Error(403)
 			return
 		}
diff --git a/modules/middleware/context.go b/modules/middleware/context.go
index 744cdfc10c..cb3cbabca6 100644
--- a/modules/middleware/context.go
+++ b/modules/middleware/context.go
@@ -14,7 +14,6 @@ import (
 
 	"github.com/gogits/gogs/models"
 	"github.com/gogits/gogs/modules/auth"
-	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/log"
 )
 
@@ -112,10 +111,7 @@ func InitContext() martini.Handler {
 			ctx.Data["SignedUser"] = user
 			ctx.Data["SignedUserId"] = user.Id
 			ctx.Data["SignedUserName"] = user.LowerName
-
-			if ctx.User.IsAdmin || ctx.User.LowerName == base.AdminName {
-				ctx.Data["IsAdmin"] = true
-			}
+			ctx.Data["IsAdmin"] = ctx.User.IsAdmin
 		}
 
 		ctx.Data["PageStartTime"] = time.Now()
diff --git a/routers/user/user.go b/routers/user/user.go
index 2b759e4192..be2c4d3839 100644
--- a/routers/user/user.go
+++ b/routers/user/user.go
@@ -153,7 +153,7 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) {
 	log.Trace("%s User created: %s", ctx.Req.RequestURI, strings.ToLower(form.UserName))
 
 	// Send confirmation e-mail.
-	if base.Service.RegisterEmailConfirm {
+	if base.Service.RegisterEmailConfirm && u.Id > 1 {
 		mailer.SendRegisterMail(ctx.Render, u)
 		ctx.Data["IsSendRegisterMail"] = true
 		ctx.Data["Email"] = u.Email

From cb80111e8923ff9317199dca61509e32408279ca Mon Sep 17 00:00:00 2001
From: FuXiaoHei <fuxiaohei@hexiaz.com>
Date: Thu, 20 Mar 2014 20:12:31 +0800
Subject: [PATCH 06/41] guide page for bare repo some ui fix

---
 public/css/gogs.css             | 14 ++++++++++++++
 public/js/app.js                | 30 +++++++++++++++++++++++++-----
 routers/repo/single.go          |  6 ++++--
 templates/repo/single.tmpl      |  2 +-
 templates/repo/single_bare.tmpl | 31 +++++++++++++++++++++++++++++++
 templates/repo/toolbar.tmpl     |  3 +--
 6 files changed, 76 insertions(+), 10 deletions(-)
 create mode 100644 templates/repo/single_bare.tmpl

diff --git a/public/css/gogs.css b/public/css/gogs.css
index a4767c1c8b..95f44d0fd4 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -724,6 +724,20 @@ html, body {
     background-color: #FFF;
 }
 
+.commit-list .date {
+    width: 120px;
+}
+
+.guide-box pre, .guide-box .input-group {
+    margin-top: 20px;
+    margin-bottom: 30px;
+    line-height: 24px;
+}
+
+.guide-box input[readonly] {
+    background-color: #FFF;
+}
+
 /* wrapper and footer */
 
 #wrapper {
diff --git a/public/js/app.js b/public/js/app.js
index 30296bc337..e1aeb8a51a 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -41,15 +41,15 @@ var Gogits = {
         });
     };
     Gogits.initPopovers = function () {
-        var hideAllPopovers = function() {
-           $('[data-toggle=popover]').each(function() {
+        var hideAllPopovers = function () {
+            $('[data-toggle=popover]').each(function () {
                 $(this).popover('hide');
-            });  
+            });
         };
 
-        $(document).on('click', function(e) {
+        $(document).on('click', function (e) {
             var $e = $(e.target);
-            if($e.data('toggle') == 'popover'||$e.parents("[data-toggle=popover], .popover").length > 0){
+            if ($e.data('toggle') == 'popover' || $e.parents("[data-toggle=popover], .popover").length > 0) {
                 return;
             }
             hideAllPopovers();
@@ -142,6 +142,23 @@ function initUserSetting() {
     });
 }
 
+function initRepository() {
+    var $guide = $('.guide-box');
+    if ($guide.length) {
+        var $url = $('#guide-clone-url');
+        $guide.find('button[data-url]').on("click",function () {
+            var $this = $(this);
+            if (!$this.hasClass('btn-primary')) {
+                $guide.find('.btn-primary').removeClass('btn-primary').addClass("btn-default");
+                $(this).addClass('btn-primary').removeClass('btn-default');
+                $url.val($this.data("url"));
+                $guide.find('span.clone-url').text($this.data('url'));
+            }
+        }).eq(0).trigger("click");
+        // todo copy to clipboard
+    }
+}
+
 (function ($) {
     $(function () {
         initCore();
@@ -152,5 +169,8 @@ function initUserSetting() {
         if (body.data("page") == "user") {
             initUserSetting();
         }
+        if ($('.gogs-repo-nav').length) {
+            initRepository();
+        }
     });
 })(jQuery);
diff --git a/routers/repo/single.go b/routers/repo/single.go
index ebf64dc665..4a6af9ff50 100644
--- a/routers/repo/single.go
+++ b/routers/repo/single.go
@@ -59,6 +59,8 @@ func Single(ctx *middleware.Context, params martini.Params) {
 		return
 	}
 
+	ctx.Data["IsRepoToolbarSource"] = true
+
 	// Branches.
 	brs, err := models.GetBranches(params["username"], params["reponame"])
 	if err != nil {
@@ -176,7 +178,6 @@ func Single(ctx *middleware.Context, params martini.Params) {
 
 	ctx.Data["Paths"] = Paths
 	ctx.Data["Treenames"] = treenames
-	ctx.Data["IsRepoToolbarSource"] = true
 	ctx.Data["BranchLink"] = branchLink
 	ctx.HTML(200, "repo/single")
 }
@@ -187,6 +188,8 @@ func Setting(ctx *middleware.Context, params martini.Params) {
 		return
 	}
 
+	ctx.Data["IsRepoToolbarSetting"] = true
+
 	// Branches.
 	brs, err := models.GetBranches(params["username"], params["reponame"])
 	if err != nil {
@@ -205,7 +208,6 @@ func Setting(ctx *middleware.Context, params martini.Params) {
 	}
 
 	ctx.Data["Title"] = title + " - settings"
-	ctx.Data["IsRepoToolbarSetting"] = true
 	ctx.HTML(200, "repo/setting")
 }
 
diff --git a/templates/repo/single.tmpl b/templates/repo/single.tmpl
index 60247898e2..8a7b5e479b 100644
--- a/templates/repo/single.tmpl
+++ b/templates/repo/single.tmpl
@@ -5,7 +5,7 @@
 <div id="gogs-body" class="container">
     <div id="gogs-source">
         {{if .IsBareRepo}}
-        Need to fill in some guide.
+        {{template "repo/single_bare" .}}
         {{else}}
         <div class="source-toolbar">
             {{ $n := len .Treenames}}
diff --git a/templates/repo/single_bare.tmpl b/templates/repo/single_bare.tmpl
new file mode 100644
index 0000000000..caf2ef7498
--- /dev/null
+++ b/templates/repo/single_bare.tmpl
@@ -0,0 +1,31 @@
+<div class="panel panel-default guide-box">
+    <div class="panel-heading guide-head">
+        <h4>Quick Guide</h4>
+    </div>
+    <div class="panel-body guide-content text-center">
+        <h3>Clone this repository</h3>
+        <div class="input-group col-md-8 col-md-offset-2 guide-buttons">
+            <span class="input-group-btn">
+                <button class="btn btn-default" data-url="https-link" type="button">HTTPS</button>
+                <button class="btn btn-default" data-url="git-link" type="button">SSH</button>
+            </span>
+            <input type="text" class="form-control" id="guide-clone-url" value="" readonly/>
+            <span class="input-group-btn">
+                <button class="btn btn-default" type="button"><i class="fa fa-copy" data-toggle="tooltip" title="copy to clipboard" data-placement="top"></i></button>
+            </span>
+        </div>
+        <p>We recommend every repository include a <strong>README</strong>, <strong>LICENSE</strong>, and <strong>.gitignore</strong>.</p>
+        <hr/>
+        <h3>Create a new repository on the command line</h3>
+            <pre class="text-left"><code>touch README.md
+git init
+git add README.md
+git commit -m "first commit"
+git remote add origin <span class="clone-url">https://github.com/fuxiaohei/air.git</span>
+git push -u origin master</code></pre>
+        <hr/>
+        <h3>Push an existing repository from the command line</h3>
+        <pre class="text-left"><code>git remote add origin <span class="clone-url">https://github.com/fuxiaohei/air.git</span>
+git push -u origin master</code></pre>
+    </div>
+</div>
\ No newline at end of file
diff --git a/templates/repo/toolbar.tmpl b/templates/repo/toolbar.tmpl
index 5cd9f526b4..b51768a3c3 100644
--- a/templates/repo/toolbar.tmpl
+++ b/templates/repo/toolbar.tmpl
@@ -15,9 +15,8 @@
                             <li><a href="/{{.RepositoryLink}}/release">Release</a></li>
                             <li><a href="//{{.RepositoryLink}}/wiki">Wiki</a></li>
                         </ul>
-                    </li>
+                    </li>{{end}}
                 </ul>
-                {{end}}
                 <ul class="nav navbar-nav navbar-right">
                     {{if not .IsBareRepo}}
                     <li class="dropdown">

From e8a49c7746f3d93688d83401c69b0f4936c25783 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Thu, 20 Mar 2014 08:25:41 -0400
Subject: [PATCH 07/41] Add data to ui

---
 modules/middleware/repo.go      |  1 +
 templates/repo/single_bare.tmpl | 10 +++++-----
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go
index b25c942316..62c67bcee1 100644
--- a/modules/middleware/repo.go
+++ b/modules/middleware/repo.go
@@ -70,6 +70,7 @@ func RepoAssignment(redirect bool) martini.Handler {
 		}
 		ctx.Repo.Repository = repo
 		ctx.Repo.CloneLink.SSH = fmt.Sprintf("git@%s:%s/%s.git", base.Domain, user.LowerName, repo.LowerName)
+		ctx.Repo.CloneLink.HTTPS = fmt.Sprintf("https://%s/%s/%s.git", base.Domain, user.LowerName, repo.LowerName)
 
 		ctx.Data["IsRepositoryValid"] = true
 		ctx.Data["Repository"] = repo
diff --git a/templates/repo/single_bare.tmpl b/templates/repo/single_bare.tmpl
index caf2ef7498..999ff557b0 100644
--- a/templates/repo/single_bare.tmpl
+++ b/templates/repo/single_bare.tmpl
@@ -6,8 +6,8 @@
         <h3>Clone this repository</h3>
         <div class="input-group col-md-8 col-md-offset-2 guide-buttons">
             <span class="input-group-btn">
-                <button class="btn btn-default" data-url="https-link" type="button">HTTPS</button>
-                <button class="btn btn-default" data-url="git-link" type="button">SSH</button>
+                <button class="btn btn-default" data-url="{{.CloneLink.HTTPS}}" type="button">HTTPS</button>
+                <button class="btn btn-default" data-url="{{.CloneLink.SSH}}" type="button">SSH</button>
             </span>
             <input type="text" class="form-control" id="guide-clone-url" value="" readonly/>
             <span class="input-group-btn">
@@ -20,12 +20,12 @@
             <pre class="text-left"><code>touch README.md
 git init
 git add README.md
-git commit -m "first commit"
-git remote add origin <span class="clone-url">https://github.com/fuxiaohei/air.git</span>
+git commit -m "first commit" {{.CloneLink.SSH}}
+git remote add origin <span class="clone-url">{{.CloneLink.HTTPS}}</span>
 git push -u origin master</code></pre>
         <hr/>
         <h3>Push an existing repository from the command line</h3>
-        <pre class="text-left"><code>git remote add origin <span class="clone-url">https://github.com/fuxiaohei/air.git</span>
+        <pre class="text-left"><code>git remote add origin <span class="clone-url">{{.CloneLink.HTTPS}}</span>
 git push -u origin master</code></pre>
     </div>
 </div>
\ No newline at end of file

From c7b6fbfd46fe465b5103ecc0b743ea009eb1e586 Mon Sep 17 00:00:00 2001
From: FuXiaoHei <fuxiaohei@hexiaz.com>
Date: Thu, 20 Mar 2014 20:42:06 +0800
Subject: [PATCH 08/41] clean padding in single file page

---
 public/css/gogs.css             | 18 +++++++++++++++++-
 public/js/app.js                |  2 +-
 templates/repo/single_bare.tmpl |  8 ++++----
 3 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/public/css/gogs.css b/public/css/gogs.css
index 95f44d0fd4..d2ba5b9a43 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -644,7 +644,19 @@ html, body {
 }
 
 .file-content .file-body {
-    padding: 30px 30px 50px;
+    padding: 0;
+    border: none;
+    background-color: #FFF;
+}
+
+.file-content .file-body pre {
+    background-color: #FFF;
+    border: none;
+}
+
+.file-content .markdown > pre > ol.linenums > li:first-child {
+    padding-top: 0;
+    margin-top: 0;
 }
 
 .branch-list th, .commit-list th {
@@ -738,6 +750,10 @@ html, body {
     background-color: #FFF;
 }
 
+.guide-box {
+    margin-top: 20px;
+}
+
 /* wrapper and footer */
 
 #wrapper {
diff --git a/public/js/app.js b/public/js/app.js
index e1aeb8a51a..1f64b529d5 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -67,7 +67,7 @@ var Gogits = {
     // render markdown
     Gogits.renderMarkdown = function () {
         var $pre = $('.markdown').find('pre > code').parent();
-        $pre.addClass("prettyprint");
+        $pre.addClass("prettyprint linenums");
         prettyPrint();
     }
 
diff --git a/templates/repo/single_bare.tmpl b/templates/repo/single_bare.tmpl
index 999ff557b0..06711157d4 100644
--- a/templates/repo/single_bare.tmpl
+++ b/templates/repo/single_bare.tmpl
@@ -6,8 +6,8 @@
         <h3>Clone this repository</h3>
         <div class="input-group col-md-8 col-md-offset-2 guide-buttons">
             <span class="input-group-btn">
-                <button class="btn btn-default" data-url="{{.CloneLink.HTTPS}}" type="button">HTTPS</button>
                 <button class="btn btn-default" data-url="{{.CloneLink.SSH}}" type="button">SSH</button>
+                <button class="btn btn-default" data-url="{{.CloneLink.HTTPS}}" type="button">HTTPS</button>
             </span>
             <input type="text" class="form-control" id="guide-clone-url" value="" readonly/>
             <span class="input-group-btn">
@@ -20,12 +20,12 @@
             <pre class="text-left"><code>touch README.md
 git init
 git add README.md
-git commit -m "first commit" {{.CloneLink.SSH}}
-git remote add origin <span class="clone-url">{{.CloneLink.HTTPS}}</span>
+git commit -m "first commit"
+git remote add origin <span class="clone-url"></span>
 git push -u origin master</code></pre>
         <hr/>
         <h3>Push an existing repository from the command line</h3>
-        <pre class="text-left"><code>git remote add origin <span class="clone-url">{{.CloneLink.HTTPS}}</span>
+        <pre class="text-left"><code>git remote add origin <span class="clone-url"></span>
 git push -u origin master</code></pre>
     </div>
 </div>
\ No newline at end of file

From de956c477684f66a9e27ad895efbebae1837b2b1 Mon Sep 17 00:00:00 2001
From: slene <vslene@gmail.com>
Date: Thu, 20 Mar 2014 21:10:37 +0800
Subject: [PATCH 09/41] linenums

---
 public/css/gogs.css             | 47 ++++++++++++++++++++++++++++-----
 public/css/markdown.css         | 10 +++++--
 public/js/app.js                | 23 +++++++++++++++-
 public/js/lib.js                |  2 +-
 routers/repo/single.go          |  2 ++
 templates/repo/single_file.tmpl | 11 ++++++--
 6 files changed, 82 insertions(+), 13 deletions(-)

diff --git a/public/css/gogs.css b/public/css/gogs.css
index eb5f7ad2a5..41e4be9a4c 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -644,7 +644,7 @@ html, body {
 }
 
 .file-content .file-body {
-    padding: 0;
+    padding: 30px 30px 50px;
     border: none;
     background-color: #FFF;
 }
@@ -654,17 +654,50 @@ html, body {
     border: none;
 }
 
-.file-content .markdown > pre > ol.linenums > li:first-child {
-    padding-top: 0;
-    margin-top: 0;
-}
-
 .file-content .file-body.file-code {
     padding: 0;
 }
 
-.file-content .file-body.file-code > pre {
+.file-content .file-body.file-code .lines-code > pre {
     border: none;
+    background: none;
+    border-left: 1px solid #ddd;
+}
+
+.file-content .file-body.file-code .lines-code ol.linenums > .active {
+    background: #ffffdd;
+}
+
+.file-content .file-body.file-code .lines-num {
+    text-align: right;
+    color: #999;
+    background: #fafafa;
+    width: 1%;
+}
+
+.file-content .file-body.file-code .lines-num span {
+    font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
+    line-height: 1.6;
+    padding: 0 8px 0 10px;
+    cursor: pointer;
+    display: block;
+    margin-top: 6px;
+    font-size: 90%;
+}
+
+.file-content .file-body.file-code .lines-num span:first-child {
+    margin-top: 0;
+}
+
+.file-content .file-body.file-code > table {
+    width: 100%;
+}
+
+.file-content .file-body.file-code > table > tbody > tr,
+.file-content .file-body.file-code > table > tbody > tr > td,
+.file-content .file-body.file-code > table {
+    border: none;
+    background: none;
 }
 
 .branch-list th, .commit-list th {
diff --git a/public/css/markdown.css b/public/css/markdown.css
index 1edc3b626c..68094867b1 100644
--- a/public/css/markdown.css
+++ b/public/css/markdown.css
@@ -111,7 +111,6 @@
   line-height: 1.6;
   overflow: auto;
   background: #f8f8f8;
-  padding: 6px 10px;
   border: 1px solid #ddd;
 }
 
@@ -120,6 +119,13 @@
 }
 
 .markdown > pre > ol.linenums {
+  list-style: none;
+  padding: 0;
+}
+
+.markdown > pre.linenums-style > ol.linenums {
+  list-style-type: decimal;
+  padding: 0 0 0 40px;
   -webkit-box-shadow: inset 40px 0 0 #f5f5f5, inset 41px 0 0 #ccc;
   box-shadow: inset 40px 0 0 #f5f5f5, inset 41px 0 0 #ccc;
 }
@@ -142,7 +148,7 @@
   padding-bottom: 12px;
 }
 
-.markdown > pre > ol.linenums > li {
+.markdown > pre.linenums-style > ol.linenums > li {
   border-left: 1px solid #ddd;
 }
 
diff --git a/public/js/app.js b/public/js/app.js
index 12f9e7f359..93cfbc1faa 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -68,9 +68,30 @@ var Gogits = {
     Gogits.renderMarkdown = function () {
         var $md = $('.markdown');
         var $pre = $md.find('pre > code').parent();
-        $pre.addClass("prettyprint");
+        $pre.addClass('prettyprint');
         prettyPrint();
 
+        var $lineNums = $pre.parent().siblings('.lines-num');
+        if($lineNums.length > 0){
+            var nums = $pre.find('ol.linenums > li').length;
+            for(var i=0;i < nums;i++){
+                $lineNums.append('<span id="L'+i+'" rel=".L'+i+'">'+(i+1)+'</span>');
+            }
+
+            var last;
+            $(document).on('click', '.lines-num span', function(){
+                var $e = $(this);
+                console.log($e.parent().siblings('.lines-code').find('ol.linenums > ' + $e.attr('rel')));
+                console.log('ol.linenums > ' + $e.attr('rel'));
+                if(last){
+                    last.removeClass('active');
+                }
+                last = $e.parent().siblings('.lines-code').find('ol.linenums > ' + $e.attr('rel'));
+                last.addClass('active');
+                window.location.href = '#' + $e.attr('id');
+            });
+        }
+
         // Set anchor.
         var headers = {};
         $md.find('h1, h2, h3, h4, h5, h6').each(function () {
diff --git a/public/js/lib.js b/public/js/lib.js
index 2a98f27775..b9e07c0caf 100644
--- a/public/js/lib.js
+++ b/public/js/lib.js
@@ -340,7 +340,7 @@ q,"'\"`"]):d.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?
 s+")*(?:\\x5D|$))+/")+")")])}(b=a.types)&&g.push(["typ",b]);b=(""+a.keywords).replace(/^ | $/g,"");b.length&&g.push(["kwd",RegExp("^(?:"+b.replace(/[\s,]+/g,"|")+")\\b"),q]);d.push(["pln",/^\s+/,q," \r\n\t\u00a0"]);b="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(b+="(?!s*/)");g.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,
 q],["pun",RegExp(b),q]);return C(d,g)}function J(a,d,g){function b(a){var c=a.nodeType;if(c==1&&!x.test(a.className))if("br"===a.nodeName)s(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((c==3||c==4)&&g){var d=a.nodeValue,i=d.match(m);if(i)c=d.substring(0,i.index),a.nodeValue=c,(d=d.substring(i.index+i[0].length))&&a.parentNode.insertBefore(j.createTextNode(d),a.nextSibling),s(a),c||a.parentNode.removeChild(a)}}function s(a){function b(a,c){var d=
 c?a.cloneNode(!1):a,e=a.parentNode;if(e){var e=b(e,1),g=a.nextSibling;e.appendChild(d);for(var i=g;i;i=g)g=i.nextSibling,e.appendChild(i)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),d;(d=a.parentNode)&&d.nodeType===1;)a=d;c.push(a)}for(var x=/(?:^|\s)nocode(?:\s|$)/,m=/\r\n?|\n/,j=a.ownerDocument,k=j.createElement("li");a.firstChild;)k.appendChild(a.firstChild);for(var c=[k],i=0;i<c.length;++i)b(c[i]);d===(d|0)&&c[0].setAttribute("value",d);var r=j.createElement("ol");
-r.className="linenums";for(var d=Math.max(0,d-1|0)||0,i=0,n=c.length;i<n;++i)k=c[i],k.className="L"+(i+d)%10,k.firstChild||k.appendChild(j.createTextNode("\u00a0")),r.appendChild(k);a.appendChild(r)}function p(a,d){for(var g=d.length;--g>=0;){var b=d[g];F.hasOwnProperty(b)?D.console&&console.warn("cannot override language handler %s",b):F[b]=a}}function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\s*</.test(d)?"default-markup":"default-code";return F[a]}function K(a){var d=a.h;try{var g=T(a.c,a.i),b=g.a;
+r.className="linenums";for(var d=Math.max(0,d-1|0)||0,i=0,n=c.length;i<n;++i)k=c[i],k.className="L"+(i+d),k.firstChild||k.appendChild(j.createTextNode("\u00a0")),r.appendChild(k);a.appendChild(r)}function p(a,d){for(var g=d.length;--g>=0;){var b=d[g];F.hasOwnProperty(b)?D.console&&console.warn("cannot override language handler %s",b):F[b]=a}}function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\s*</.test(d)?"default-markup":"default-code";return F[a]}function K(a){var d=a.h;try{var g=T(a.c,a.i),b=g.a;
 a.a=b;a.d=g.d;a.e=0;I(d,b)(a);var s=/\bMSIE\s(\d+)/.exec(navigator.userAgent),s=s&&+s[1]<=8,d=/\n/g,x=a.a,m=x.length,g=0,j=a.d,k=j.length,b=0,c=a.g,i=c.length,r=0;c[i]=m;var n,e;for(e=n=0;e<i;)c[e]!==c[e+2]?(c[n++]=c[e++],c[n++]=c[e++]):e+=2;i=n;for(e=n=0;e<i;){for(var p=c[e],w=c[e+1],t=e+2;t+2<=i&&c[t+1]===w;)t+=2;c[n++]=p;c[n++]=w;e=t}c.length=n;var f=a.c,h;if(f)h=f.style.display,f.style.display="none";try{for(;b<k;){var l=j[b+2]||m,B=c[r+2]||m,t=Math.min(l,B),A=j[b+1],G;if(A.nodeType!==1&&(G=x.substring(g,
 t))){s&&(G=G.replace(d,"\r"));A.nodeValue=G;var L=A.ownerDocument,o=L.createElement("span");o.className=c[r+1];var v=A.parentNode;v.replaceChild(o,A);o.appendChild(A);g<l&&(j[b+1]=A=L.createTextNode(x.substring(t,l)),v.insertBefore(A,o.nextSibling))}g=t;g>=l&&(b+=2);g>=B&&(r+=2)}}finally{if(f)f.style.display=h}}catch(u){D.console&&console.log(u&&u.stack||u)}}var D=window,y=["break,continue,do,else,for,if,return,while"],E=[[y,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
 "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],M=[E,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],N=[E,"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"],
diff --git a/routers/repo/single.go b/routers/repo/single.go
index 6eb839c10d..49eb55d3e0 100644
--- a/routers/repo/single.go
+++ b/routers/repo/single.go
@@ -5,6 +5,7 @@
 package repo
 
 import (
+	"path"
 	"strings"
 
 	"github.com/codegangsta/martini"
@@ -95,6 +96,7 @@ func Single(ctx *middleware.Context, params martini.Params) {
 		} else {
 			ctx.Data["IsFile"] = true
 			ctx.Data["FileName"] = repoFile.Name
+			ctx.Data["FileExt"] = path.Ext(repoFile.Name)
 
 			readmeExist := base.IsMarkdownFile(repoFile.Name) || base.IsReadmeFile(repoFile.Name)
 			ctx.Data["ReadmeExist"] = readmeExist
diff --git a/templates/repo/single_file.tmpl b/templates/repo/single_file.tmpl
index 0c1c3713f6..7bca626aaa 100644
--- a/templates/repo/single_file.tmpl
+++ b/templates/repo/single_file.tmpl
@@ -16,8 +16,15 @@
                 {{.FileContent|str2html}}
             </div>
         {{else}}
-            <div class="panel-body file-body file-code markdown">
-                <pre class="linenums"><code>{{.FileContent}}</code></pre>
+            <div class="panel-body file-body file-code">
+                <table>
+                    <tbody>
+                        <tr>
+                            <td class="lines-num"></td>
+                            <td class="lines-code markdown"><pre class="linenums lang-{{.FileExt}}"><code>{{.FileContent}}</code></pre></td>
+                        </tr>
+                    </tbody>
+                </table>
             </div>
         {{end}}
     {{end}}

From 47234f1031b35dfc6b3a20223d5dd61db2decda1 Mon Sep 17 00:00:00 2001
From: slene <vslene@gmail.com>
Date: Thu, 20 Mar 2014 21:11:48 +0800
Subject: [PATCH 10/41] fix ext

---
 modules/base/markdown.go | 2 +-
 routers/repo/single.go   | 6 +++++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/modules/base/markdown.go b/modules/base/markdown.go
index e49e111c0e..2273cd772f 100644
--- a/modules/base/markdown.go
+++ b/modules/base/markdown.go
@@ -36,7 +36,7 @@ func isLink(link []byte) bool {
 func IsMarkdownFile(name string) bool {
 	name = strings.ToLower(name)
 	switch filepath.Ext(name) {
-	case "md", "markdown", "mdown":
+	case ".md", ".markdown", ".mdown":
 		return true
 	}
 	return false
diff --git a/routers/repo/single.go b/routers/repo/single.go
index 49eb55d3e0..e218bc9158 100644
--- a/routers/repo/single.go
+++ b/routers/repo/single.go
@@ -96,7 +96,11 @@ func Single(ctx *middleware.Context, params martini.Params) {
 		} else {
 			ctx.Data["IsFile"] = true
 			ctx.Data["FileName"] = repoFile.Name
-			ctx.Data["FileExt"] = path.Ext(repoFile.Name)
+			ext := path.Ext(repoFile.Name)
+			if len(ext) > 0 {
+				ext = ext[1:]
+			}
+			ctx.Data["FileExt"] = ext
 
 			readmeExist := base.IsMarkdownFile(repoFile.Name) || base.IsReadmeFile(repoFile.Name)
 			ctx.Data["ReadmeExist"] = readmeExist

From c8790eb7d367cec25f1201f923ca017268fe157d Mon Sep 17 00:00:00 2001
From: slene <vslene@gmail.com>
Date: Thu, 20 Mar 2014 21:24:15 +0800
Subject: [PATCH 11/41] overflow

---
 public/css/gogs.css | 3 +++
 public/js/app.js    | 2 --
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/public/css/gogs.css b/public/css/gogs.css
index 41e4be9a4c..3a8760c355 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -647,6 +647,9 @@ html, body {
     padding: 30px 30px 50px;
     border: none;
     background-color: #FFF;
+    overflow: auto;
+    overflow-x: auto;
+    overflow-y: hidden;
 }
 
 .file-content .file-body pre {
diff --git a/public/js/app.js b/public/js/app.js
index 93cfbc1faa..a39976006f 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -81,8 +81,6 @@ var Gogits = {
             var last;
             $(document).on('click', '.lines-num span', function(){
                 var $e = $(this);
-                console.log($e.parent().siblings('.lines-code').find('ol.linenums > ' + $e.attr('rel')));
-                console.log('ol.linenums > ' + $e.attr('rel'));
                 if(last){
                     last.removeClass('active');
                 }

From 42b08ff26158b9c815d13a427c596bd76468beb8 Mon Sep 17 00:00:00 2001
From: FuXiaoHei <fuxiaohei@hexiaz.com>
Date: Thu, 20 Mar 2014 21:28:12 +0800
Subject: [PATCH 12/41] fix single bare page link

---
 modules/middleware/repo.go      |  1 +
 public/js/app.js                | 46 +++++++++++++++++----------------
 templates/repo/nav.tmpl         |  2 +-
 templates/repo/single_bare.tmpl |  4 +--
 4 files changed, 28 insertions(+), 25 deletions(-)

diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go
index 62c67bcee1..a9a90e3ff5 100644
--- a/modules/middleware/repo.go
+++ b/modules/middleware/repo.go
@@ -79,5 +79,6 @@ func RepoAssignment(redirect bool) martini.Handler {
 		ctx.Data["CloneLink"] = ctx.Repo.CloneLink
 		ctx.Data["RepositoryLink"] = ctx.Data["Title"]
 		ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner
+		ctx.Data["IsRepositoryWatching"] = ctx.Repo.IsWatching
 	}
 }
diff --git a/public/js/app.js b/public/js/app.js
index 93cfbc1faa..64cc980fd8 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -72,18 +72,18 @@ var Gogits = {
         prettyPrint();
 
         var $lineNums = $pre.parent().siblings('.lines-num');
-        if($lineNums.length > 0){
+        if ($lineNums.length > 0) {
             var nums = $pre.find('ol.linenums > li').length;
-            for(var i=0;i < nums;i++){
-                $lineNums.append('<span id="L'+i+'" rel=".L'+i+'">'+(i+1)+'</span>');
+            for (var i = 1; i <= nums; i++) {
+                $lineNums.append('<span id="L' + i + '" rel=".L' + i + '">' + i + '</span>');
             }
 
             var last;
-            $(document).on('click', '.lines-num span', function(){
+            $(document).on('click', '.lines-num span', function () {
                 var $e = $(this);
                 console.log($e.parent().siblings('.lines-code').find('ol.linenums > ' + $e.attr('rel')));
                 console.log('ol.linenums > ' + $e.attr('rel'));
-                if(last){
+                if (last) {
                     last.removeClass('active');
                 }
                 last = $e.parent().siblings('.lines-code').find('ol.linenums > ' + $e.attr('rel'));
@@ -98,12 +98,12 @@ var Gogits = {
             var node = $(this);
             var val = encodeURIComponent(node.text().toLowerCase().replace(/[^\w\- ]/g, '').replace(/[ ]/g, '-'));
             var name = val;
-            if(headers[val] > 0){
+            if (headers[val] > 0) {
                 name = val + '-' + headers[val];
             }
-            if(headers[val] == undefined){
+            if (headers[val] == undefined) {
                 headers[val] = 1;
-            }else{
+            } else {
                 headers[val] += 1;
             }
             node = node.wrap('<div id="' + name + '" class="anchor-wrap" ></div>');
@@ -183,20 +183,22 @@ function initUserSetting() {
 }
 
 function initRepository() {
-    var $guide = $('.guide-box');
-    if ($guide.length) {
-        var $url = $('#guide-clone-url');
-        $guide.find('button[data-url]').on("click",function () {
-            var $this = $(this);
-            if (!$this.hasClass('btn-primary')) {
-                $guide.find('.btn-primary').removeClass('btn-primary').addClass("btn-default");
-                $(this).addClass('btn-primary').removeClass('btn-default');
-                $url.val($this.data("url"));
-                $guide.find('span.clone-url').text($this.data('url'));
-            }
-        }).eq(0).trigger("click");
-        // todo copy to clipboard
-    }
+    (function () {
+        var $guide = $('.guide-box');
+        if ($guide.length) {
+            var $url = $('#guide-clone-url');
+            $guide.find('button[data-url]').on("click",function () {
+                var $this = $(this);
+                if (!$this.hasClass('btn-primary')) {
+                    $guide.find('.btn-primary').removeClass('btn-primary').addClass("btn-default");
+                    $(this).addClass('btn-primary').removeClass('btn-default');
+                    $url.val($this.data("url"));
+                    $guide.find('span.clone-url').text($this.data('url'));
+                }
+            }).eq(0).trigger("click");
+            // todo copy to clipboard
+        }
+    })();
 }
 
 (function ($) {
diff --git a/templates/repo/nav.tmpl b/templates/repo/nav.tmpl
index 92e529dbc7..e8685b08bc 100644
--- a/templates/repo/nav.tmpl
+++ b/templates/repo/nav.tmpl
@@ -13,7 +13,7 @@
                         <span class="caret"></span>
                     </button>
                 </div>
-                <div class="btn-group" id="gogs-repo-watching">
+                <div class="btn-group {{if .IsRepositoryWatching}}watching{{end}}" id="gogs-repo-watching">
                     <button type="button" class="btn btn-default"><i class="fa fa-eye fa-lg fa-m"></i></button>
                     <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
                         <span class="caret"></span>
diff --git a/templates/repo/single_bare.tmpl b/templates/repo/single_bare.tmpl
index 06711157d4..bb05c2f9a6 100644
--- a/templates/repo/single_bare.tmpl
+++ b/templates/repo/single_bare.tmpl
@@ -6,8 +6,8 @@
         <h3>Clone this repository</h3>
         <div class="input-group col-md-8 col-md-offset-2 guide-buttons">
             <span class="input-group-btn">
-                <button class="btn btn-default" data-url="{{.CloneLink.SSH}}" type="button">SSH</button>
-                <button class="btn btn-default" data-url="{{.CloneLink.HTTPS}}" type="button">HTTPS</button>
+                <button class="btn btn-default" data-link="{{.CloneLink.SSH}}" type="button">SSH</button>
+                <button class="btn btn-default" data-link="{{.CloneLink.HTTPS}}" type="button">HTTPS</button>
             </span>
             <input type="text" class="form-control" id="guide-clone-url" value="" readonly/>
             <span class="input-group-btn">

From 4efd73d37a7e76401ef93982db63b4538013ea23 Mon Sep 17 00:00:00 2001
From: FuXiaoHei <fuxiaohei@hexiaz.com>
Date: Thu, 20 Mar 2014 21:32:08 +0800
Subject: [PATCH 13/41] fix single bare page link

---
 public/js/app.js | 46 ++++++++++++++++++++++++----------------------
 1 file changed, 24 insertions(+), 22 deletions(-)

diff --git a/public/js/app.js b/public/js/app.js
index a39976006f..2952083ed8 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -72,16 +72,16 @@ var Gogits = {
         prettyPrint();
 
         var $lineNums = $pre.parent().siblings('.lines-num');
-        if($lineNums.length > 0){
+        if ($lineNums.length > 0) {
             var nums = $pre.find('ol.linenums > li').length;
-            for(var i=0;i < nums;i++){
-                $lineNums.append('<span id="L'+i+'" rel=".L'+i+'">'+(i+1)+'</span>');
+            for (var i = 0; i < nums; i++) {
+                $lineNums.append('<span id="L' + i + '" rel=".L' + i + '">' + (i + 1) + '</span>');
             }
 
             var last;
-            $(document).on('click', '.lines-num span', function(){
+            $(document).on('click', '.lines-num span', function () {
                 var $e = $(this);
-                if(last){
+                if (last) {
                     last.removeClass('active');
                 }
                 last = $e.parent().siblings('.lines-code').find('ol.linenums > ' + $e.attr('rel'));
@@ -96,12 +96,12 @@ var Gogits = {
             var node = $(this);
             var val = encodeURIComponent(node.text().toLowerCase().replace(/[^\w\- ]/g, '').replace(/[ ]/g, '-'));
             var name = val;
-            if(headers[val] > 0){
+            if (headers[val] > 0) {
                 name = val + '-' + headers[val];
             }
-            if(headers[val] == undefined){
+            if (headers[val] == undefined) {
                 headers[val] = 1;
-            }else{
+            } else {
                 headers[val] += 1;
             }
             node = node.wrap('<div id="' + name + '" class="anchor-wrap" ></div>');
@@ -181,20 +181,22 @@ function initUserSetting() {
 }
 
 function initRepository() {
-    var $guide = $('.guide-box');
-    if ($guide.length) {
-        var $url = $('#guide-clone-url');
-        $guide.find('button[data-url]').on("click",function () {
-            var $this = $(this);
-            if (!$this.hasClass('btn-primary')) {
-                $guide.find('.btn-primary').removeClass('btn-primary').addClass("btn-default");
-                $(this).addClass('btn-primary').removeClass('btn-default');
-                $url.val($this.data("url"));
-                $guide.find('span.clone-url').text($this.data('url'));
-            }
-        }).eq(0).trigger("click");
-        // todo copy to clipboard
-    }
+    (function () {
+        var $guide = $('.guide-box');
+        if ($guide.length) {
+            var $url = $('#guide-clone-url');
+            $guide.find('button[data-link]').on("click",function () {
+                var $this = $(this);
+                if (!$this.hasClass('btn-primary')) {
+                    $guide.find('.btn-primary').removeClass('btn-primary').addClass("btn-default");
+                    $(this).addClass('btn-primary').removeClass('btn-default');
+                    $url.val($this.data("link"));
+                    $guide.find('span.clone-url').text($this.data('link'));
+                }
+            }).eq(0).trigger("click");
+            // todo copy to clipboard
+        }
+    })();
 }
 
 (function ($) {

From fa455ab757886b56a2adb3de77d9db06bfae0eb6 Mon Sep 17 00:00:00 2001
From: slene <vslene@gmail.com>
Date: Thu, 20 Mar 2014 21:32:44 +0800
Subject: [PATCH 14/41] fix offset

---
 public/css/gogs.css | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/public/css/gogs.css b/public/css/gogs.css
index 3a8760c355..d1b1e155a8 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -501,8 +501,7 @@ html, body {
 }
 
 .activity-list .info {
-    float: left;
-    padding: 0 0 0 10px;
+    margin: 0 0 0 40px;
     line-height: 1.7em;
 }
 

From 7c6c6125f3846acc633c00bb92c8698c30e761fa Mon Sep 17 00:00:00 2001
From: slene <vslene@gmail.com>
Date: Thu, 20 Mar 2014 21:35:46 +0800
Subject: [PATCH 15/41] fix line num

---
 public/js/app.js | 4 ++--
 public/js/lib.js | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/public/js/app.js b/public/js/app.js
index 2952083ed8..555410329b 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -74,8 +74,8 @@ var Gogits = {
         var $lineNums = $pre.parent().siblings('.lines-num');
         if ($lineNums.length > 0) {
             var nums = $pre.find('ol.linenums > li').length;
-            for (var i = 0; i < nums; i++) {
-                $lineNums.append('<span id="L' + i + '" rel=".L' + i + '">' + (i + 1) + '</span>');
+            for (var i = 1; i <= nums; i++) {
+                $lineNums.append('<span id="L' + i + '" rel=".L' + i + '">' + i + '</span>');
             }
 
             var last;
diff --git a/public/js/lib.js b/public/js/lib.js
index b9e07c0caf..8deb6f7226 100644
--- a/public/js/lib.js
+++ b/public/js/lib.js
@@ -340,7 +340,7 @@ q,"'\"`"]):d.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?
 s+")*(?:\\x5D|$))+/")+")")])}(b=a.types)&&g.push(["typ",b]);b=(""+a.keywords).replace(/^ | $/g,"");b.length&&g.push(["kwd",RegExp("^(?:"+b.replace(/[\s,]+/g,"|")+")\\b"),q]);d.push(["pln",/^\s+/,q," \r\n\t\u00a0"]);b="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(b+="(?!s*/)");g.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,
 q],["pun",RegExp(b),q]);return C(d,g)}function J(a,d,g){function b(a){var c=a.nodeType;if(c==1&&!x.test(a.className))if("br"===a.nodeName)s(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((c==3||c==4)&&g){var d=a.nodeValue,i=d.match(m);if(i)c=d.substring(0,i.index),a.nodeValue=c,(d=d.substring(i.index+i[0].length))&&a.parentNode.insertBefore(j.createTextNode(d),a.nextSibling),s(a),c||a.parentNode.removeChild(a)}}function s(a){function b(a,c){var d=
 c?a.cloneNode(!1):a,e=a.parentNode;if(e){var e=b(e,1),g=a.nextSibling;e.appendChild(d);for(var i=g;i;i=g)g=i.nextSibling,e.appendChild(i)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),d;(d=a.parentNode)&&d.nodeType===1;)a=d;c.push(a)}for(var x=/(?:^|\s)nocode(?:\s|$)/,m=/\r\n?|\n/,j=a.ownerDocument,k=j.createElement("li");a.firstChild;)k.appendChild(a.firstChild);for(var c=[k],i=0;i<c.length;++i)b(c[i]);d===(d|0)&&c[0].setAttribute("value",d);var r=j.createElement("ol");
-r.className="linenums";for(var d=Math.max(0,d-1|0)||0,i=0,n=c.length;i<n;++i)k=c[i],k.className="L"+(i+d),k.firstChild||k.appendChild(j.createTextNode("\u00a0")),r.appendChild(k);a.appendChild(r)}function p(a,d){for(var g=d.length;--g>=0;){var b=d[g];F.hasOwnProperty(b)?D.console&&console.warn("cannot override language handler %s",b):F[b]=a}}function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\s*</.test(d)?"default-markup":"default-code";return F[a]}function K(a){var d=a.h;try{var g=T(a.c,a.i),b=g.a;
+r.className="linenums";for(var d=Math.max(0,d-1|0)||0,i=0,n=c.length;i<n;++i)k=c[i],k.className="L"+(i+d+1),k.firstChild||k.appendChild(j.createTextNode("\u00a0")),r.appendChild(k);a.appendChild(r)}function p(a,d){for(var g=d.length;--g>=0;){var b=d[g];F.hasOwnProperty(b)?D.console&&console.warn("cannot override language handler %s",b):F[b]=a}}function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\s*</.test(d)?"default-markup":"default-code";return F[a]}function K(a){var d=a.h;try{var g=T(a.c,a.i),b=g.a;
 a.a=b;a.d=g.d;a.e=0;I(d,b)(a);var s=/\bMSIE\s(\d+)/.exec(navigator.userAgent),s=s&&+s[1]<=8,d=/\n/g,x=a.a,m=x.length,g=0,j=a.d,k=j.length,b=0,c=a.g,i=c.length,r=0;c[i]=m;var n,e;for(e=n=0;e<i;)c[e]!==c[e+2]?(c[n++]=c[e++],c[n++]=c[e++]):e+=2;i=n;for(e=n=0;e<i;){for(var p=c[e],w=c[e+1],t=e+2;t+2<=i&&c[t+1]===w;)t+=2;c[n++]=p;c[n++]=w;e=t}c.length=n;var f=a.c,h;if(f)h=f.style.display,f.style.display="none";try{for(;b<k;){var l=j[b+2]||m,B=c[r+2]||m,t=Math.min(l,B),A=j[b+1],G;if(A.nodeType!==1&&(G=x.substring(g,
 t))){s&&(G=G.replace(d,"\r"));A.nodeValue=G;var L=A.ownerDocument,o=L.createElement("span");o.className=c[r+1];var v=A.parentNode;v.replaceChild(o,A);o.appendChild(A);g<l&&(j[b+1]=A=L.createTextNode(x.substring(t,l)),v.insertBefore(A,o.nextSibling))}g=t;g>=l&&(b+=2);g>=B&&(r+=2)}}finally{if(f)f.style.display=h}}catch(u){D.console&&console.log(u&&u.stack||u)}}var D=window,y=["break,continue,do,else,for,if,return,while"],E=[[y,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
 "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],M=[E,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],N=[E,"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"],

From b4a55434a46ffaf5c18df10d6bb39eb1e775822b Mon Sep 17 00:00:00 2001
From: slene <vslene@gmail.com>
Date: Thu, 20 Mar 2014 21:43:54 +0800
Subject: [PATCH 16/41] wrong link should 404

---
 routers/repo/single.go | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/routers/repo/single.go b/routers/repo/single.go
index e218bc9158..f1b15cceed 100644
--- a/routers/repo/single.go
+++ b/routers/repo/single.go
@@ -87,6 +87,11 @@ func Single(ctx *middleware.Context, params martini.Params) {
 
 	branchLink := "/" + ctx.Repo.Owner.LowerName + "/" + ctx.Repo.Repository.Name + "/src/" + params["branchname"]
 
+	if len(treename) != 0 && repoFile == nil {
+		ctx.Error(404)
+		return
+	}
+
 	if repoFile != nil && repoFile.IsFile() {
 		if repoFile.Size > 1024*1024 || repoFile.Filemode != git.FileModeBlob {
 			ctx.Data["FileIsLarge"] = true

From 4a6c56d2fdca7f3f7cbc6d03a6809796c0b5a56e Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Thu, 20 Mar 2014 09:49:06 -0400
Subject: [PATCH 17/41] Bug fix

---
 gogs.go        | 2 +-
 models/repo.go | 4 ++++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/gogs.go b/gogs.go
index 385b74217b..d32e3908c9 100644
--- a/gogs.go
+++ b/gogs.go
@@ -20,7 +20,7 @@ import (
 // Test that go1.1 tag above is included in builds. main.go refers to this definition.
 const go11tag = true
 
-const APP_VER = "0.1.1.0320.1"
+const APP_VER = "0.1.2.0320.1"
 
 func init() {
 	base.AppVer = APP_VER
diff --git a/models/repo.go b/models/repo.go
index 4b6dedaf90..052341ff6e 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -411,6 +411,10 @@ func DeleteRepository(userId, repoId int64, userName string) (err error) {
 		session.Rollback()
 		return err
 	}
+	if _, err = session.Delete(&Watch{RepoId: repoId}); err != nil {
+		session.Rollback()
+		return err
+	}
 	if err = session.Commit(); err != nil {
 		session.Rollback()
 		return err

From 1a0d7c54a2abecbe5335ca374fd8a345c2e7d3fd Mon Sep 17 00:00:00 2001
From: FuXiaoHei <fuxiaohei@hexiaz.com>
Date: Thu, 20 Mar 2014 22:39:10 +0800
Subject: [PATCH 18/41] repo watching ajax

---
 public/css/gogs.css     |  8 ++++++--
 public/js/app.js        | 35 +++++++++++++++++++++++++++++++++++
 templates/repo/nav.tmpl | 14 +++++++++-----
 3 files changed, 50 insertions(+), 7 deletions(-)

diff --git a/public/css/gogs.css b/public/css/gogs.css
index d1b1e155a8..f88b396397 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -445,7 +445,7 @@ html, body {
     padding: 0;
 }
 
-#gogs-repo-watching .dropdown-menu .dropdown-item:hover .dropdown-header {
+#gogs-repo-watching .dropdown-menu .dropdown-item:hover .dropdown-header, #gogs-repo-watching .dropdown-item .dropdown-header.text-primary {
     color: rgb(65, 131, 196);
     cursor: pointer;
 }
@@ -678,7 +678,7 @@ html, body {
 }
 
 .file-content .file-body.file-code .lines-num span {
-    font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
+    font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
     line-height: 1.6;
     padding: 0 8px 0 10px;
     cursor: pointer;
@@ -783,6 +783,10 @@ html, body {
     width: 120px;
 }
 
+.commit-list .author {
+    min-width: 180px;
+}
+
 .guide-box pre, .guide-box .input-group {
     margin-top: 20px;
     margin-bottom: 30px;
diff --git a/public/js/app.js b/public/js/app.js
index 555410329b..9a5a0d68ad 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -181,6 +181,7 @@ function initUserSetting() {
 }
 
 function initRepository() {
+    // guide box script
     (function () {
         var $guide = $('.guide-box');
         if ($guide.length) {
@@ -197,6 +198,40 @@ function initRepository() {
             // todo copy to clipboard
         }
     })();
+
+    // watching script
+    (function () {
+        var $watch = $('#gogs-repo-watching'),
+            watchLink = $watch.data("watch"),
+            unwatchLink = $watch.data("unwatch");
+        $watch.on('click', '.to-watch',function () {
+            if ($watch.hasClass("watching")) {
+                return false;
+            }
+            $.get(watchLink, function (json) {
+                if (json.ok) {
+                    $watch.find('.text-primary').removeClass('text-primary');
+                    $watch.find('.to-watch h4').addClass('text-primary');
+                    $watch.find('.fa-eye-slash').removeClass('fa-eye-slash').addClass('fa-eye');
+                    $watch.removeClass("no-watching").addClass("watching");
+                }
+            });
+            return false;
+        }).on('click', '.to-unwatch', function () {
+            if ($watch.hasClass("no-watching")) {
+                return false;
+            }
+            $.get(unwatchLink, function (json) {
+                if (json.ok) {
+                    $watch.find('.text-primary').removeClass('text-primary');
+                    $watch.find('.to-unwatch h4').addClass('text-primary');
+                    $watch.find('.fa-eye').removeClass('fa-eye').addClass('fa-eye-slash');
+                    $watch.removeClass("watching").addClass("no-watching");
+                }
+            });
+            return false;
+        });
+    })();
 }
 
 (function ($) {
diff --git a/templates/repo/nav.tmpl b/templates/repo/nav.tmpl
index e8685b08bc..718c429a2b 100644
--- a/templates/repo/nav.tmpl
+++ b/templates/repo/nav.tmpl
@@ -13,20 +13,24 @@
                         <span class="caret"></span>
                     </button>
                 </div>
-                <div class="btn-group {{if .IsRepositoryWatching}}watching{{end}}" id="gogs-repo-watching">
+                <div class="btn-group {{if .IsRepositoryWatching}}watching{{else}}no-watching{{end}}" id="gogs-repo-watching" data-watch="/{{.SignedUser.Name}}/{{.Repository.Name}}/action/watch" data-unwatch="/{{.SignedUser.Name}}/{{.Repository.Name}}/action/unwatch">
+                    {{if .IsRepositoryWatching}}
                     <button type="button" class="btn btn-default"><i class="fa fa-eye fa-lg fa-m"></i></button>
+                    {{else}}
+                    <button type="button" class="btn btn-default"><i class="fa fa-eye-slash fa-lg fa-m"></i></button>
+                    {{end}}
                     <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
                         <span class="caret"></span>
                         <span class="sr-only">Toggle Dropdown</span>
                     </button>
                     <div class="dropdown-menu" role="menu">
-                        <div class="dropdown-item text-left" data-val="not-watching">
-                            <h4 role="presentation" class="dropdown-header">Not Watching</h4>
+                        <div class="dropdown-item text-left to-unwatch">
+                            <h4 role="presentation" class="dropdown-header {{if not .IsRepositoryWatching}}text-primary{{end}}">Not Watching</h4>
                             <p class="description">You only receive notifications for conversations in which you participate or are @mentioned.</p>
                             <p class="divider"></p>
                         </div>
-                        <div class="dropdown-item text-left" data-val="watching">
-                            <h4 role="presentation" class="dropdown-header">Watching</h4>
+                        <div class="dropdown-item text-left to-watch">
+                            <h4 role="presentation" class="dropdown-header {{if .IsRepositoryWatching}}text-primary{{end}}">Watching</h4>
                             <p class="description">You receive notifications for all conversations in this repository.</p>
                         </div>
                     </div>

From ef3c0b215df8429af9bc03a559259c77be32907c Mon Sep 17 00:00:00 2001
From: slene <vslene@gmail.com>
Date: Thu, 20 Mar 2014 23:37:17 +0800
Subject: [PATCH 19/41] fix

---
 public/js/lib.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/public/js/lib.js b/public/js/lib.js
index 8deb6f7226..b5cc41c042 100644
--- a/public/js/lib.js
+++ b/public/js/lib.js
@@ -400,7 +400,7 @@ PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t-\r ]+/,null,"\t\n\u000
 ["kwd",/^-[_a-z]+/],["typ",/^[A-Z_]\w*/],["pun",/^[,.;]/]]),["erlang","erl"]);
 
 // lang-go.js
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["pln",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])+(?:'|$)|`[^`]*(?:`|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\/\*[\S\s]*?\*\/)/],["pln",/^(?:[^"'/`]|\/(?![*/]))+/]]),["go"]);
+// PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["pln",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])+(?:'|$)|`[^`]*(?:`|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\/\*[\S\s]*?\*\/)/],["pln",/^(?:[^"'/`]|\/(?![*/]))+/]]),["go"]);
 
 // lang-hs.js
 PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t-\r ]+/,null,"\t\n\u000b\u000c\r "],["str",/^"(?:[^\n\f\r"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["str",/^'(?:[^\n\f\r'\\]|\\[^&])'?/,null,"'"],["lit",/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)/i,null,"0123456789"]],[["com",/^(?:--+[^\n\f\r]*|{-(?:[^-]|-+[^}-])*-})/],["kwd",/^(?:case|class|data|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|module|newtype|of|then|type|where|_)(?=[^\d'A-Za-z]|$)/,

From 3b387336bfc097090d5b03f5b01e136bca56f8fd Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Thu, 20 Mar 2014 11:41:24 -0400
Subject: [PATCH 20/41] Add Repository/user name filter

---
 README.md              |  2 +-
 gogs.go                |  2 +-
 models/repo.go         | 31 +++++++++++++++++++++++++++++++
 models/user.go         |  5 +++++
 routers/repo/repo.go   |  3 +++
 routers/repo/single.go |  5 +++++
 routers/user/user.go   |  8 +++++---
 7 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/README.md b/README.md
index 3a1023c6d9..4219e4ed03 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ Gogs(Go Git Service) is a GitHub-like clone in the Go Programming Language.
 
 Since we choose to use pure Go implementation of Git manipulation, Gogs certainly supports **ALL platforms**  that Go supports, including Linux, Max OS X, and Windows with **ZERO** dependency.
 
-##### Current version: 0.1.1 Alpha
+##### Current version: 0.1.4 Alpha
 
 ## Purpose
 
diff --git a/gogs.go b/gogs.go
index d32e3908c9..a600c53d12 100644
--- a/gogs.go
+++ b/gogs.go
@@ -20,7 +20,7 @@ import (
 // Test that go1.1 tag above is included in builds. main.go refers to this definition.
 const go11tag = true
 
-const APP_VER = "0.1.2.0320.1"
+const APP_VER = "0.1.3.0320.1"
 
 func init() {
 	base.AppVer = APP_VER
diff --git a/models/repo.go b/models/repo.go
index 052341ff6e..bcbc586785 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -12,6 +12,7 @@ import (
 	"os"
 	"path"
 	"path/filepath"
+	"regexp"
 	"strings"
 	"sync"
 	"time"
@@ -82,6 +83,7 @@ var (
 	ErrRepoAlreadyExist = errors.New("Repository already exist")
 	ErrRepoNotExist     = errors.New("Repository does not exist")
 	ErrRepoFileNotExist = errors.New("Target Repo file does not exist")
+	ErrRepoNameIllegal  = errors.New("Repository name contains illegal characters")
 )
 
 func init() {
@@ -104,6 +106,15 @@ func init() {
 			os.Exit(2)
 		}
 	}
+
+	// Initialize illegal patterns.
+	for i := range illegalPatterns[1:] {
+		pattern := ""
+		for j := range illegalPatterns[i+1] {
+			pattern += "[" + string(illegalPatterns[i+1][j]-32) + string(illegalPatterns[i+1][j]) + "]"
+		}
+		illegalPatterns[i+1] = pattern
+	}
 }
 
 // IsRepositoryExist returns true if the repository with given name under user has already existed.
@@ -120,8 +131,28 @@ func IsRepositoryExist(user *User, repoName string) (bool, error) {
 	return s.IsDir(), nil
 }
 
+var (
+	// Define as all lower case!!
+	illegalPatterns = []string{"[.][Gg][Ii][Tt]", "user", "help", "stars", "issues", "pulls", "commits", "admin", "repo", "template"}
+)
+
+// IsLegalName returns false if name contains illegal characters.
+func IsLegalName(repoName string) bool {
+	for _, pattern := range illegalPatterns {
+		has, _ := regexp.MatchString(pattern, repoName)
+		if has {
+			return false
+		}
+	}
+	return true
+}
+
 // CreateRepository creates a repository for given user or orgnaziation.
 func CreateRepository(user *User, repoName, desc, repoLang, license string, private bool, initReadme bool) (*Repository, error) {
+	if !IsLegalName(repoName) {
+		return nil, ErrRepoNameIllegal
+	}
+
 	isExist, err := IsRepositoryExist(user, repoName)
 	if err != nil {
 		return nil, err
diff --git a/models/user.go b/models/user.go
index fd89af6b3f..990e1954a5 100644
--- a/models/user.go
+++ b/models/user.go
@@ -79,6 +79,7 @@ var (
 	ErrUserAlreadyExist = errors.New("User already exist")
 	ErrUserNotExist     = errors.New("User does not exist")
 	ErrEmailAlreadyUsed = errors.New("E-mail already used")
+	ErrUserNameIllegal  = errors.New("User name contains illegal characters")
 )
 
 // IsUserExist checks if given user name exist,
@@ -108,6 +109,10 @@ func GetUserSalt() string {
 
 // RegisterUser creates record of a new user.
 func RegisterUser(user *User) (*User, error) {
+	if !IsLegalName(user.Name) {
+		return nil, ErrUserNameIllegal
+	}
+
 	isExist, err := IsUserExist(user.Name)
 	if err != nil {
 		return nil, err
diff --git a/routers/repo/repo.go b/routers/repo/repo.go
index 556cc4343c..c83a6df522 100644
--- a/routers/repo/repo.go
+++ b/routers/repo/repo.go
@@ -31,6 +31,9 @@ func Create(ctx *middleware.Context, form auth.CreateRepoForm) {
 	} else if err == models.ErrRepoAlreadyExist {
 		ctx.RenderWithErr("Repository name has already been used", "repo/create", &form)
 		return
+	} else if err == models.ErrRepoNameIllegal {
+		ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "repo/create", &form)
+		return
 	}
 	ctx.Handle(200, "repo.Create", err)
 }
diff --git a/routers/repo/single.go b/routers/repo/single.go
index f1b15cceed..eab49be919 100644
--- a/routers/repo/single.go
+++ b/routers/repo/single.go
@@ -217,6 +217,11 @@ func Setting(ctx *middleware.Context, params martini.Params) {
 		title = t
 	}
 
+	if len(params["branchname"]) == 0 {
+		params["branchname"] = "master"
+	}
+
+	ctx.Data["Branchname"] = params["branchname"]
 	ctx.Data["Title"] = title + " - settings"
 	ctx.HTML(200, "repo/setting")
 }
diff --git a/routers/user/user.go b/routers/user/user.go
index be2c4d3839..ea6922591e 100644
--- a/routers/user/user.go
+++ b/routers/user/user.go
@@ -139,11 +139,13 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) {
 
 	var err error
 	if u, err = models.RegisterUser(u); err != nil {
-		switch err.Error() {
-		case models.ErrUserAlreadyExist.Error():
+		switch err {
+		case models.ErrUserAlreadyExist:
 			ctx.RenderWithErr("Username has been already taken", "user/signup", &form)
-		case models.ErrEmailAlreadyUsed.Error():
+		case models.ErrEmailAlreadyUsed:
 			ctx.RenderWithErr("E-mail address has been already used", "user/signup", &form)
+		case models.ErrUserNameIllegal:
+			ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "user/signup", &form)
 		default:
 			ctx.Handle(200, "user.SignUp", err)
 		}

From c44aa757d05c2711da1c6e90c0d9d73bcd387433 Mon Sep 17 00:00:00 2001
From: slene <vslene@gmail.com>
Date: Thu, 20 Mar 2014 23:44:13 +0800
Subject: [PATCH 21/41] fix style

---
 public/css/gogs.css     | 2 +-
 public/css/markdown.css | 5 +++++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/public/css/gogs.css b/public/css/gogs.css
index f88b396397..89ae347004 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -683,7 +683,7 @@ html, body {
     padding: 0 8px 0 10px;
     cursor: pointer;
     display: block;
-    margin-top: 6px;
+    margin-top: 2px;
     font-size: 90%;
 }
 
diff --git a/public/css/markdown.css b/public/css/markdown.css
index 68094867b1..fb9d667fb0 100644
--- a/public/css/markdown.css
+++ b/public/css/markdown.css
@@ -123,6 +123,10 @@
   padding: 0;
 }
 
+.markdown > pre > ol.linenums > li {
+  margin-top: 2px;
+}
+
 .markdown > pre.linenums-style > ol.linenums {
   list-style-type: decimal;
   padding: 0 0 0 40px;
@@ -246,6 +250,7 @@
   /* a comment */
   .com {
     color: #999988;
+    font-style: italic;
   }
 
   /* a type name */

From 686348974b1a1f6f11cab5244df2362f99e0a124 Mon Sep 17 00:00:00 2001
From: slene <vslene@gmail.com>
Date: Thu, 20 Mar 2014 23:55:27 +0800
Subject: [PATCH 22/41] fix code style

---
 public/css/gogs.css     | 2 +-
 public/css/markdown.css | 5 +++--
 public/js/app.js        | 2 +-
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/public/css/gogs.css b/public/css/gogs.css
index 89ae347004..b799882352 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -651,7 +651,7 @@ html, body {
     overflow-y: hidden;
 }
 
-.file-content .file-body pre {
+.file-content .file-body.file-code pre {
     background-color: #FFF;
     border: none;
 }
diff --git a/public/css/markdown.css b/public/css/markdown.css
index fb9d667fb0..a810fa3ce7 100644
--- a/public/css/markdown.css
+++ b/public/css/markdown.css
@@ -112,6 +112,7 @@
   overflow: auto;
   background: #f8f8f8;
   border: 1px solid #ddd;
+  padding: 0;
 }
 
 .markdown > pre.linenums {
@@ -127,7 +128,7 @@
   margin-top: 2px;
 }
 
-.markdown > pre.linenums-style > ol.linenums {
+.markdown > pre.nums-style > ol.linenums {
   list-style-type: decimal;
   padding: 0 0 0 40px;
   -webkit-box-shadow: inset 40px 0 0 #f5f5f5, inset 41px 0 0 #ccc;
@@ -152,7 +153,7 @@
   padding-bottom: 12px;
 }
 
-.markdown > pre.linenums-style > ol.linenums > li {
+.markdown > pre.nums-style > ol.linenums > li {
   border-left: 1px solid #ddd;
 }
 
diff --git a/public/js/app.js b/public/js/app.js
index 9a5a0d68ad..a264fc94eb 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -68,7 +68,7 @@ var Gogits = {
     Gogits.renderMarkdown = function () {
         var $md = $('.markdown');
         var $pre = $md.find('pre > code').parent();
-        $pre.addClass('prettyprint');
+        $pre.addClass('prettyprint linenums');
         prettyPrint();
 
         var $lineNums = $pre.parent().siblings('.lines-num');

From 06631ab91f5d84b48d6f71ac8eaf4df740ba0282 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Thu, 20 Mar 2014 16:04:56 -0400
Subject: [PATCH 23/41] Basic admin data table, models changes

---
 README.md                      |   2 +-
 gogs.go                        |   8 +-
 models/issue.go                |  19 +++
 models/models.go               |  56 ++++-----
 models/publickey.go            |  10 +-
 models/repo.go                 | 216 +++++++++++++++++----------------
 models/user.go                 |  97 ++++++++-------
 modules/base/conf.go           |  21 +++-
 routers/admin/admin.go         |  15 +++
 serve.go                       |   4 +-
 templates/admin/dashboard.tmpl |   2 +-
 templates/admin/repos.tmpl     |  24 ++++
 templates/admin/users.tmpl     |  26 ++++
 13 files changed, 291 insertions(+), 209 deletions(-)
 create mode 100644 models/issue.go

diff --git a/README.md b/README.md
index 4219e4ed03..8c971fdb85 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ There are some very good products in this category such as [gitlab](http://gitla
 
 - Please see [Wiki](https://github.com/gogits/gogs/wiki) for project design, develop specification, change log and road map.
 - See [Trello Broad](https://trello.com/b/uxAoeLUl/gogs-go-git-service) to follow the develop team.
-- Try it before anything? Go down to **Installation -> Install from binary** section!.
+- Try it before anything? Do it [online](http://try.gogits.org/Unknown/gogs) or go down to **Installation -> Install from binary** section!
 - Having troubles? Get help from [Troubleshooting](https://github.com/gogits/gogs/wiki/Troubleshooting).
 
 ## Features
diff --git a/gogs.go b/gogs.go
index a600c53d12..a9f7e6b5c4 100644
--- a/gogs.go
+++ b/gogs.go
@@ -15,12 +15,12 @@ import (
 	"github.com/gogits/gogs/modules/base"
 )
 
-// +build go1.1
+// +build go1.2
 
-// Test that go1.1 tag above is included in builds. main.go refers to this definition.
-const go11tag = true
+// Test that go1.2 tag above is included in builds. main.go refers to this definition.
+const go12tag = true
 
-const APP_VER = "0.1.3.0320.1"
+const APP_VER = "0.1.4.0321"
 
 func init() {
 	base.AppVer = APP_VER
diff --git a/models/issue.go b/models/issue.go
new file mode 100644
index 0000000000..c669d201f6
--- /dev/null
+++ b/models/issue.go
@@ -0,0 +1,19 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package models
+
+type Issue struct {
+	Id       int64
+	RepoId   int64 `xorm:"index"`
+	PosterId int64
+}
+
+type PullRequest struct {
+	Id int64
+}
+
+type Comment struct {
+	Id int64
+}
diff --git a/models/models.go b/models/models.go
index 2e0bb759d4..214d1c767a 100644
--- a/models/models.go
+++ b/models/models.go
@@ -15,30 +15,7 @@ import (
 	"github.com/gogits/gogs/modules/base"
 )
 
-var (
-	orm          *xorm.Engine
-	RepoRootPath string
-)
-
-type Members struct {
-	Id     int64
-	OrgId  int64 `xorm:"unique(s) index"`
-	UserId int64 `xorm:"unique(s)"`
-}
-
-type Issue struct {
-	Id       int64
-	RepoId   int64 `xorm:"index"`
-	PosterId int64
-}
-
-type PullRequest struct {
-	Id int64
-}
-
-type Comment struct {
-	Id int64
-}
+var orm *xorm.Engine
 
 func setEngine() {
 	dbType := base.Cfg.MustValue("database", "DB_TYPE")
@@ -65,8 +42,8 @@ func setEngine() {
 		os.Exit(2)
 	}
 
-	// TODO: for serv command, MUST remove the output to os.stdout, so
-	// use log file to instead print to stdout
+	// WARNNING: for serv command, MUST remove the output to os.stdout,
+	// so use log file to instead print to stdout.
 
 	//x.ShowDebug = true
 	//orm.ShowErr = true
@@ -77,20 +54,29 @@ func setEngine() {
 	}
 	orm.Logger = f
 	orm.ShowSQL = true
-
-	// Determine and create root git reposiroty path.
-	RepoRootPath = base.Cfg.MustValue("repository", "ROOT")
-	if err = os.MkdirAll(RepoRootPath, os.ModePerm); err != nil {
-		fmt.Printf("models.init(fail to create RepoRootPath(%s)): %v\n", RepoRootPath, err)
-		os.Exit(2)
-	}
 }
 
 func init() {
 	setEngine()
-	if err := orm.Sync(new(User), new(PublicKey), new(Repository), new(Access),
-		new(Action), new(Watch)); err != nil {
+	if err := orm.Sync(new(User), new(PublicKey), new(Repository), new(Watch),
+		new(Action), new(Access)); err != nil {
 		fmt.Printf("sync database struct error: %v\n", err)
 		os.Exit(2)
 	}
 }
+
+type Statistic struct {
+	Counter struct {
+		User, PublicKey, Repo, Watch, Action, Access int64
+	}
+}
+
+func GetStatistic() (stats Statistic) {
+	stats.Counter.User, _ = orm.Count(new(User))
+	stats.Counter.PublicKey, _ = orm.Count(new(PublicKey))
+	stats.Counter.Repo, _ = orm.Count(new(Repository))
+	stats.Counter.Watch, _ = orm.Count(new(Watch))
+	stats.Counter.Action, _ = orm.Count(new(Action))
+	stats.Counter.Access, _ = orm.Count(new(Access))
+	return stats
+}
diff --git a/models/publickey.go b/models/publickey.go
index 092436d55f..c69bca681d 100644
--- a/models/publickey.go
+++ b/models/publickey.go
@@ -27,8 +27,12 @@ const (
 )
 
 var (
-	sshOpLocker = sync.Mutex{}
+	ErrKeyAlreadyExist = errors.New("Public key already exist")
+)
 
+var sshOpLocker = sync.Mutex{}
+
+var (
 	sshPath string
 	appPath string
 )
@@ -79,10 +83,6 @@ type PublicKey struct {
 	Updated     time.Time `xorm:"updated"`
 }
 
-var (
-	ErrKeyAlreadyExist = errors.New("Public key already exist")
-)
-
 // GenAuthorizedKey returns formatted public key string.
 func GenAuthorizedKey(keyId int64, key string) string {
 	return fmt.Sprintf(TPL_PUBLICK_KEY+"\n", appPath, keyId, key)
diff --git a/models/repo.go b/models/repo.go
index bcbc586785..f7173d76d0 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -27,63 +27,18 @@ import (
 	"github.com/gogits/gogs/modules/log"
 )
 
-// Repository represents a git repository.
-type Repository struct {
-	Id          int64
-	OwnerId     int64 `xorm:"unique(s)"`
-	ForkId      int64
-	LowerName   string `xorm:"unique(s) index not null"`
-	Name        string `xorm:"index not null"`
-	Description string
-	Website     string
-	Private     bool
-	NumWatchs   int
-	NumStars    int
-	NumForks    int
-	Created     time.Time `xorm:"created"`
-	Updated     time.Time `xorm:"updated"`
-}
-
-// Watch is connection request for receiving repository notifycation.
-type Watch struct {
-	Id     int64
-	RepoId int64 `xorm:"UNIQUE(watch)"`
-	UserId int64 `xorm:"UNIQUE(watch)"`
-}
-
-// Watch or unwatch repository.
-func WatchRepo(userId, repoId int64, watch bool) (err error) {
-	if watch {
-		_, err = orm.Insert(&Watch{RepoId: repoId, UserId: userId})
-	} else {
-		_, err = orm.Delete(&Watch{0, repoId, userId})
-	}
-	return err
-}
-
-// GetWatches returns all watches of given repository.
-func GetWatches(repoId int64) ([]Watch, error) {
-	watches := make([]Watch, 0, 10)
-	err := orm.Find(&watches, &Watch{RepoId: repoId})
-	return watches, err
-}
-
-// IsWatching checks if user has watched given repository.
-func IsWatching(userId, repoId int64) bool {
-	has, _ := orm.Get(&Watch{0, repoId, userId})
-	return has
-}
-
 var (
-	gitInitLocker          = sync.Mutex{}
-	LanguageIgns, Licenses []string
+	ErrRepoAlreadyExist  = errors.New("Repository already exist")
+	ErrRepoNotExist      = errors.New("Repository does not exist")
+	ErrRepoFileNotExist  = errors.New("Target Repo file does not exist")
+	ErrRepoNameIllegal   = errors.New("Repository name contains illegal characters")
+	ErrRepoFileNotLoaded = fmt.Errorf("repo file not loaded")
 )
 
+var gitInitLocker = sync.Mutex{}
+
 var (
-	ErrRepoAlreadyExist = errors.New("Repository already exist")
-	ErrRepoNotExist     = errors.New("Repository does not exist")
-	ErrRepoFileNotExist = errors.New("Target Repo file does not exist")
-	ErrRepoNameIllegal  = errors.New("Repository name contains illegal characters")
+	LanguageIgns, Licenses []string
 )
 
 func init() {
@@ -117,6 +72,23 @@ func init() {
 	}
 }
 
+// Repository represents a git repository.
+type Repository struct {
+	Id          int64
+	OwnerId     int64 `xorm:"unique(s)"`
+	ForkId      int64
+	LowerName   string `xorm:"unique(s) index not null"`
+	Name        string `xorm:"index not null"`
+	Description string
+	Website     string
+	Private     bool
+	NumWatches  int
+	NumStars    int
+	NumForks    int
+	Created     time.Time `xorm:"created"`
+	Updated     time.Time `xorm:"updated"`
+}
+
 // IsRepositoryExist returns true if the repository with given name under user has already existed.
 func IsRepositoryExist(user *User, repoName string) (bool, error) {
 	repo := Repository{OwnerId: user.Id}
@@ -351,6 +323,60 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep
 	return nil
 }
 
+// GetRepos returns given number of repository objects with offset.
+func GetRepos(num, offset int) ([]Repository, error) {
+	repos := make([]Repository, 0, num)
+	err := orm.Limit(num, offset).Asc("id").Find(&repos)
+	return repos, err
+}
+
+func RepoPath(userName, repoName string) string {
+	return filepath.Join(UserPath(userName), repoName+".git")
+}
+
+// DeleteRepository deletes a repository for a user or orgnaztion.
+func DeleteRepository(userId, repoId int64, userName string) (err error) {
+	repo := &Repository{Id: repoId, OwnerId: userId}
+	has, err := orm.Get(repo)
+	if err != nil {
+		return err
+	} else if !has {
+		return ErrRepoNotExist
+	}
+
+	session := orm.NewSession()
+	if err = session.Begin(); err != nil {
+		return err
+	}
+	if _, err = session.Delete(&Repository{Id: repoId}); err != nil {
+		session.Rollback()
+		return err
+	}
+	if _, err := session.Delete(&Access{UserName: userName, RepoName: repo.Name}); err != nil {
+		session.Rollback()
+		return err
+	}
+	rawSql := "UPDATE `user` SET num_repos = num_repos - 1 WHERE id = ?"
+	if _, err = session.Exec(rawSql, userId); err != nil {
+		session.Rollback()
+		return err
+	}
+	if _, err = session.Delete(&Watch{RepoId: repoId}); err != nil {
+		session.Rollback()
+		return err
+	}
+	if err = session.Commit(); err != nil {
+		session.Rollback()
+		return err
+	}
+	if err = os.RemoveAll(RepoPath(userName, repo.Name)); err != nil {
+		// TODO: log and delete manully
+		log.Error("delete repo %s/%s failed: %v", userName, repo.Name, err)
+		return err
+	}
+	return nil
+}
+
 // GetRepositoryByName returns the repository by given name under user if exists.
 func GetRepositoryByName(user *User, repoName string) (*Repository, error) {
 	repo := &Repository{
@@ -388,6 +414,36 @@ func GetRepositoryCount(user *User) (int64, error) {
 	return orm.Count(&Repository{OwnerId: user.Id})
 }
 
+// Watch is connection request for receiving repository notifycation.
+type Watch struct {
+	Id     int64
+	RepoId int64 `xorm:"UNIQUE(watch)"`
+	UserId int64 `xorm:"UNIQUE(watch)"`
+}
+
+// Watch or unwatch repository.
+func WatchRepo(userId, repoId int64, watch bool) (err error) {
+	if watch {
+		_, err = orm.Insert(&Watch{RepoId: repoId, UserId: userId})
+	} else {
+		_, err = orm.Delete(&Watch{0, repoId, userId})
+	}
+	return err
+}
+
+// GetWatches returns all watches of given repository.
+func GetWatches(repoId int64) ([]Watch, error) {
+	watches := make([]Watch, 0, 10)
+	err := orm.Find(&watches, &Watch{RepoId: repoId})
+	return watches, err
+}
+
+// IsWatching checks if user has watched given repository.
+func IsWatching(userId, repoId int64) bool {
+	has, _ := orm.Get(&Watch{0, repoId, userId})
+	return has
+}
+
 func StarReposiory(user *User, repoName string) error {
 	return nil
 }
@@ -408,60 +464,6 @@ func ForkRepository(reposName string, userId int64) {
 
 }
 
-func RepoPath(userName, repoName string) string {
-	return filepath.Join(UserPath(userName), repoName+".git")
-}
-
-// DeleteRepository deletes a repository for a user or orgnaztion.
-func DeleteRepository(userId, repoId int64, userName string) (err error) {
-	repo := &Repository{Id: repoId, OwnerId: userId}
-	has, err := orm.Get(repo)
-	if err != nil {
-		return err
-	} else if !has {
-		return ErrRepoNotExist
-	}
-
-	session := orm.NewSession()
-	if err = session.Begin(); err != nil {
-		return err
-	}
-	if _, err = session.Delete(&Repository{Id: repoId}); err != nil {
-		session.Rollback()
-		return err
-	}
-	if _, err := session.Delete(&Access{UserName: userName, RepoName: repo.Name}); err != nil {
-		session.Rollback()
-		return err
-	}
-	rawSql := "UPDATE user SET num_repos = num_repos - 1 WHERE id = ?"
-	if base.Cfg.MustValue("database", "DB_TYPE") == "postgres" {
-		rawSql = "UPDATE \"user\" SET num_repos = num_repos - 1 WHERE id = ?"
-	}
-	if _, err = session.Exec(rawSql, userId); err != nil {
-		session.Rollback()
-		return err
-	}
-	if _, err = session.Delete(&Watch{RepoId: repoId}); err != nil {
-		session.Rollback()
-		return err
-	}
-	if err = session.Commit(); err != nil {
-		session.Rollback()
-		return err
-	}
-	if err = os.RemoveAll(RepoPath(userName, repo.Name)); err != nil {
-		// TODO: log and delete manully
-		log.Error("delete repo %s/%s failed: %v", userName, repo.Name, err)
-		return err
-	}
-	return nil
-}
-
-var (
-	ErrRepoFileNotLoaded = fmt.Errorf("repo file not loaded")
-)
-
 // RepoFile represents a file object in git repository.
 type RepoFile struct {
 	*git.TreeEntry
diff --git a/models/user.go b/models/user.go
index 990e1954a5..3c11091285 100644
--- a/models/user.go
+++ b/models/user.go
@@ -33,6 +33,14 @@ const (
 	LT_LDAP
 )
 
+var (
+	ErrUserOwnRepos     = errors.New("User still have ownership of repositories")
+	ErrUserAlreadyExist = errors.New("User already exist")
+	ErrUserNotExist     = errors.New("User does not exist")
+	ErrEmailAlreadyUsed = errors.New("E-mail already used")
+	ErrUserNameIllegal  = errors.New("User name contains illegal characters")
+)
+
 // User represents the object of individual and member of organization.
 type User struct {
 	Id            int64
@@ -67,20 +75,28 @@ func (user *User) AvatarLink() string {
 	return "http://1.gravatar.com/avatar/" + user.Avatar
 }
 
-type Follow struct {
-	Id       int64
-	UserId   int64     `xorm:"unique(s)"`
-	FollowId int64     `xorm:"unique(s)"`
-	Created  time.Time `xorm:"created"`
+// NewGitSig generates and returns the signature of given user.
+func (user *User) NewGitSig() *git.Signature {
+	return &git.Signature{
+		Name:  user.Name,
+		Email: user.Email,
+		When:  time.Now(),
+	}
 }
 
-var (
-	ErrUserOwnRepos     = errors.New("User still have ownership of repositories")
-	ErrUserAlreadyExist = errors.New("User already exist")
-	ErrUserNotExist     = errors.New("User does not exist")
-	ErrEmailAlreadyUsed = errors.New("E-mail already used")
-	ErrUserNameIllegal  = errors.New("User name contains illegal characters")
-)
+// EncodePasswd encodes password to safe format.
+func (user *User) EncodePasswd() error {
+	newPasswd, err := scrypt.Key([]byte(user.Passwd), []byte(base.SecretKey), 16384, 8, 1, 64)
+	user.Passwd = fmt.Sprintf("%x", newPasswd)
+	return err
+}
+
+// Member represents user is member of organization.
+type Member struct {
+	Id     int64
+	OrgId  int64 `xorm:"unique(member) index"`
+	UserId int64 `xorm:"unique(member)"`
+}
 
 // IsUserExist checks if given user name exist,
 // the user name should be noncased unique.
@@ -93,15 +109,6 @@ func IsEmailUsed(email string) (bool, error) {
 	return orm.Get(&User{Email: email})
 }
 
-// NewGitSig generates and returns the signature of given user.
-func (user *User) NewGitSig() *git.Signature {
-	return &git.Signature{
-		Name:  user.Name,
-		Email: user.Email,
-		When:  time.Now(),
-	}
-}
-
 // return a user salt token
 func GetUserSalt() string {
 	return base.GetRandomString(10)
@@ -151,6 +158,13 @@ func RegisterUser(user *User) (*User, error) {
 	return user, err
 }
 
+// GetUsers returns given number of user objects with offset.
+func GetUsers(num, offset int) ([]User, error) {
+	users := make([]User, 0, num)
+	err := orm.Limit(num, offset).Asc("id").Find(&users)
+	return users, err
+}
+
 // get user by erify code
 func getVerifyUser(code string) (user *User) {
 	if len(code) <= base.TimeLimitCodeLength {
@@ -229,24 +243,14 @@ func DeleteUser(user *User) error {
 	return err
 }
 
-// EncodePasswd encodes password to safe format.
-func (user *User) EncodePasswd() error {
-	newPasswd, err := scrypt.Key([]byte(user.Passwd), []byte(base.SecretKey), 16384, 8, 1, 64)
-	user.Passwd = fmt.Sprintf("%x", newPasswd)
-	return err
-}
-
 // UserPath returns the path absolute path of user repositories.
 func UserPath(userName string) string {
-	return filepath.Join(RepoRootPath, strings.ToLower(userName))
+	return filepath.Join(base.RepoRootPath, strings.ToLower(userName))
 }
 
 func GetUserByKeyId(keyId int64) (*User, error) {
 	user := new(User)
-	rawSql := "SELECT a.* FROM user AS a, public_key AS b WHERE a.id = b.owner_id AND b.id=?"
-	if base.Cfg.MustValue("database", "DB_TYPE") == "postgres" {
-		rawSql = "SELECT a.* FROM \"user\" AS a, public_key AS b WHERE a.id = b.owner_id AND b.id=?"
-	}
+	rawSql := "SELECT a.* FROM `user` AS a, public_key AS b WHERE a.id = b.owner_id AND b.id=?"
 	has, err := orm.Sql(rawSql, keyId).Get(user)
 	if err != nil {
 		return nil, err
@@ -303,6 +307,13 @@ func LoginUserPlain(name, passwd string) (*User, error) {
 	return &user, err
 }
 
+// Follow is connection request for receiving user notifycation.
+type Follow struct {
+	Id       int64
+	UserId   int64 `xorm:"unique(follow)"`
+	FollowId int64 `xorm:"unique(follow)"`
+}
+
 // FollowUser marks someone be another's follower.
 func FollowUser(userId int64, followId int64) (err error) {
 	session := orm.NewSession()
@@ -314,19 +325,13 @@ func FollowUser(userId int64, followId int64) (err error) {
 		return err
 	}
 
-	rawSql := "UPDATE user SET num_followers = num_followers + 1 WHERE id = ?"
-	if base.Cfg.MustValue("database", "DB_TYPE") == "postgres" {
-		rawSql = "UPDATE \"user\" SET num_followers = num_followers + 1 WHERE id = ?"
-	}
+	rawSql := "UPDATE `user` SET num_followers = num_followers + 1 WHERE id = ?"
 	if _, err = session.Exec(rawSql, followId); err != nil {
 		session.Rollback()
 		return err
 	}
 
-	rawSql = "UPDATE user SET num_followings = num_followings + 1 WHERE id = ?"
-	if base.Cfg.MustValue("database", "DB_TYPE") == "postgres" {
-		rawSql = "UPDATE \"user\" SET num_followings = num_followings + 1 WHERE id = ?"
-	}
+	rawSql = "UPDATE `user` SET num_followings = num_followings + 1 WHERE id = ?"
 	if _, err = session.Exec(rawSql, userId); err != nil {
 		session.Rollback()
 		return err
@@ -345,19 +350,13 @@ func UnFollowUser(userId int64, unFollowId int64) (err error) {
 		return err
 	}
 
-	rawSql := "UPDATE user SET num_followers = num_followers - 1 WHERE id = ?"
-	if base.Cfg.MustValue("database", "DB_TYPE") == "postgres" {
-		rawSql = "UPDATE \"user\" SET num_followers = num_followers - 1 WHERE id = ?"
-	}
+	rawSql := "UPDATE `user` SET num_followers = num_followers - 1 WHERE id = ?"
 	if _, err = session.Exec(rawSql, unFollowId); err != nil {
 		session.Rollback()
 		return err
 	}
 
-	rawSql = "UPDATE user SET num_followings = num_followings - 1 WHERE id = ?"
-	if base.Cfg.MustValue("database", "DB_TYPE") == "postgres" {
-		rawSql = "UPDATE \"user\" SET num_followings = num_followings - 1 WHERE id = ?"
-	}
+	rawSql = "UPDATE `user` SET num_followings = num_followings - 1 WHERE id = ?"
 	if _, err = session.Exec(rawSql, userId); err != nil {
 		session.Rollback()
 		return err
diff --git a/modules/base/conf.go b/modules/base/conf.go
index fdbf3ad385..81f32bd591 100644
--- a/modules/base/conf.go
+++ b/modules/base/conf.go
@@ -26,12 +26,14 @@ type Mailer struct {
 }
 
 var (
-	AppVer      string
-	AppName     string
-	AppLogo     string
-	AppUrl      string
-	Domain      string
-	SecretKey   string
+	AppVer       string
+	AppName      string
+	AppLogo      string
+	AppUrl       string
+	Domain       string
+	SecretKey    string
+	RepoRootPath string
+
 	Cfg         *goconfig.ConfigFile
 	MailService *Mailer
 )
@@ -173,6 +175,13 @@ func init() {
 	AppUrl = Cfg.MustValue("server", "ROOT_URL")
 	Domain = Cfg.MustValue("server", "DOMAIN")
 	SecretKey = Cfg.MustValue("security", "SECRET_KEY")
+
+	// Determine and create root git reposiroty path.
+	RepoRootPath = Cfg.MustValue("repository", "ROOT")
+	if err = os.MkdirAll(RepoRootPath, os.ModePerm); err != nil {
+		fmt.Printf("models.init(fail to create RepoRootPath(%s)): %v\n", RepoRootPath, err)
+		os.Exit(2)
+	}
 }
 
 func NewServices() {
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
index c7523b7f59..a37f1207c9 100644
--- a/routers/admin/admin.go
+++ b/routers/admin/admin.go
@@ -5,20 +5,35 @@
 package admin
 
 import (
+	"github.com/gogits/gogs/models"
 	"github.com/gogits/gogs/modules/middleware"
 )
 
 func Dashboard(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Admin Dashboard"
+	ctx.Data["Stats"] = models.GetStatistic()
 	ctx.HTML(200, "admin/dashboard")
 }
 
 func Users(ctx *middleware.Context) {
 	ctx.Data["Title"] = "User Management"
+
+	var err error
+	ctx.Data["Users"], err = models.GetUsers(100, 0)
+	if err != nil {
+		ctx.Handle(200, "admin.Users", err)
+		return
+	}
 	ctx.HTML(200, "admin/users")
 }
 
 func Repositories(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Repository Management"
+	var err error
+	ctx.Data["Repos"], err = models.GetRepos(100, 0)
+	if err != nil {
+		ctx.Handle(200, "admin.Repositories", err)
+		return
+	}
 	ctx.HTML(200, "admin/repos")
 }
diff --git a/serve.go b/serve.go
index ddc670235e..2a17a33490 100644
--- a/serve.go
+++ b/serve.go
@@ -12,7 +12,9 @@ import (
 	"strings"
 
 	"github.com/codegangsta/cli"
+
 	"github.com/gogits/gogs/models"
+	"github.com/gogits/gogs/modules/base"
 )
 
 var (
@@ -144,7 +146,7 @@ func runServ(*cli.Context) {
 	}
 
 	gitcmd := exec.Command(verb, rRepo)
-	gitcmd.Dir = models.RepoRootPath
+	gitcmd.Dir = base.RepoRootPath
 	gitcmd.Stdout = os.Stdout
 	gitcmd.Stdin = os.Stdin
 	gitcmd.Stderr = os.Stderr
diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl
index 84456c85b8..6a914b65f7 100644
--- a/templates/admin/dashboard.tmpl
+++ b/templates/admin/dashboard.tmpl
@@ -16,7 +16,7 @@
             </div>
 
             <div class="panel-body">
-                Gogs database has 4 users, 3 repositories, 4 SSH keys.
+                Gogs database has <b>{{.Stats.Counter.User}}</b> users, <b>{{.Stats.Counter.PublicKey}}</b> SSH keys, <b>{{.Stats.Counter.Repo}}</b> repositories, <b>{{.Stats.Counter.Watch}}</b> watches, <b>{{.Stats.Counter.Action}}</b> actions, and <b>{{.Stats.Counter.Access}}</b> accesses.
             </div>
         </div>
     </div>
diff --git a/templates/admin/repos.tmpl b/templates/admin/repos.tmpl
index ec7f47e090..4522c66792 100644
--- a/templates/admin/repos.tmpl
+++ b/templates/admin/repos.tmpl
@@ -16,6 +16,30 @@
             </div>
 
             <div class="panel-body">
+                <table class="table table-striped">
+                    <thead>
+                        <tr>
+                            <th>Id</th>
+                            <th>Name</th>
+                            <th>Private</th>
+                            <th>Watches</th>
+                            <th>Forks</th>
+                            <th>Created</th>
+                        </tr>
+                    </thead>
+                    <tbody>
+                        {{range .Repos}}
+                        <tr>
+                            <td>{{.Id}}</td>
+                            <td>{{.Name}}</td>
+                            <td><i class="fa fa{{if .Private}}-check{{end}}-square-o"></i></td>
+                            <td>{{.NumWatches}}</td>
+                            <td>{{.NumForks}}</td>
+                            <td>{{DateFormat .Created "M d, Y"}}</td>
+                        </tr>
+                        {{end}}
+                    </tbody>
+                </table>
             </div>
         </div>
     </div>
diff --git a/templates/admin/users.tmpl b/templates/admin/users.tmpl
index 8acf256d05..c087f268f2 100644
--- a/templates/admin/users.tmpl
+++ b/templates/admin/users.tmpl
@@ -16,6 +16,32 @@
             </div>
 
             <div class="panel-body">
+                <table class="table table-striped">
+                    <thead>
+                        <tr>
+                            <th>Id</th>
+                            <th>Name</th>
+                            <th>E-mail</th>
+                            <th>Actived</th>
+                            <th>Admin</th>
+                            <th>Repos</th>
+                            <th>Join</th>
+                        </tr>
+                    </thead>
+                    <tbody>
+                        {{range .Users}}
+                        <tr>
+                            <td>{{.Id}}</td>
+                            <td>{{.Name}}</td>
+                            <td>{{.Email}}</td>
+                            <td><i class="fa fa{{if .IsActive}}-check{{end}}-square-o"></i></td>
+                            <td><i class="fa fa{{if .IsAdmin}}-check{{end}}-square-o"></i></td>
+                            <td>{{.NumRepos}}</td>
+                            <td>{{DateFormat .Created "M d, Y"}}</td>
+                        </tr>
+                        {{end}}
+                    </tbody>
+                </table>
             </div>
         </div>
     </div>

From 53a17bbd240e0dd3755b7a666792d69e358f3e00 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Thu, 20 Mar 2014 16:14:50 -0400
Subject: [PATCH 24/41] Bug fix

---
 models/repo.go | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/models/repo.go b/models/repo.go
index f7173d76d0..f5ceaf7631 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -424,9 +424,18 @@ type Watch struct {
 // Watch or unwatch repository.
 func WatchRepo(userId, repoId int64, watch bool) (err error) {
 	if watch {
-		_, err = orm.Insert(&Watch{RepoId: repoId, UserId: userId})
+		if _, err = orm.Insert(&Watch{RepoId: repoId, UserId: userId}); err != nil {
+			return err
+		}
+
+		rawSql := "UPDATE `repository` SET num_watches = num_watches + 1 WHERE id = ?"
+		_, err = orm.Exec(rawSql, repoId)
 	} else {
-		_, err = orm.Delete(&Watch{0, repoId, userId})
+		if _, err = orm.Delete(&Watch{0, repoId, userId}); err != nil {
+			return err
+		}
+		rawSql := "UPDATE `repository` SET num_watches = num_watches - 1 WHERE id = ?"
+		_, err = orm.Exec(rawSql, repoId)
 	}
 	return err
 }

From 369ddf76a8ae6916ab72f1fa26c81b44c456c6ea Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 21 Mar 2014 01:09:22 -0400
Subject: [PATCH 25/41] Batch fix

---
 README.md                  |  2 +-
 conf/app.ini               |  8 +++++++-
 models/action.go           |  4 ++++
 models/models.go           |  5 +++++
 models/repo.go             | 28 +++++++++++++++++++++++++---
 modules/base/conf.go       |  8 +++++---
 modules/base/template.go   | 11 ++++++++++-
 routers/user/user.go       |  6 ++++++
 templates/admin/repos.tmpl |  4 +++-
 templates/admin/users.tmpl |  2 +-
 templates/base/navbar.tmpl |  3 ++-
 templates/repo/single.tmpl |  2 +-
 templates/user/signin.tmpl |  2 +-
 templates/user/signup.tmpl |  4 ++++
 14 files changed, 75 insertions(+), 14 deletions(-)

diff --git a/README.md b/README.md
index 8c971fdb85..3668ae8998 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ There are some very good products in this category such as [gitlab](http://gitla
 - Repository viewer.
 - Gravatar support.
 - Mail service(register).
-- Supports MySQL and PostgreSQL.
+- Supports MySQL, PostgreSQL and SQLite3(binary release only).
 
 ## Installation
 
diff --git a/conf/app.ini b/conf/app.ini
index 658f7c0151..d38cd1f05e 100644
--- a/conf/app.ini
+++ b/conf/app.ini
@@ -18,7 +18,7 @@ HTTP_ADDR =
 HTTP_PORT = 3000
 
 [database]
-; Either "mysql" or "postgres", it's your choice
+; Either "mysql", "postgres" or "sqlite3"(binary release only), it's your choice
 DB_TYPE = mysql
 HOST = 
 NAME = gogs
@@ -26,6 +26,10 @@ USER = root
 PASSWD =
 ; For "postgres" only, either "disable", "require" or "verify-full"
 SSL_MODE = disable
+; For "sqlite3" only
+PATH = data/gogs.db
+
+[admin]
 
 [security]
 ; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!!
@@ -36,6 +40,8 @@ ACTIVE_CODE_LIVE_MINUTES = 180
 RESET_PASSWD_CODE_LIVE_MINUTES = 180
 ; User need to confirm e-mail for registration
 REGISTER_EMAIL_CONFIRM = false
+; Does not allow register and admin create account only
+DISENABLE_REGISTERATION = false
 
 [mailer]
 ENABLED = false
diff --git a/models/action.go b/models/action.go
index b3be093533..107d4b1057 100644
--- a/models/action.go
+++ b/models/action.go
@@ -64,6 +64,10 @@ func CommitRepoAction(userId int64, userName string,
 	watches = append(watches, Watch{UserId: userId})
 
 	for i := range watches {
+		if userId == watches[i].UserId && i > 0 {
+			continue // Do not add twice in case author watches his/her repository.
+		}
+
 		_, err = orm.InsertOne(&Action{
 			UserId:      watches[i].UserId,
 			ActUserId:   userId,
diff --git a/models/models.go b/models/models.go
index 214d1c767a..8df230975f 100644
--- a/models/models.go
+++ b/models/models.go
@@ -7,6 +7,7 @@ package models
 import (
 	"fmt"
 	"os"
+	"path"
 
 	_ "github.com/go-sql-driver/mysql"
 	_ "github.com/lib/pq"
@@ -23,6 +24,7 @@ func setEngine() {
 	dbName := base.Cfg.MustValue("database", "NAME")
 	dbUser := base.Cfg.MustValue("database", "USER")
 	dbPwd := base.Cfg.MustValue("database", "PASSWD")
+	dbPath := base.Cfg.MustValue("database", "PATH", "data/gogs.db")
 	sslMode := base.Cfg.MustValue("database", "SSL_MODE")
 
 	var err error
@@ -33,6 +35,9 @@ func setEngine() {
 	case "postgres":
 		orm, err = xorm.NewEngine("postgres", fmt.Sprintf("user=%s password=%s dbname=%s sslmode=%s",
 			dbUser, dbPwd, dbName, sslMode))
+	case "sqlite3":
+		os.MkdirAll(path.Dir(dbPath), os.ModePerm)
+		orm, err = xorm.NewEngine("sqlite3", dbPath)
 	default:
 		fmt.Printf("Unknown database type: %s\n", dbType)
 		os.Exit(2)
diff --git a/models/repo.go b/models/repo.go
index f5ceaf7631..93f68ceddf 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -323,11 +323,33 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep
 	return nil
 }
 
+// UserRepo reporesents a repository with user name.
+type UserRepo struct {
+	*Repository
+	UserName string
+}
+
 // GetRepos returns given number of repository objects with offset.
-func GetRepos(num, offset int) ([]Repository, error) {
+func GetRepos(num, offset int) ([]UserRepo, error) {
 	repos := make([]Repository, 0, num)
-	err := orm.Limit(num, offset).Asc("id").Find(&repos)
-	return repos, err
+	if err := orm.Limit(num, offset).Asc("id").Find(&repos); err != nil {
+		return nil, err
+	}
+
+	urepos := make([]UserRepo, len(repos))
+	for i := range repos {
+		urepos[i].Repository = &repos[i]
+		u := new(User)
+		has, err := orm.Id(urepos[i].Repository.OwnerId).Get(u)
+		if err != nil {
+			return nil, err
+		} else if !has {
+			return nil, ErrUserNotExist
+		}
+		urepos[i].UserName = u.Name
+	}
+
+	return urepos, nil
 }
 
 func RepoPath(userName, repoName string) string {
diff --git a/modules/base/conf.go b/modules/base/conf.go
index 81f32bd591..41b66b69f8 100644
--- a/modules/base/conf.go
+++ b/modules/base/conf.go
@@ -39,9 +39,10 @@ var (
 )
 
 var Service struct {
-	RegisterEmailConfirm bool
-	ActiveCodeLives      int
-	ResetPwdCodeLives    int
+	RegisterEmailConfirm   bool
+	DisenableRegisteration bool
+	ActiveCodeLives        int
+	ResetPwdCodeLives      int
 }
 
 func exeDir() (string, error) {
@@ -68,6 +69,7 @@ var logLevels = map[string]string{
 func newService() {
 	Service.ActiveCodeLives = Cfg.MustInt("service", "ACTIVE_CODE_LIVE_MINUTES", 180)
 	Service.ResetPwdCodeLives = Cfg.MustInt("service", "RESET_PASSWD_CODE_LIVE_MINUTES", 180)
+	Service.DisenableRegisteration = Cfg.MustBool("service", "DISENABLE_REGISTERATION", false)
 }
 
 func newLogService() {
diff --git a/modules/base/template.go b/modules/base/template.go
index e596d1dada..8d95dbeab7 100644
--- a/modules/base/template.go
+++ b/modules/base/template.go
@@ -33,6 +33,10 @@ func List(l *list.List) chan interface{} {
 	return c
 }
 
+var mailDomains = map[string]string{
+	"gmail.com": "gmail.com",
+}
+
 var TemplateFuncs template.FuncMap = map[string]interface{}{
 	"AppName": func() string {
 		return AppName
@@ -56,7 +60,12 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
 	"DateFormat": DateFormat,
 	"List":       List,
 	"Mail2Domain": func(mail string) string {
-		return "mail." + strings.Split(mail, "@")[1]
+		suffix := strings.SplitN(mail, "@", 2)[1]
+		domain, ok := mailDomains[suffix]
+		if !ok {
+			return "mail." + suffix
+		}
+		return domain
 	},
 	"SubStr": func(str string, start, length int) string {
 		return str[start : start+length]
diff --git a/routers/user/user.go b/routers/user/user.go
index ea6922591e..40b594ab80 100644
--- a/routers/user/user.go
+++ b/routers/user/user.go
@@ -112,6 +112,12 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) {
 	ctx.Data["Title"] = "Sign Up"
 	ctx.Data["PageIsSignUp"] = true
 
+	if base.Service.DisenableRegisteration {
+		ctx.Data["DisenableRegisteration"] = true
+		ctx.HTML(200, "user/signup")
+		return
+	}
+
 	if ctx.Req.Method == "GET" {
 		ctx.HTML(200, "user/signup")
 		return
diff --git a/templates/admin/repos.tmpl b/templates/admin/repos.tmpl
index 4522c66792..f4834c9060 100644
--- a/templates/admin/repos.tmpl
+++ b/templates/admin/repos.tmpl
@@ -20,6 +20,7 @@
                     <thead>
                         <tr>
                             <th>Id</th>
+                            <th>Owner</th>
                             <th>Name</th>
                             <th>Private</th>
                             <th>Watches</th>
@@ -31,7 +32,8 @@
                         {{range .Repos}}
                         <tr>
                             <td>{{.Id}}</td>
-                            <td>{{.Name}}</td>
+                            <th>{{.UserName}}</th>
+                            <td><a href="/{{.UserName}}/{{.Name}}">{{.Name}}</a></td>
                             <td><i class="fa fa{{if .Private}}-check{{end}}-square-o"></i></td>
                             <td>{{.NumWatches}}</td>
                             <td>{{.NumForks}}</td>
diff --git a/templates/admin/users.tmpl b/templates/admin/users.tmpl
index c087f268f2..b690e1771e 100644
--- a/templates/admin/users.tmpl
+++ b/templates/admin/users.tmpl
@@ -32,7 +32,7 @@
                         {{range .Users}}
                         <tr>
                             <td>{{.Id}}</td>
-                            <td>{{.Name}}</td>
+                            <td><a href="/user/{{.Name}}">{{.Name}}</a></td>
                             <td>{{.Email}}</td>
                             <td><i class="fa fa{{if .IsActive}}-check{{end}}-square-o"></i></td>
                             <td><i class="fa fa{{if .IsAdmin}}-check{{end}}-square-o"></i></td>
diff --git a/templates/base/navbar.tmpl b/templates/base/navbar.tmpl
index 9c064d07e7..d775191a5a 100644
--- a/templates/base/navbar.tmpl
+++ b/templates/base/navbar.tmpl
@@ -11,7 +11,8 @@
             <a class="navbar-right gogs-nav-item{{if .PageIsNewRepo}} active{{end}}" href="/repo/create" data-toggle="tooltip" data-placement="bottom" title="New Repository"><i class="fa fa-plus fa-lg"></i></a>
             <a class="navbar-right gogs-nav-item{{if .PageIsUserSetting}} active{{end}}" href="/user/setting"  data-toggle="tooltip" data-placement="bottom" title="Setting"><i class="fa fa-cogs fa-lg"></i></a>
             {{if .IsAdmin}}<a class="navbar-right gogs-nav-item{{if .PageIsAdmin}} active{{end}}" href="/admin"  data-toggle="tooltip" data-placement="bottom" title="Admin"><i class="fa fa-gear fa-lg"></i></a>{{end}}
-            {{else}}<a id="gogs-nav-signin" class="gogs-nav-item navbar-right navbar-btn btn btn-danger" href="/user/login/">Sign in</a>{{end}}
+            {{else}}<a id="gogs-nav-signin" class="gogs-nav-item navbar-right navbar-btn btn btn-success" href="/user/login/">Sign In</a>
+            <a id="gogs-nav-signup" class="gogs-nav-item navbar-right navbar-btn btn btn-info" href="/user/sign_up/">Sign Up</a>{{end}}
         </nav>
     </div>
 </div>
diff --git a/templates/repo/single.tmpl b/templates/repo/single.tmpl
index 8a7b5e479b..a1c3cfbb26 100644
--- a/templates/repo/single.tmpl
+++ b/templates/repo/single.tmpl
@@ -15,7 +15,7 @@
                     <b class="caret"></b></a>
                 <ul class="dropdown-menu">
                     {{range .Branches}}
-                    <li><a {{if eq . $.Branchname}}class="current" {{end}}href="{{$.BranchLink}}">{{.}}</a></li>
+                    <li><a {{if eq . $.Branchname}}class="current" {{end}}href="/{{$.Username}}/{{$.Reponame}}/src/{{.}}">{{.}}</a></li>
                     {{end}}
                 </ul>
             </div>
diff --git a/templates/user/signin.tmpl b/templates/user/signin.tmpl
index e60cedec88..a49bf11405 100644
--- a/templates/user/signin.tmpl
+++ b/templates/user/signin.tmpl
@@ -32,7 +32,7 @@
         </div>
 
         <div class="form-group text-center" id="gogs-social-login">
-            <a class="btn btn-default btn-lg">Social Login</a>
+            <a class="btn btn-danger btn-lg">Register new account</a>
         </div>
     </form>
 </div>
diff --git a/templates/user/signup.tmpl b/templates/user/signup.tmpl
index 187364de8f..069d34a5b2 100644
--- a/templates/user/signup.tmpl
+++ b/templates/user/signup.tmpl
@@ -2,6 +2,9 @@
 {{template "base/navbar" .}}
 <div class="container" id="gogs-body" data-page="user-signup">
 	<form action="/user/sign_up" method="post" class="form-horizontal gogs-card" id="gogs-login-card">
+		{{if .DisenableRegisteration}}
+		Sorry, registeration has been disenabled, you can only get account from administrator.
+		{{else}}
         <h3>Sign Up</h3>
 	    <div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div>
 		<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}">
@@ -43,6 +46,7 @@
                 <a href="/user/login">Already have an account? Sign in now!</a>
             </div>
 	    </div>
+	    {{end}}
 	</form>
 </div>
 {{template "base/footer" .}}
\ No newline at end of file

From f6596f11c4aacd3c7c30098f7ffe79e936d21583 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 21 Mar 2014 01:48:10 -0400
Subject: [PATCH 26/41] All configuration reload-able

---
 README.md                      |  1 +
 models/models.go               | 39 +++++++++++++++++++++-------------
 models/models_test.go          |  3 +++
 models/repo.go                 |  4 +++-
 modules/base/conf.go           |  2 +-
 modules/mailer/mailer.go       |  2 +-
 routers/admin/admin.go         | 10 +++++++++
 templates/admin/config.tmpl    | 17 +++++++++++++++
 templates/admin/dashboard.tmpl |  9 +-------
 templates/admin/nav.tmpl       |  8 +++++++
 templates/admin/repos.tmpl     |  9 +-------
 templates/admin/users.tmpl     |  9 +-------
 web.go                         | 20 ++++++++++++++---
 13 files changed, 88 insertions(+), 45 deletions(-)
 create mode 100644 templates/admin/config.tmpl
 create mode 100644 templates/admin/nav.tmpl

diff --git a/README.md b/README.md
index 3668ae8998..e78ce8fe99 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,7 @@ There are some very good products in this category such as [gitlab](http://gitla
 - Repository viewer.
 - Gravatar support.
 - Mail service(register).
+- Administration panel.
 - Supports MySQL, PostgreSQL and SQLite3(binary release only).
 
 ## Installation
diff --git a/models/models.go b/models/models.go
index 8df230975f..bb0015d3de 100644
--- a/models/models.go
+++ b/models/models.go
@@ -16,30 +16,39 @@ import (
 	"github.com/gogits/gogs/modules/base"
 )
 
-var orm *xorm.Engine
+var (
+	orm *xorm.Engine
+
+	dbCfg struct {
+		Type, Host, Name, User, Pwd, Path, SslMode string
+	}
+)
+
+func LoadModelsConfig() {
+	dbCfg.Type = base.Cfg.MustValue("database", "DB_TYPE")
+	dbCfg.Host = base.Cfg.MustValue("database", "HOST")
+	dbCfg.Name = base.Cfg.MustValue("database", "NAME")
+	dbCfg.User = base.Cfg.MustValue("database", "USER")
+	dbCfg.Pwd = base.Cfg.MustValue("database", "PASSWD")
+	dbCfg.Path = base.Cfg.MustValue("database", "PATH", "data/gogs.db")
+	dbCfg.SslMode = base.Cfg.MustValue("database", "SSL_MODE")
+}
 
 func setEngine() {
-	dbType := base.Cfg.MustValue("database", "DB_TYPE")
-	dbHost := base.Cfg.MustValue("database", "HOST")
-	dbName := base.Cfg.MustValue("database", "NAME")
-	dbUser := base.Cfg.MustValue("database", "USER")
-	dbPwd := base.Cfg.MustValue("database", "PASSWD")
-	dbPath := base.Cfg.MustValue("database", "PATH", "data/gogs.db")
-	sslMode := base.Cfg.MustValue("database", "SSL_MODE")
 
 	var err error
-	switch dbType {
+	switch dbCfg.Type {
 	case "mysql":
 		orm, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@%s/%s?charset=utf8",
-			dbUser, dbPwd, dbHost, dbName))
+			dbCfg.User, dbCfg.Pwd, dbCfg.Host, dbCfg.Name))
 	case "postgres":
 		orm, err = xorm.NewEngine("postgres", fmt.Sprintf("user=%s password=%s dbname=%s sslmode=%s",
-			dbUser, dbPwd, dbName, sslMode))
+			dbCfg.User, dbCfg.Pwd, dbCfg.Name, dbCfg.SslMode))
 	case "sqlite3":
-		os.MkdirAll(path.Dir(dbPath), os.ModePerm)
-		orm, err = xorm.NewEngine("sqlite3", dbPath)
+		os.MkdirAll(path.Dir(dbCfg.Path), os.ModePerm)
+		orm, err = xorm.NewEngine("sqlite3", dbCfg.Path)
 	default:
-		fmt.Printf("Unknown database type: %s\n", dbType)
+		fmt.Printf("Unknown database type: %s\n", dbCfg.Type)
 		os.Exit(2)
 	}
 	if err != nil {
@@ -61,7 +70,7 @@ func setEngine() {
 	orm.ShowSQL = true
 }
 
-func init() {
+func NewEngine() {
 	setEngine()
 	if err := orm.Sync(new(User), new(PublicKey), new(Repository), new(Watch),
 		new(Action), new(Access)); err != nil {
diff --git a/models/models_test.go b/models/models_test.go
index c44ef476c6..d0f734d678 100644
--- a/models/models_test.go
+++ b/models/models_test.go
@@ -13,6 +13,9 @@ import (
 )
 
 func init() {
+	LoadModelsConfig()
+	NewEngine()
+
 	var err error
 	orm, err = xorm.NewEngine("sqlite3", "./test.db")
 	if err != nil {
diff --git a/models/repo.go b/models/repo.go
index 93f68ceddf..f252004785 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -41,10 +41,12 @@ var (
 	LanguageIgns, Licenses []string
 )
 
-func init() {
+func LoadRepoConfig() {
 	LanguageIgns = strings.Split(base.Cfg.MustValue("repository", "LANG_IGNS"), "|")
 	Licenses = strings.Split(base.Cfg.MustValue("repository", "LICENSES"), "|")
+}
 
+func NewRepoContext() {
 	zip.Verbose = false
 
 	// Check if server has basic git setting.
diff --git a/modules/base/conf.go b/modules/base/conf.go
index 41b66b69f8..42d50da4f3 100644
--- a/modules/base/conf.go
+++ b/modules/base/conf.go
@@ -148,7 +148,7 @@ func newRegisterMailService() {
 	log.Info("Register Mail Service Enabled")
 }
 
-func init() {
+func NewConfigContext() {
 	var err error
 	workDir, err := exeDir()
 	if err != nil {
diff --git a/modules/mailer/mailer.go b/modules/mailer/mailer.go
index 150607f8c4..da63e01d2a 100644
--- a/modules/mailer/mailer.go
+++ b/modules/mailer/mailer.go
@@ -40,7 +40,7 @@ func (m Message) Content() string {
 
 var mailQueue chan *Message
 
-func init() {
+func NewMailerContext() {
 	mailQueue = make(chan *Message, base.Cfg.MustInt("mailer", "SEND_BUFFER_LEN", 10))
 	go processMailQueue()
 }
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
index a37f1207c9..1095a599b9 100644
--- a/routers/admin/admin.go
+++ b/routers/admin/admin.go
@@ -11,12 +11,14 @@ import (
 
 func Dashboard(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Admin Dashboard"
+	ctx.Data["PageIsDashboard"] = true
 	ctx.Data["Stats"] = models.GetStatistic()
 	ctx.HTML(200, "admin/dashboard")
 }
 
 func Users(ctx *middleware.Context) {
 	ctx.Data["Title"] = "User Management"
+	ctx.Data["PageIsUsers"] = true
 
 	var err error
 	ctx.Data["Users"], err = models.GetUsers(100, 0)
@@ -29,6 +31,8 @@ func Users(ctx *middleware.Context) {
 
 func Repositories(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Repository Management"
+	ctx.Data["PageIsRepos"] = true
+
 	var err error
 	ctx.Data["Repos"], err = models.GetRepos(100, 0)
 	if err != nil {
@@ -37,3 +41,9 @@ func Repositories(ctx *middleware.Context) {
 	}
 	ctx.HTML(200, "admin/repos")
 }
+
+func Config(ctx *middleware.Context) {
+	ctx.Data["Title"] = "Server Configuration"
+	ctx.Data["PageIsConfig"] = true
+	ctx.HTML(200, "admin/config")
+}
diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl
new file mode 100644
index 0000000000..d209bcdfd9
--- /dev/null
+++ b/templates/admin/config.tmpl
@@ -0,0 +1,17 @@
+{{template "base/head" .}}
+{{template "base/navbar" .}}
+<div id="gogs-body" class="container" data-page="admin">
+    {{template "admin/nav" .}}
+    <div id="gogs-admin-container" class="col-md-9">
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                Server Configuration
+            </div>
+
+            <div class="panel-body">
+
+            </div>
+        </div>
+    </div>
+</div>
+{{template "base/footer" .}}
\ No newline at end of file
diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl
index 6a914b65f7..8950f50cac 100644
--- a/templates/admin/dashboard.tmpl
+++ b/templates/admin/dashboard.tmpl
@@ -1,14 +1,7 @@
 {{template "base/head" .}}
 {{template "base/navbar" .}}
 <div id="gogs-body" class="container" data-page="admin">
-    <div id="gogs-user-setting-nav" class="col-md-3">
-        <ul class="list-group" data-init="tabs">
-            <li class="list-group-item active"><a href="/admin"><i class="fa fa-tachometer fa-lg"></i> Dashboard</a></li>
-            <li class="list-group-item"><a href="/admin/users"><i class="fa fa-users fa-lg"></i> Users</a></li>
-            <li class="list-group-item"><a href="/admin/repos"><i class="fa fa-book fa-lg"></i> Repositories</a></li>
-        </ul>
-    </div>
-
+    {{template "admin/nav" .}}
     <div id="gogs-admin-container" class="col-md-9">
         <div class="panel panel-default">
             <div class="panel-heading">
diff --git a/templates/admin/nav.tmpl b/templates/admin/nav.tmpl
new file mode 100644
index 0000000000..bb704ee3fb
--- /dev/null
+++ b/templates/admin/nav.tmpl
@@ -0,0 +1,8 @@
+<div id="gogs-user-setting-nav" class="col-md-3">
+    <ul class="list-group" data-init="tabs">
+        <li class="list-group-item{{if .PageIsDashboard}} active{{end}}"><a href="/admin"><i class="fa fa-tachometer fa-lg"></i> Dashboard</a></li>
+        <li class="list-group-item{{if .PageIsUsers}} active{{end}}"><a href="/admin/users"><i class="fa fa-users fa-lg"></i> Users</a></li>
+        <li class="list-group-item{{if .PageIsRepos}} active{{end}}"><a href="/admin/repos"><i class="fa fa-book fa-lg"></i> Repositories</a></li>
+        <li class="list-group-item{{if .PageIsConfig}} active{{end}}"><a href="/admin/config"><i class="fa fa-cogs fa-lg"></i> Configuration</a></li>
+    </ul>
+</div>
\ No newline at end of file
diff --git a/templates/admin/repos.tmpl b/templates/admin/repos.tmpl
index f4834c9060..a1f41d8365 100644
--- a/templates/admin/repos.tmpl
+++ b/templates/admin/repos.tmpl
@@ -1,14 +1,7 @@
 {{template "base/head" .}}
 {{template "base/navbar" .}}
 <div id="gogs-body" class="container" data-page="admin">
-    <div id="gogs-user-setting-nav" class="col-md-3">
-        <ul class="list-group" data-init="tabs">
-            <li class="list-group-item"><a href="/admin"><i class="fa fa-tachometer fa-lg"></i> Dashboard</a></li>
-            <li class="list-group-item"><a href="/admin/users"><i class="fa fa-users fa-lg"></i> Users</a></li>
-            <li class="list-group-item active"><a href="/admin/repos"><i class="fa fa-book fa-lg"></i> Repositories</a></li>
-        </ul>
-    </div>
-
+    {{template "admin/nav" .}}
     <div id="gogs-admin-container" class="col-md-9">
         <div class="panel panel-default">
             <div class="panel-heading">
diff --git a/templates/admin/users.tmpl b/templates/admin/users.tmpl
index b690e1771e..ae2b5bbb65 100644
--- a/templates/admin/users.tmpl
+++ b/templates/admin/users.tmpl
@@ -1,14 +1,7 @@
 {{template "base/head" .}}
 {{template "base/navbar" .}}
 <div id="gogs-body" class="container" data-page="admin">
-    <div id="gogs-user-setting-nav" class="col-md-3">
-        <ul class="list-group" data-init="tabs">
-            <li class="list-group-item"><a href="/admin"><i class="fa fa-tachometer fa-lg"></i> Dashboard</a></li>
-            <li class="list-group-item active"><a href="/admin/users"><i class="fa fa-users fa-lg"></i> Users</a></li>
-            <li class="list-group-item"><a href="/admin/repos"><i class="fa fa-book fa-lg"></i> Repositories</a></li>
-        </ul>
-    </div>
-
+    {{template "admin/nav" .}}
     <div id="gogs-admin-container" class="col-md-9">
         <div class="panel panel-default">
             <div class="panel-heading">
diff --git a/web.go b/web.go
index a5a8305aee..648cb9d79c 100644
--- a/web.go
+++ b/web.go
@@ -16,9 +16,11 @@ import (
 
 	"github.com/gogits/binding"
 
+	"github.com/gogits/gogs/models"
 	"github.com/gogits/gogs/modules/auth"
 	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/log"
+	"github.com/gogits/gogs/modules/mailer"
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/routers"
 	"github.com/gogits/gogs/routers/admin"
@@ -36,6 +38,16 @@ gogs web`,
 	Flags:  []cli.Flag{},
 }
 
+// globalInit is for global configuration reload-able.
+func globalInit() {
+	base.NewConfigContext()
+	mailer.NewMailerContext()
+	models.LoadModelsConfig()
+	models.LoadRepoConfig()
+	models.NewRepoContext()
+	models.NewEngine()
+}
+
 // Check run mode(Default of martini is Dev).
 func checkRunMode() {
 	switch base.Cfg.MustValue("", "RUN_MODE") {
@@ -59,6 +71,7 @@ func newMartini() *martini.ClassicMartini {
 }
 
 func runWeb(*cli.Context) {
+	globalInit()
 	base.NewServices()
 	checkRunMode()
 	log.Info("%s %s", base.AppName, base.AppVer)
@@ -101,9 +114,10 @@ func runWeb(*cli.Context) {
 	m.Get("/help", routers.Help)
 
 	adminReq := middleware.AdminRequire()
-	m.Any("/admin", reqSignIn, adminReq, admin.Dashboard)
-	m.Any("/admin/users", reqSignIn, adminReq, admin.Users)
-	m.Any("/admin/repos", reqSignIn, adminReq, admin.Repositories)
+	m.Get("/admin", reqSignIn, adminReq, admin.Dashboard)
+	m.Get("/admin/users", reqSignIn, adminReq, admin.Users)
+	m.Get("/admin/repos", reqSignIn, adminReq, admin.Repositories)
+	m.Get("/admin/config", reqSignIn, adminReq, admin.Config)
 
 	m.Post("/:username/:reponame/settings", reqSignIn, middleware.RepoAssignment(true), repo.SettingPost)
 	m.Get("/:username/:reponame/settings", reqSignIn, middleware.RepoAssignment(true), repo.Setting)

From 5373a3093eaf9bc9ced7a6b3335ccf1b17fd343e Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 21 Mar 2014 01:59:15 -0400
Subject: [PATCH 27/41] config option: Require sign in to view repository

---
 conf/app.ini               | 2 ++
 modules/base/conf.go       | 2 ++
 modules/middleware/auth.go | 2 +-
 web.go                     | 3 ++-
 4 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/conf/app.ini b/conf/app.ini
index d38cd1f05e..d4fdc0dcf7 100644
--- a/conf/app.ini
+++ b/conf/app.ini
@@ -42,6 +42,8 @@ RESET_PASSWD_CODE_LIVE_MINUTES = 180
 REGISTER_EMAIL_CONFIRM = false
 ; Does not allow register and admin create account only
 DISENABLE_REGISTERATION = false
+; User must sign in to view anything.
+REQUIRE_SIGNIN_VIEW = false
 
 [mailer]
 ENABLED = false
diff --git a/modules/base/conf.go b/modules/base/conf.go
index 42d50da4f3..3050b915fa 100644
--- a/modules/base/conf.go
+++ b/modules/base/conf.go
@@ -41,6 +41,7 @@ var (
 var Service struct {
 	RegisterEmailConfirm   bool
 	DisenableRegisteration bool
+	RequireSignInView      bool
 	ActiveCodeLives        int
 	ResetPwdCodeLives      int
 }
@@ -70,6 +71,7 @@ func newService() {
 	Service.ActiveCodeLives = Cfg.MustInt("service", "ACTIVE_CODE_LIVE_MINUTES", 180)
 	Service.ResetPwdCodeLives = Cfg.MustInt("service", "RESET_PASSWD_CODE_LIVE_MINUTES", 180)
 	Service.DisenableRegisteration = Cfg.MustBool("service", "DISENABLE_REGISTERATION", false)
+	Service.RequireSignInView = Cfg.MustBool("service", "REQUIRE_SIGNIN_VIEW", false)
 }
 
 func newLogService() {
diff --git a/modules/middleware/auth.go b/modules/middleware/auth.go
index 44033abb8f..f211de32b9 100644
--- a/modules/middleware/auth.go
+++ b/modules/middleware/auth.go
@@ -15,7 +15,7 @@ func SignInRequire(redirect bool) martini.Handler {
 	return func(ctx *Context) {
 		if !ctx.IsSigned {
 			if redirect {
-				ctx.Redirect("/")
+				ctx.Redirect("/user/login")
 			}
 			return
 		} else if !ctx.User.IsActive && base.Service.RegisterEmailConfirm {
diff --git a/web.go b/web.go
index 648cb9d79c..6fe838aa78 100644
--- a/web.go
+++ b/web.go
@@ -87,7 +87,8 @@ func runWeb(*cli.Context) {
 
 	m.Use(middleware.InitContext())
 
-	reqSignIn, ignSignIn := middleware.SignInRequire(true), middleware.SignInRequire(false)
+	reqSignIn := middleware.SignInRequire(true)
+	ignSignIn := middleware.SignInRequire(base.Service.RequireSignInView)
 	reqSignOut := middleware.SignOutRequire()
 	// Routers.
 	m.Get("/", ignSignIn, routers.Home)

From c1576b4c400376f22ec25012a6ca66e9c5539ee4 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 21 Mar 2014 03:27:59 -0400
Subject: [PATCH 28/41] Add admin add user

---
 models/models.go               | 28 +++++++--------
 models/repo.go                 |  2 +-
 modules/base/conf.go           |  2 ++
 routers/admin/admin.go         | 18 ++++++++++
 routers/admin/user.go          | 63 ++++++++++++++++++++++++++++++++++
 templates/admin/config.tmpl    | 50 +++++++++++++++++++++++++++
 templates/admin/users.tmpl     |  1 +
 templates/admin/users/new.tmpl | 54 +++++++++++++++++++++++++++++
 web.go                         |  1 +
 9 files changed, 204 insertions(+), 15 deletions(-)
 create mode 100644 routers/admin/user.go
 create mode 100644 templates/admin/users/new.tmpl

diff --git a/models/models.go b/models/models.go
index bb0015d3de..a4550d7243 100644
--- a/models/models.go
+++ b/models/models.go
@@ -19,36 +19,36 @@ import (
 var (
 	orm *xorm.Engine
 
-	dbCfg struct {
+	DbCfg struct {
 		Type, Host, Name, User, Pwd, Path, SslMode string
 	}
 )
 
 func LoadModelsConfig() {
-	dbCfg.Type = base.Cfg.MustValue("database", "DB_TYPE")
-	dbCfg.Host = base.Cfg.MustValue("database", "HOST")
-	dbCfg.Name = base.Cfg.MustValue("database", "NAME")
-	dbCfg.User = base.Cfg.MustValue("database", "USER")
-	dbCfg.Pwd = base.Cfg.MustValue("database", "PASSWD")
-	dbCfg.Path = base.Cfg.MustValue("database", "PATH", "data/gogs.db")
-	dbCfg.SslMode = base.Cfg.MustValue("database", "SSL_MODE")
+	DbCfg.Type = base.Cfg.MustValue("database", "DB_TYPE")
+	DbCfg.Host = base.Cfg.MustValue("database", "HOST")
+	DbCfg.Name = base.Cfg.MustValue("database", "NAME")
+	DbCfg.User = base.Cfg.MustValue("database", "USER")
+	DbCfg.Pwd = base.Cfg.MustValue("database", "PASSWD")
+	DbCfg.SslMode = base.Cfg.MustValue("database", "SSL_MODE")
+	DbCfg.Path = base.Cfg.MustValue("database", "PATH", "data/gogs.db")
 }
 
 func setEngine() {
 
 	var err error
-	switch dbCfg.Type {
+	switch DbCfg.Type {
 	case "mysql":
 		orm, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@%s/%s?charset=utf8",
-			dbCfg.User, dbCfg.Pwd, dbCfg.Host, dbCfg.Name))
+			DbCfg.User, DbCfg.Pwd, DbCfg.Host, DbCfg.Name))
 	case "postgres":
 		orm, err = xorm.NewEngine("postgres", fmt.Sprintf("user=%s password=%s dbname=%s sslmode=%s",
-			dbCfg.User, dbCfg.Pwd, dbCfg.Name, dbCfg.SslMode))
+			DbCfg.User, DbCfg.Pwd, DbCfg.Name, DbCfg.SslMode))
 	case "sqlite3":
-		os.MkdirAll(path.Dir(dbCfg.Path), os.ModePerm)
-		orm, err = xorm.NewEngine("sqlite3", dbCfg.Path)
+		os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm)
+		orm, err = xorm.NewEngine("sqlite3", DbCfg.Path)
 	default:
-		fmt.Printf("Unknown database type: %s\n", dbCfg.Type)
+		fmt.Printf("Unknown database type: %s\n", DbCfg.Type)
 		os.Exit(2)
 	}
 	if err != nil {
diff --git a/models/repo.go b/models/repo.go
index f252004785..918e5dc84c 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -107,7 +107,7 @@ func IsRepositoryExist(user *User, repoName string) (bool, error) {
 
 var (
 	// Define as all lower case!!
-	illegalPatterns = []string{"[.][Gg][Ii][Tt]", "user", "help", "stars", "issues", "pulls", "commits", "admin", "repo", "template"}
+	illegalPatterns = []string{"[.][Gg][Ii][Tt]", "user", "help", "stars", "issues", "pulls", "commits", "admin", "repo", "template", "admin"}
 )
 
 // IsLegalName returns false if name contains illegal characters.
diff --git a/modules/base/conf.go b/modules/base/conf.go
index 3050b915fa..bf054ec3c5 100644
--- a/modules/base/conf.go
+++ b/modules/base/conf.go
@@ -32,6 +32,7 @@ var (
 	AppUrl       string
 	Domain       string
 	SecretKey    string
+	RunUser      string
 	RepoRootPath string
 
 	Cfg         *goconfig.ConfigFile
@@ -179,6 +180,7 @@ func NewConfigContext() {
 	AppUrl = Cfg.MustValue("server", "ROOT_URL")
 	Domain = Cfg.MustValue("server", "DOMAIN")
 	SecretKey = Cfg.MustValue("security", "SECRET_KEY")
+	RunUser = Cfg.MustValue("", "RUN_USER")
 
 	// Determine and create root git reposiroty path.
 	RepoRootPath = Cfg.MustValue("repository", "ROOT")
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
index 1095a599b9..547883f7bc 100644
--- a/routers/admin/admin.go
+++ b/routers/admin/admin.go
@@ -5,7 +5,12 @@
 package admin
 
 import (
+	"strings"
+
+	"github.com/codegangsta/martini"
+
 	"github.com/gogits/gogs/models"
+	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/middleware"
 )
 
@@ -45,5 +50,18 @@ func Repositories(ctx *middleware.Context) {
 func Config(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Server Configuration"
 	ctx.Data["PageIsConfig"] = true
+
+	ctx.Data["AppUrl"] = base.AppUrl
+	ctx.Data["Domain"] = base.Domain
+	ctx.Data["RunUser"] = base.RunUser
+	ctx.Data["RunMode"] = strings.Title(martini.Env)
+	ctx.Data["RepoRootPath"] = base.RepoRootPath
+
+	ctx.Data["Service"] = base.Service
+
+	ctx.Data["DbCfg"] = models.DbCfg
+
+	ctx.Data["Mailer"] = base.MailService
+
 	ctx.HTML(200, "admin/config")
 }
diff --git a/routers/admin/user.go b/routers/admin/user.go
new file mode 100644
index 0000000000..9dcc1499e3
--- /dev/null
+++ b/routers/admin/user.go
@@ -0,0 +1,63 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package admin
+
+import (
+	"strings"
+
+	"github.com/gogits/gogs/models"
+	"github.com/gogits/gogs/modules/auth"
+	"github.com/gogits/gogs/modules/log"
+	"github.com/gogits/gogs/modules/middleware"
+)
+
+func NewUser(ctx *middleware.Context, form auth.RegisterForm) {
+	ctx.Data["Title"] = "New Account"
+
+	if ctx.Req.Method == "GET" {
+		ctx.HTML(200, "admin/users/new")
+		return
+	}
+
+	if form.Password != form.RetypePasswd {
+		ctx.Data["HasError"] = true
+		ctx.Data["Err_Password"] = true
+		ctx.Data["Err_RetypePasswd"] = true
+		ctx.Data["ErrorMsg"] = "Password and re-type password are not same"
+		auth.AssignForm(form, ctx.Data)
+	}
+
+	if ctx.HasError() {
+		ctx.HTML(200, "admin/users/new")
+		return
+	}
+
+	u := &models.User{
+		Name:     form.UserName,
+		Email:    form.Email,
+		Passwd:   form.Password,
+		IsActive: true,
+	}
+
+	var err error
+	if u, err = models.RegisterUser(u); err != nil {
+		switch err {
+		case models.ErrUserAlreadyExist:
+			ctx.RenderWithErr("Username has been already taken", "admin/users/new", &form)
+		case models.ErrEmailAlreadyUsed:
+			ctx.RenderWithErr("E-mail address has been already used", "admin/users/new", &form)
+		case models.ErrUserNameIllegal:
+			ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "admin/users/new", &form)
+		default:
+			ctx.Handle(200, "admin.user.NewUser", err)
+		}
+		return
+	}
+
+	log.Trace("%s User created by admin(%s): %s", ctx.Req.RequestURI,
+		ctx.User.LowerName, strings.ToLower(form.UserName))
+
+	ctx.Redirect("/admin/users")
+}
diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl
index d209bcdfd9..9593a545f8 100644
--- a/templates/admin/config.tmpl
+++ b/templates/admin/config.tmpl
@@ -9,7 +9,57 @@
             </div>
 
             <div class="panel-body">
+                <div><b>Application Name:</b> {{AppName}}</div>
+                <div><b>Application Version:</b> {{AppVer}}</div>
+                <div><b>Application URL:</b> {{.AppUrl}}</div>
+                <div><b>Domain:</b> {{.Domain}}</div>
+                <hr/>
+                <div><b>Run User:</b> {{.RunUser}}</div>
+                <div><b>Run Mode:</b> {{.RunMode}}</div>
+                <hr/>
+                <div><b>Repository Root Path:</b> {{.RepoRootPath}}</div>
+            </div>
+        </div>
 
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                Database Configuration
+            </div>
+
+            <div class="panel-body">
+                <div><b>Type:</b> {{.DbCfg.Type}}</div>
+                <div><b>Host:</b> {{.DbCfg.Host}}</div>
+                <div><b>Name:</b> {{.DbCfg.Name}}</div>
+                <div><b>User:</b> {{.DbCfg.User}}</div>
+                <div><b>SslMode:</b> {{.DbCfg.SslMode}} (for "postgres" only)</div>
+                <div><b>Path:</b> {{.DbCfg.Path}} (for "sqlite3" only)</div>
+            </div>
+        </div>
+
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                Service Configuration
+            </div>
+
+            <div class="panel-body">
+                <div><b>Register Email Confirmation:</b> <i class="fa fa{{if .Service.RegisterEmailConfirm}}-check{{end}}-square-o"></i></div>
+                <div><b>Disenable Registeration:</b> <i class="fa fa{{if .Service.DisenableRegisteration}}-check{{end}}-square-o"></i></div>
+                <div><b>Require Sign In View:</b> <i class="fa fa{{if .Service.RequireSignInView}}-check{{end}}-square-o"></i></div>
+                <hr/>
+                <div><b>Active Code Lives:</b> {{.Service.ActiveCodeLives}} minutes</div>
+                <div><b>Reset Password Code Lives:</b> {{.Service.ResetPwdCodeLives}} minutes</div>
+            </div>
+        </div>
+
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                Mailer Configuration
+            </div>
+
+            <div class="panel-body">
+                <div><b>Name:</b> {{.Mailer.Name}}</div>
+                <div><b>Host:</b> {{.Mailer.Host}}</div>
+                <div><b>User:</b> {{.Mailer.User}}</div>
             </div>
         </div>
     </div>
diff --git a/templates/admin/users.tmpl b/templates/admin/users.tmpl
index ae2b5bbb65..d82f04b812 100644
--- a/templates/admin/users.tmpl
+++ b/templates/admin/users.tmpl
@@ -9,6 +9,7 @@
             </div>
 
             <div class="panel-body">
+                <a href="/admin/users/new" class="btn btn-primary">New Account</a>
                 <table class="table table-striped">
                     <thead>
                         <tr>
diff --git a/templates/admin/users/new.tmpl b/templates/admin/users/new.tmpl
new file mode 100644
index 0000000000..bf59b16a80
--- /dev/null
+++ b/templates/admin/users/new.tmpl
@@ -0,0 +1,54 @@
+{{template "base/head" .}}
+{{template "base/navbar" .}}
+<div id="gogs-body" class="container" data-page="admin">
+    {{template "admin/nav" .}}
+    <div id="gogs-admin-container" class="col-md-9">
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                New Account
+            </div>
+
+            <div class="panel-body">
+            	<br/>
+				<form action="/admin/users/new" method="post" class="form-horizontal">
+				    <div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div>
+					<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}">
+						<label class="col-md-4 control-label">Username: </label>
+						<div class="col-md-6">
+							<input name="username" class="form-control" placeholder="Type account's username" value="{{.username}}" required="required">
+						</div>
+					</div>
+
+					<div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}">
+						<label class="col-md-4 control-label">Email: </label>
+						<div class="col-md-6">
+							<input name="email" class="form-control" placeholder="Type account's e-mail address" value="{{.email}}" required="required" title="Email is not valid">
+						</div>
+					</div>
+
+					<div class="form-group {{if .Err_Password}}has-error has-feedback{{end}}">
+						<label class="col-md-4 control-label">Password: </label>
+						<div class="col-md-6">
+							<input name="passwd" type="password" class="form-control" placeholder="Type account's password" required="required" title="Password must contain at least 6 characters">
+						</div>
+					</div>
+
+					<div class="form-group {{if .Err_RetypePasswd}}has-error has-feedback{{end}}">
+						<label class="col-md-4 control-label">Re-type: </label>
+						<div class="col-md-6">
+							<input name="retypepasswd" type="password" class="form-control" placeholder="Re-type account's password" required="required" title="Re-type Password must be same to Password">
+						</div>
+					</div>
+
+					<div class="form-group">
+					    <div class="col-md-offset-4 col-md-6">
+					    	<button type="submit" class="btn btn-lg btn-primary">Create new account</button>
+					    </div>
+					</div>
+				</form>
+            </div>
+        </div>
+
+	</div>
+</div>
+{{template "base/footer" .}}
\ No newline at end of file
diff --git a/web.go b/web.go
index 6fe838aa78..d6d78afa5d 100644
--- a/web.go
+++ b/web.go
@@ -117,6 +117,7 @@ func runWeb(*cli.Context) {
 	adminReq := middleware.AdminRequire()
 	m.Get("/admin", reqSignIn, adminReq, admin.Dashboard)
 	m.Get("/admin/users", reqSignIn, adminReq, admin.Users)
+	m.Any("/admin/users/new", reqSignIn, adminReq, binding.BindIgnErr(auth.RegisterForm{}), admin.NewUser)
 	m.Get("/admin/repos", reqSignIn, adminReq, admin.Repositories)
 	m.Get("/admin/config", reqSignIn, adminReq, admin.Config)
 

From c2816afe9c60922b3468cece689c84e52e0ba11c Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 21 Mar 2014 03:36:26 -0400
Subject: [PATCH 29/41] Bug fix

---
 serve.go | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/serve.go b/serve.go
index 2a17a33490..3ce8f9046c 100644
--- a/serve.go
+++ b/serve.go
@@ -45,6 +45,10 @@ func In(b string, sl map[string]int) bool {
 }
 
 func runServ(*cli.Context) {
+	base.NewConfigContext()
+	models.LoadModelsConfig()
+	models.NewEngine()
+
 	keys := strings.Split(os.Args[2], "-")
 	if len(keys) != 2 {
 		fmt.Println("auth file format error")

From e67653cf13857f671de9bf6279453f99cdd60d11 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 21 Mar 2014 04:13:32 -0400
Subject: [PATCH 30/41] Bug fix

---
 CONTRIBUTING.md                | 49 ++++++++++++++++++++++++++++++++++
 routers/admin/admin.go         |  6 ++++-
 templates/admin/config.tmpl    |  1 +
 templates/admin/dashboard.tmpl |  9 +++++++
 templates/repo/nav.tmpl        |  6 ++---
 5 files changed, 67 insertions(+), 4 deletions(-)
 create mode 100644 CONTRIBUTING.md

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000000..08013d3705
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,49 @@
+# Contributing to Gogs
+
+Want to hack on Gogs? Awesome! Here are instructions to get you
+started. They are probably not perfect, please let us know if anything
+feels wrong or incomplete.
+
+## Contribution guidelines
+
+### Pull requests are always welcome
+
+We are always thrilled to receive pull requests, and do our best to
+process them as fast as possible. Not sure if that typo is worth a pull
+request? Do it! We will appreciate it.
+
+If your pull request is not accepted on the first try, don't be
+discouraged! If there's a problem with the implementation, hopefully you
+received feedback on what to improve.
+
+We're trying very hard to keep Gogs lean and focused. We don't want it
+to do everything for everybody. This means that we might decide against
+incorporating a new feature.
+
+### Discuss your design on the mailing list
+
+We recommend discussing your plans [on the mailing
+list](https://groups.google.com/forum/#!forum/gogits)
+before starting to code - especially for more ambitious contributions.
+This gives other contributors a chance to point you in the right
+direction, give feedback on your design, and maybe point out if someone
+else is working on the same thing.
+
+We may close your pull request if not first discussed on the mailing
+list. We aren't doing this to be jerks. We are doing this to prevent
+people from spending large amounts of time on changes that may need
+to be designed or architected in a specific way, or may not align with
+the vision of the project.
+
+### Create issues...
+
+Any significant improvement should be documented as [a GitHub
+issue](https://github.com/gogits/gogs/issues) before anybody
+starts working on it.
+
+### ...but check for existing issues first!
+
+Please take a moment to check that an issue doesn't already exist
+documenting your bug report or improvement proposal. If it does, it
+never hurts to add a quick "+1" or "I have this problem too". This will
+help prioritize the most common problems and requests.
\ No newline at end of file
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
index 547883f7bc..6d3831a9f3 100644
--- a/routers/admin/admin.go
+++ b/routers/admin/admin.go
@@ -61,7 +61,11 @@ func Config(ctx *middleware.Context) {
 
 	ctx.Data["DbCfg"] = models.DbCfg
 
-	ctx.Data["Mailer"] = base.MailService
+	ctx.Data["MailerEnabled"] = false
+	if base.MailService != nil {
+		ctx.Data["MailerEnabled"] = true
+		ctx.Data["Mailer"] = base.MailService
+	}
 
 	ctx.HTML(200, "admin/config")
 }
diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl
index 9593a545f8..7013c201ae 100644
--- a/templates/admin/config.tmpl
+++ b/templates/admin/config.tmpl
@@ -57,6 +57,7 @@
             </div>
 
             <div class="panel-body">
+                <div><b>Enabled:</b> <i class="fa fa{{if .MailerEnabled}}-check{{end}}-square-o"></i></div>
                 <div><b>Name:</b> {{.Mailer.Name}}</div>
                 <div><b>Host:</b> {{.Mailer.Host}}</div>
                 <div><b>User:</b> {{.Mailer.User}}</div>
diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl
index 8950f50cac..6088487d62 100644
--- a/templates/admin/dashboard.tmpl
+++ b/templates/admin/dashboard.tmpl
@@ -12,6 +12,15 @@
                 Gogs database has <b>{{.Stats.Counter.User}}</b> users, <b>{{.Stats.Counter.PublicKey}}</b> SSH keys, <b>{{.Stats.Counter.Repo}}</b> repositories, <b>{{.Stats.Counter.Watch}}</b> watches, <b>{{.Stats.Counter.Action}}</b> actions, and <b>{{.Stats.Counter.Access}}</b> accesses.
             </div>
         </div>
+
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                System Status
+            </div>
+
+            <div class="panel-body">
+            </div>
+        </div>
     </div>
 </div>
 {{template "base/footer" .}}
\ No newline at end of file
diff --git a/templates/repo/nav.tmpl b/templates/repo/nav.tmpl
index 718c429a2b..c61051af25 100644
--- a/templates/repo/nav.tmpl
+++ b/templates/repo/nav.tmpl
@@ -5,8 +5,8 @@
                 <h3 class="name"><i class="fa fa-book fa-lg"></i><a href="{{.Owner.HomeLink}}">{{.Owner.Name}}</a> / {{.Repository.Name}}</h3>
                 <p class="desc">{{.Repository.Description}}{{if .Repository.Website}}<a href="{{.Repository.Website}}">{{.Repository.Website}}</a>{{end}}</p>
             </div>
-            {{if not .IsBareRepo}}
             <div class="col-md-6 actions text-right">
+                {{if not .IsBareRepo}}
                 <div class="btn-group" id="gogs-repo-clone">
                     <button type="button" class="btn btn-default"><i class="fa fa-download fa-lg fa-m"></i></button>
                     <button type="button" class="btn btn-default dropdown-toggle" data-container="body" data-toggle="popover" data-placement="bottom" data-content="<label>SSH:</label><div class='input-group'><input type='text' class='form-control' value='{{.CloneLink.SSH}}'></div>" data-html="1">
@@ -38,11 +38,11 @@
                 <div class="btn-group">
                     <button type="button" class="btn btn-default"><i class="fa fa-star"></i>Star&nbsp;&nbsp;{{.Repository.NumStars}}</button>
                 </div>
+                {{end}}
                 <div class="btn-group">
-                    <button type="button" class="btn btn-default"><i class="fa fa-code-fork"></i>Fork&nbsp;&nbsp;{{.Repository.NumForks}}</button>
+                    <a type="button" {{if not .IsRepositoryOwner}}href="/{{.Username}}/{{.Reponame}}/fork"{{end}} class="btn btn-default"><i class="fa fa-code-fork"></i>Fork&nbsp;&nbsp;{{.Repository.NumForks}}</a>
                 </div>
             </div>
-            {{end}}
         </div>
     </div>
 </div>
\ No newline at end of file

From 30618b271aab40d29a6d34cb4e06c8d28fa74d18 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 21 Mar 2014 06:15:58 -0400
Subject: [PATCH 31/41] Add admin edit user

---
 conf/app.ini                      |   4 +-
 conf/gitignore/C++                |  13 ++
 conf/license/Artistic License 2.0 | 201 ++++++++++++++++++++++++++++++
 modules/auth/admin.go             |  55 ++++++++
 modules/auth/user.go              |   2 +-
 routers/admin/user.go             |  44 +++++++
 routers/user/setting.go           |   1 +
 templates/admin/users.tmpl        |   2 +
 templates/admin/users/edit.tmpl   |  83 ++++++++++++
 templates/admin/users/new.tmpl    |  20 +--
 templates/user/setting.tmpl       |   6 +-
 web.go                            |   1 +
 12 files changed, 416 insertions(+), 16 deletions(-)
 create mode 100644 conf/gitignore/C++
 create mode 100644 conf/license/Artistic License 2.0
 create mode 100644 modules/auth/admin.go
 create mode 100644 templates/admin/users/edit.tmpl

diff --git a/conf/app.ini b/conf/app.ini
index d4fdc0dcf7..985903a8e5 100644
--- a/conf/app.ini
+++ b/conf/app.ini
@@ -8,8 +8,8 @@ RUN_MODE = dev
 
 [repository]
 ROOT = /Users/%(RUN_USER)s/git/gogs-repositories
-LANG_IGNS = Google Go|C|Python|Ruby|C Sharp
-LICENSES = Apache v2 License|GPL v2|MIT License|Affero GPL|BSD (3-Clause) License
+LANG_IGNS = Google Go|C|C++|Python|Ruby|C Sharp
+LICENSES = Apache v2 License|GPL v2|MIT License|Affero GPL|Artistic License 2.0|BSD (3-Clause) License
 
 [server]
 DOMAIN = localhost
diff --git a/conf/gitignore/C++ b/conf/gitignore/C++
new file mode 100644
index 0000000000..5a1b6ec431
--- /dev/null
+++ b/conf/gitignore/C++
@@ -0,0 +1,13 @@
+# Compiled Object files
+*.slo
+*.lo
+*.o
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
\ No newline at end of file
diff --git a/conf/license/Artistic License 2.0 b/conf/license/Artistic License 2.0
new file mode 100644
index 0000000000..b7c38097e6
--- /dev/null
+++ b/conf/license/Artistic License 2.0	
@@ -0,0 +1,201 @@
+The Artistic License 2.0
+
+           Copyright (c) 2014
+
+     Everyone is permitted to copy and distribute verbatim copies
+      of this license document, but changing it is not allowed.
+
+Preamble
+
+This license establishes the terms under which a given free software
+Package may be copied, modified, distributed, and/or redistributed.
+The intent is that the Copyright Holder maintains some artistic
+control over the development of that Package while still keeping the
+Package available as open source and free software.
+
+You are always permitted to make arrangements wholly outside of this
+license directly with the Copyright Holder of a given Package.  If the
+terms of this license do not permit the full use that you propose to
+make of the Package, you should contact the Copyright Holder and seek
+a different licensing arrangement.
+
+Definitions
+
+    "Copyright Holder" means the individual(s) or organization(s)
+    named in the copyright notice for the entire Package.
+
+    "Contributor" means any party that has contributed code or other
+    material to the Package, in accordance with the Copyright Holder's
+    procedures.
+
+    "You" and "your" means any person who would like to copy,
+    distribute, or modify the Package.
+
+    "Package" means the collection of files distributed by the
+    Copyright Holder, and derivatives of that collection and/or of
+    those files. A given Package may consist of either the Standard
+    Version, or a Modified Version.
+
+    "Distribute" means providing a copy of the Package or making it
+    accessible to anyone else, or in the case of a company or
+    organization, to others outside of your company or organization.
+
+    "Distributor Fee" means any fee that you charge for Distributing
+    this Package or providing support for this Package to another
+    party.  It does not mean licensing fees.
+
+    "Standard Version" refers to the Package if it has not been
+    modified, or has been modified only in ways explicitly requested
+    by the Copyright Holder.
+
+    "Modified Version" means the Package, if it has been changed, and
+    such changes were not explicitly requested by the Copyright
+    Holder.
+
+    "Original License" means this Artistic License as Distributed with
+    the Standard Version of the Package, in its current version or as
+    it may be modified by The Perl Foundation in the future.
+
+    "Source" form means the source code, documentation source, and
+    configuration files for the Package.
+
+    "Compiled" form means the compiled bytecode, object code, binary,
+    or any other form resulting from mechanical transformation or
+    translation of the Source form.
+
+
+Permission for Use and Modification Without Distribution
+
+(1)  You are permitted to use the Standard Version and create and use
+Modified Versions for any purpose without restriction, provided that
+you do not Distribute the Modified Version.
+
+
+Permissions for Redistribution of the Standard Version
+
+(2)  You may Distribute verbatim copies of the Source form of the
+Standard Version of this Package in any medium without restriction,
+either gratis or for a Distributor Fee, provided that you duplicate
+all of the original copyright notices and associated disclaimers.  At
+your discretion, such verbatim copies may or may not include a
+Compiled form of the Package.
+
+(3)  You may apply any bug fixes, portability changes, and other
+modifications made available from the Copyright Holder.  The resulting
+Package will still be considered the Standard Version, and as such
+will be subject to the Original License.
+
+
+Distribution of Modified Versions of the Package as Source
+
+(4)  You may Distribute your Modified Version as Source (either gratis
+or for a Distributor Fee, and with or without a Compiled form of the
+Modified Version) provided that you clearly document how it differs
+from the Standard Version, including, but not limited to, documenting
+any non-standard features, executables, or modules, and provided that
+you do at least ONE of the following:
+
+    (a)  make the Modified Version available to the Copyright Holder
+    of the Standard Version, under the Original License, so that the
+    Copyright Holder may include your modifications in the Standard
+    Version.
+
+    (b)  ensure that installation of your Modified Version does not
+    prevent the user installing or running the Standard Version. In
+    addition, the Modified Version must bear a name that is different
+    from the name of the Standard Version.
+
+    (c)  allow anyone who receives a copy of the Modified Version to
+    make the Source form of the Modified Version available to others
+    under
+
+    (i)  the Original License or
+
+    (ii)  a license that permits the licensee to freely copy,
+    modify and redistribute the Modified Version using the same
+    licensing terms that apply to the copy that the licensee
+    received, and requires that the Source form of the Modified
+    Version, and of any works derived from it, be made freely
+    available in that license fees are prohibited but Distributor
+    Fees are allowed.
+
+
+Distribution of Compiled Forms of the Standard Version
+or Modified Versions without the Source
+
+(5)  You may Distribute Compiled forms of the Standard Version without
+the Source, provided that you include complete instructions on how to
+get the Source of the Standard Version.  Such instructions must be
+valid at the time of your distribution.  If these instructions, at any
+time while you are carrying out such distribution, become invalid, you
+must provide new instructions on demand or cease further distribution.
+If you provide valid instructions or cease distribution within thirty
+days after you become aware that the instructions are invalid, then
+you do not forfeit any of your rights under this license.
+
+(6)  You may Distribute a Modified Version in Compiled form without
+the Source, provided that you comply with Section 4 with respect to
+the Source of the Modified Version.
+
+
+Aggregating or Linking the Package
+
+(7)  You may aggregate the Package (either the Standard Version or
+Modified Version) with other packages and Distribute the resulting
+aggregation provided that you do not charge a licensing fee for the
+Package.  Distributor Fees are permitted, and licensing fees for other
+components in the aggregation are permitted. The terms of this license
+apply to the use and Distribution of the Standard or Modified Versions
+as included in the aggregation.
+
+(8) You are permitted to link Modified and Standard Versions with
+other works, to embed the Package in a larger work of your own, or to
+build stand-alone binary or bytecode versions of applications that
+include the Package, and Distribute the result without restriction,
+provided the result does not expose a direct interface to the Package.
+
+
+Items That are Not Considered Part of a Modified Version
+
+(9) Works (including, but not limited to, modules and scripts) that
+merely extend or make use of the Package, do not, by themselves, cause
+the Package to be a Modified Version.  In addition, such works are not
+considered parts of the Package itself, and are not subject to the
+terms of this license.
+
+
+General Provisions
+
+(10)  Any use, modification, and distribution of the Standard or
+Modified Versions is governed by this Artistic License. By using,
+modifying or distributing the Package, you accept this license. Do not
+use, modify, or distribute the Package, if you do not accept this
+license.
+
+(11)  If your Modified Version has been derived from a Modified
+Version made by someone other than you, you are nevertheless required
+to ensure that your Modified Version complies with the requirements of
+this license.
+
+(12)  This license does not grant you the right to use any trademark,
+service mark, tradename, or logo of the Copyright Holder.
+
+(13)  This license includes the non-exclusive, worldwide,
+free-of-charge patent license to make, have made, use, offer to sell,
+sell, import and otherwise transfer the Package with respect to any
+patent claims licensable by the Copyright Holder that are necessarily
+infringed by the Package. If you institute patent litigation
+(including a cross-claim or counterclaim) against any party alleging
+that the Package constitutes direct or contributory patent
+infringement, then this Artistic License to you shall terminate on the
+date that such litigation is filed.
+
+(14)  Disclaimer of Warranty:
+THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
+IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL
+LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/modules/auth/admin.go b/modules/auth/admin.go
new file mode 100644
index 0000000000..eccab00718
--- /dev/null
+++ b/modules/auth/admin.go
@@ -0,0 +1,55 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package auth
+
+import (
+	"net/http"
+	"reflect"
+
+	"github.com/codegangsta/martini"
+
+	"github.com/gogits/binding"
+
+	"github.com/gogits/gogs/modules/base"
+	"github.com/gogits/gogs/modules/log"
+)
+
+type AdminEditUserForm struct {
+	Email    string `form:"email" binding:"Required;Email;MaxSize(50)"`
+	Website  string `form:"website" binding:"MaxSize(50)"`
+	Location string `form:"location" binding:"MaxSize(50)"`
+	Avatar   string `form:"avatar" binding:"Required;Email;MaxSize(50)"`
+	Active   string `form:"active"`
+	Admin    string `form:"admin"`
+}
+
+func (f *AdminEditUserForm) Name(field string) string {
+	names := map[string]string{
+		"Email":    "E-mail address",
+		"Website":  "Website",
+		"Location": "Location",
+		"Avatar":   "Gravatar Email",
+	}
+	return names[field]
+}
+
+func (f *AdminEditUserForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) {
+	if req.Method == "GET" || errors.Count() == 0 {
+		return
+	}
+
+	data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData)
+	data["HasError"] = true
+	AssignForm(f, data)
+
+	if len(errors.Overall) > 0 {
+		for _, err := range errors.Overall {
+			log.Error("AdminEditUserForm.Validate: %v", err)
+		}
+		return
+	}
+
+	validate(errors, data, f)
+}
diff --git a/modules/auth/user.go b/modules/auth/user.go
index 491ec65aca..f8d8f66149 100644
--- a/modules/auth/user.go
+++ b/modules/auth/user.go
@@ -79,7 +79,7 @@ type UpdateProfileForm struct {
 
 func (f *UpdateProfileForm) Name(field string) string {
 	names := map[string]string{
-		"Email":    "Email address",
+		"Email":    "E-mail address",
 		"Website":  "Website",
 		"Location": "Location",
 		"Avatar":   "Gravatar Email",
diff --git a/routers/admin/user.go b/routers/admin/user.go
index 9dcc1499e3..47eec5c914 100644
--- a/routers/admin/user.go
+++ b/routers/admin/user.go
@@ -7,8 +7,11 @@ package admin
 import (
 	"strings"
 
+	"github.com/codegangsta/martini"
+
 	"github.com/gogits/gogs/models"
 	"github.com/gogits/gogs/modules/auth"
+	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/log"
 	"github.com/gogits/gogs/modules/middleware"
 )
@@ -61,3 +64,44 @@ func NewUser(ctx *middleware.Context, form auth.RegisterForm) {
 
 	ctx.Redirect("/admin/users")
 }
+
+func EditUser(ctx *middleware.Context, params martini.Params, form auth.AdminEditUserForm) {
+	ctx.Data["Title"] = "Edit Account"
+
+	uid, err := base.StrTo(params["userid"]).Int()
+	if err != nil {
+		ctx.Handle(200, "admin.user.EditUser", err)
+		return
+	}
+
+	u, err := models.GetUserById(int64(uid))
+	if err != nil {
+		ctx.Handle(200, "admin.user.EditUser", err)
+		return
+	}
+
+	if ctx.Req.Method == "GET" {
+		ctx.Data["User"] = u
+		ctx.HTML(200, "admin/users/edit")
+		return
+	}
+
+	u.Email = form.Email
+	u.Website = form.Website
+	u.Location = form.Location
+	u.Avatar = base.EncodeMd5(form.Avatar)
+	u.AvatarEmail = form.Avatar
+	u.IsActive = form.Active == "on"
+	u.IsAdmin = form.Admin == "on"
+	if err := models.UpdateUser(u); err != nil {
+		ctx.Handle(200, "admin.user.EditUser", err)
+		return
+	}
+
+	ctx.Data["IsSuccess"] = true
+	ctx.Data["User"] = u
+	ctx.HTML(200, "admin/users/edit")
+
+	log.Trace("%s User profile updated by admin(%s): %s", ctx.Req.RequestURI,
+		ctx.User.LowerName, ctx.User.LowerName)
+}
diff --git a/routers/user/setting.go b/routers/user/setting.go
index f0c7a8a5b1..75adf2b81d 100644
--- a/routers/user/setting.go
+++ b/routers/user/setting.go
@@ -46,6 +46,7 @@ func Setting(ctx *middleware.Context, form auth.UpdateProfileForm) {
 
 	ctx.Data["IsSuccess"] = true
 	ctx.HTML(200, "user/setting")
+
 	log.Trace("%s User setting updated: %s", ctx.Req.RequestURI, ctx.User.LowerName)
 }
 
diff --git a/templates/admin/users.tmpl b/templates/admin/users.tmpl
index d82f04b812..dec5c18954 100644
--- a/templates/admin/users.tmpl
+++ b/templates/admin/users.tmpl
@@ -20,6 +20,7 @@
                             <th>Admin</th>
                             <th>Repos</th>
                             <th>Join</th>
+                            <th>Edit</th>
                         </tr>
                     </thead>
                     <tbody>
@@ -32,6 +33,7 @@
                             <td><i class="fa fa{{if .IsAdmin}}-check{{end}}-square-o"></i></td>
                             <td>{{.NumRepos}}</td>
                             <td>{{DateFormat .Created "M d, Y"}}</td>
+                            <td><a href="/admin/users/{{.Id}}"><i class="fa fa-pencil-square-o"></i></a></td>
                         </tr>
                         {{end}}
                     </tbody>
diff --git a/templates/admin/users/edit.tmpl b/templates/admin/users/edit.tmpl
new file mode 100644
index 0000000000..f7782fe07a
--- /dev/null
+++ b/templates/admin/users/edit.tmpl
@@ -0,0 +1,83 @@
+{{template "base/head" .}}
+{{template "base/navbar" .}}
+<div id="gogs-body" class="container" data-page="admin">
+    {{template "admin/nav" .}}
+    <div id="gogs-admin-container" class="col-md-9">
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                Edit Account
+            </div>
+
+            <div class="panel-body">
+            	<br/>
+				<form action="/admin/users/{{.User.Id}}" method="post" class="form-horizontal">
+				    {{if .IsSuccess}}<p class="alert alert-success">Your profile has been successfully updated.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}}
+                	<input type="hidden" value="{{.User.Id}}" name="userId"/>
+					<div class="form-group">
+						<label class="col-md-3 control-label">Username: </label>
+						<label class="control-label">{{.User.Name}}</label>
+					</div>
+
+					<div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}">
+						<label class="col-md-3 control-label">Email<strong class="text-danger">*</strong></label>
+						<div class="col-md-7">
+							<input name="email" class="form-control" placeholder="Type account's e-mail address" value="{{.User.Email}}" required="required">
+						</div>
+					</div>
+
+	                <div class="form-group">
+	                    <label class="col-md-3 control-label">Website</label>
+	                    <div class="col-md-7">
+	                        <input name="website" class="form-control" placeholder="Type account's website URL" value="{{.User.Website}}">
+	                    </div>
+	                </div>
+
+	                <div class="form-group">
+	                    <label class="col-md-3 control-label">Location</label>
+	                    <div class="col-md-7">
+	                        <input name="location" class="form-control" placeholder="Type account's current location" value="{{.User.Location}}">
+	                    </div>
+	                </div>
+
+	                <div class="form-group {{if .Err_Avatar}}has-error has-feedback{{end}}">
+	                    <label class="col-md-3 control-label">Gravatar Email<strong class="text-danger">*</strong></label>
+	                    <div class="col-md-7">
+	                        <input name="avatar" class="form-control" placeholder="Type account's Gravatar e-mail address" required="required" value="{{.User.AvatarEmail}}">
+	                    </div>
+	                </div>
+
+	                <div class="form-group">
+			            <div class="col-md-7 col-md-offset-3">
+			                <div class="checkbox">
+			                    <label>
+			                        <input type="checkbox" name="active" {{if .User.IsActive}}checked{{end}}>
+			                        <strong>This account has activated</strong>
+			                    </label>
+			                </div>
+			            </div>
+	                </div>
+
+	                <div class="form-group">
+			            <div class="col-md-7 col-md-offset-3">
+			                <div class="checkbox">
+			                    <label>
+			                        <input type="checkbox" name="admin" {{if .User.IsAdmin}}checked{{end}}>
+			                        <strong>This account has administor permisson</strong>
+			                    </label>
+			                </div>
+			            </div>
+	                </div>
+					<hr/>
+					<div class="form-group">
+					    <div class="col-md-offset-3 col-md-6">
+					    	<button type="submit" class="btn btn-lg btn-primary btn-block">Update account profile</button>
+					    	<!-- <a type="button" href="/admin/users/{{.User.Id}}/delete" class="btn btn-lg btn-danger btn-block">Delete this account</a> -->
+					    </div>
+					</div>
+				</form>
+            </div>
+        </div>
+
+	</div>
+</div>
+{{template "base/footer" .}}
\ No newline at end of file
diff --git a/templates/admin/users/new.tmpl b/templates/admin/users/new.tmpl
index bf59b16a80..01d976caa0 100644
--- a/templates/admin/users/new.tmpl
+++ b/templates/admin/users/new.tmpl
@@ -13,35 +13,35 @@
 				<form action="/admin/users/new" method="post" class="form-horizontal">
 				    <div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div>
 					<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}">
-						<label class="col-md-4 control-label">Username: </label>
-						<div class="col-md-6">
+						<label class="col-md-3 control-label">Username: </label>
+						<div class="col-md-7">
 							<input name="username" class="form-control" placeholder="Type account's username" value="{{.username}}" required="required">
 						</div>
 					</div>
 
 					<div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}">
-						<label class="col-md-4 control-label">Email: </label>
-						<div class="col-md-6">
+						<label class="col-md-3 control-label">Email: </label>
+						<div class="col-md-7">
 							<input name="email" class="form-control" placeholder="Type account's e-mail address" value="{{.email}}" required="required" title="Email is not valid">
 						</div>
 					</div>
 
 					<div class="form-group {{if .Err_Password}}has-error has-feedback{{end}}">
-						<label class="col-md-4 control-label">Password: </label>
-						<div class="col-md-6">
+						<label class="col-md-3 control-label">Password: </label>
+						<div class="col-md-7">
 							<input name="passwd" type="password" class="form-control" placeholder="Type account's password" required="required" title="Password must contain at least 6 characters">
 						</div>
 					</div>
 
 					<div class="form-group {{if .Err_RetypePasswd}}has-error has-feedback{{end}}">
-						<label class="col-md-4 control-label">Re-type: </label>
-						<div class="col-md-6">
+						<label class="col-md-3 control-label">Re-type: </label>
+						<div class="col-md-7">
 							<input name="retypepasswd" type="password" class="form-control" placeholder="Re-type account's password" required="required" title="Re-type Password must be same to Password">
 						</div>
 					</div>
-
+					<hr/>
 					<div class="form-group">
-					    <div class="col-md-offset-4 col-md-6">
+					    <div class="col-md-offset-3 col-md-7">
 					    	<button type="submit" class="btn btn-lg btn-primary">Create new account</button>
 					    </div>
 					</div>
diff --git a/templates/user/setting.tmpl b/templates/user/setting.tmpl
index c38054f39b..222ddd895b 100644
--- a/templates/user/setting.tmpl
+++ b/templates/user/setting.tmpl
@@ -5,8 +5,8 @@
     <div id="gogs-user-setting-container" class="col-md-9">
         <div id="gogs-setting-pwd">
             <h4>Account Profile</h4>
-            <form class="form-horizontal" id="gogs-password-form" method="post" action="/user/setting">{{if .IsSuccess}}
-                <p class="alert alert-success">Your profile has been successfully updated.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}}
+            <form class="form-horizontal" id="gogs-password-form" method="post" action="/user/setting">
+                {{if .IsSuccess}}<p class="alert alert-success">Your profile has been successfully updated.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}}
                 <p>Your Email will be public and used for Account related notifications and any web based operations made via the web.</p>
                 <div class="form-group">
                     <label class="col-md-2 control-label">Email</label>
@@ -29,7 +29,7 @@
                     </div>
                 </div>
 
-                <div class="form-group">
+                <div class="form-group {{if .Err_Avatar}}has-error has-feedback{{end}}">
                     <label class="col-md-2 control-label">Gravatar Email<strong class="text-danger">*</strong></label>
                     <div class="col-md-8">
                         <input type="text" name="avatar" class="form-control" placeholder="Type your Gravatar e-mail address" required="required" value="{{.Owner.AvatarEmail}}">
diff --git a/web.go b/web.go
index d6d78afa5d..54aaab573b 100644
--- a/web.go
+++ b/web.go
@@ -118,6 +118,7 @@ func runWeb(*cli.Context) {
 	m.Get("/admin", reqSignIn, adminReq, admin.Dashboard)
 	m.Get("/admin/users", reqSignIn, adminReq, admin.Users)
 	m.Any("/admin/users/new", reqSignIn, adminReq, binding.BindIgnErr(auth.RegisterForm{}), admin.NewUser)
+	m.Any("/admin/users/:userid", reqSignIn, adminReq, binding.BindIgnErr(auth.AdminEditUserForm{}), admin.EditUser)
 	m.Get("/admin/repos", reqSignIn, adminReq, admin.Repositories)
 	m.Get("/admin/config", reqSignIn, adminReq, admin.Config)
 

From e4053f5e982f627d983a08bf3fe6bb2b20b904b5 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 21 Mar 2014 06:47:24 -0400
Subject: [PATCH 32/41] Mirror update

---
 templates/admin/users/edit.tmpl |  2 +-
 templates/base/footer.tmpl      | 19 +++++++++++++------
 2 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/templates/admin/users/edit.tmpl b/templates/admin/users/edit.tmpl
index f7782fe07a..415bcedc92 100644
--- a/templates/admin/users/edit.tmpl
+++ b/templates/admin/users/edit.tmpl
@@ -11,7 +11,7 @@
             <div class="panel-body">
             	<br/>
 				<form action="/admin/users/{{.User.Id}}" method="post" class="form-horizontal">
-				    {{if .IsSuccess}}<p class="alert alert-success">Your profile has been successfully updated.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}}
+				    {{if .IsSuccess}}<p class="alert alert-success">Account profile has been successfully updated.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}}
                 	<input type="hidden" value="{{.User.Id}}" name="userId"/>
 					<div class="form-group">
 						<label class="col-md-3 control-label">Username: </label>
diff --git a/templates/base/footer.tmpl b/templates/base/footer.tmpl
index fe0ea93027..5ae5c96d68 100644
--- a/templates/base/footer.tmpl
+++ b/templates/base/footer.tmpl
@@ -2,12 +2,19 @@
 </div>
 <footer id="footer">
     <div class="container footer-wrap">
-        <p>© 2014 Gogs · ver {{AppVer}} ·
-            All: {{LoadTimes .PageStartTime}} ·
-            Tmpl: {{call .TmplLoadTimes}} ·
-            <i class="fa fa-github"></i><a target="_blank" href="https://github.com/gogits/gogs">GitHub</a> ·
-        </p>
-        <p class="desc"></p>
+    	<div class="row">
+	    	<div class="col-md-6">
+		        <p>© 2014 Gogs · Version: {{AppVer}} ·
+		            Page: <b>{{LoadTimes .PageStartTime}}</b> ·
+		            Template: <b>{{call .TmplLoadTimes}}</b>
+		        </p>
+	        </div>
+
+	    	<div class="col-md-1" style="margin: -5px;">
+		        <a target="_blank" href="https://github.com/gogits/gogs"><i class="fa fa-github fa-2x"></i></a>
+	        </div>
+	        <p class="desc"></p>
+    	</div>
     </div>
 </footer>
 </body>

From ecc61ced413a60fcfdc432b921dc2c1b3cab0366 Mon Sep 17 00:00:00 2001
From: FuXiaoHei <fuxiaohei@hexiaz.com>
Date: Fri, 21 Mar 2014 21:06:05 +0800
Subject: [PATCH 33/41] update admin nav ui

---
 public/css/gogs.css        | 21 +++++++++++++++++++++
 routers/admin/user.go      |  2 ++
 templates/admin/nav.tmpl   |  2 +-
 templates/base/footer.tmpl |  2 +-
 4 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/public/css/gogs.css b/public/css/gogs.css
index b799882352..aec8f1b328 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -324,6 +324,27 @@ html, body {
     color: #444;
 }
 
+.gogs-admin-nav{
+    background-color: #FFF;
+    padding-top: 10px;
+    padding-left: 0;
+    padding-right: 0;
+    border:1px solid #D8D8D8;
+}
+
+.gogs-admin-nav li{
+    margin-bottom: 8px;
+    border-left: 4px solid transparent;
+}
+
+.gogs-admin-nav li:hover{
+    border-left-color: #EEE;
+}
+
+.gogs-admin-nav li.active:hover{
+    border-left: 4px solid #DD4B39;
+}
+
 /* gogits user ssh keys */
 
 #gogs-ssh-keys .list-group-item {
diff --git a/routers/admin/user.go b/routers/admin/user.go
index 47eec5c914..d6f8523218 100644
--- a/routers/admin/user.go
+++ b/routers/admin/user.go
@@ -18,6 +18,7 @@ import (
 
 func NewUser(ctx *middleware.Context, form auth.RegisterForm) {
 	ctx.Data["Title"] = "New Account"
+	ctx.Data["PageIsUsers"] = true
 
 	if ctx.Req.Method == "GET" {
 		ctx.HTML(200, "admin/users/new")
@@ -67,6 +68,7 @@ func NewUser(ctx *middleware.Context, form auth.RegisterForm) {
 
 func EditUser(ctx *middleware.Context, params martini.Params, form auth.AdminEditUserForm) {
 	ctx.Data["Title"] = "Edit Account"
+	ctx.Data["PageIsUsers"] = true
 
 	uid, err := base.StrTo(params["userid"]).Int()
 	if err != nil {
diff --git a/templates/admin/nav.tmpl b/templates/admin/nav.tmpl
index bb704ee3fb..72f008acc7 100644
--- a/templates/admin/nav.tmpl
+++ b/templates/admin/nav.tmpl
@@ -1,4 +1,4 @@
-<div id="gogs-user-setting-nav" class="col-md-3">
+<div id="gogs-user-setting-nav" class="col-md-3 gogs-admin-nav">
     <ul class="list-group" data-init="tabs">
         <li class="list-group-item{{if .PageIsDashboard}} active{{end}}"><a href="/admin"><i class="fa fa-tachometer fa-lg"></i> Dashboard</a></li>
         <li class="list-group-item{{if .PageIsUsers}} active{{end}}"><a href="/admin/users"><i class="fa fa-users fa-lg"></i> Users</a></li>
diff --git a/templates/base/footer.tmpl b/templates/base/footer.tmpl
index 5ae5c96d68..6c2da63e5d 100644
--- a/templates/base/footer.tmpl
+++ b/templates/base/footer.tmpl
@@ -4,7 +4,7 @@
     <div class="container footer-wrap">
     	<div class="row">
 	    	<div class="col-md-6">
-		        <p>© 2014 Gogs · Version: {{AppVer}} ·
+		        <p>© 2014 GoGits · Version: {{AppVer}} ·
 		            Page: <b>{{LoadTimes .PageStartTime}}</b> ·
 		            Template: <b>{{call .TmplLoadTimes}}</b>
 		        </p>

From c7e0d3a499941a4cbd7814e30308c8f3c6e45543 Mon Sep 17 00:00:00 2001
From: slene <vslene@gmail.com>
Date: Fri, 21 Mar 2014 21:06:47 +0800
Subject: [PATCH 34/41] add cache

---
 conf/app.ini                  |  4 ++++
 modules/base/conf.go          | 16 ++++++++++++++++
 modules/middleware/context.go |  3 +++
 3 files changed, 23 insertions(+)

diff --git a/conf/app.ini b/conf/app.ini
index 985903a8e5..71fe81e834 100644
--- a/conf/app.ini
+++ b/conf/app.ini
@@ -60,6 +60,10 @@ FROM =
 USER = 
 PASSWD = 
 
+[cache]
+ADAPTER = memory
+CONFIG = 
+
 [log]
 ; Either "console", "file", "conn" or "smtp", default is "console"
 MODE = console
diff --git a/modules/base/conf.go b/modules/base/conf.go
index bf054ec3c5..3962972cda 100644
--- a/modules/base/conf.go
+++ b/modules/base/conf.go
@@ -15,6 +15,8 @@ import (
 	"github.com/Unknwon/com"
 	"github.com/Unknwon/goconfig"
 
+	"github.com/gogits/cache"
+
 	"github.com/gogits/gogs/modules/log"
 )
 
@@ -37,6 +39,10 @@ var (
 
 	Cfg         *goconfig.ConfigFile
 	MailService *Mailer
+
+	Cache        cache.Cache
+	CacheAdapter string
+	CacheConfig  string
 )
 
 var Service struct {
@@ -182,6 +188,16 @@ func NewConfigContext() {
 	SecretKey = Cfg.MustValue("security", "SECRET_KEY")
 	RunUser = Cfg.MustValue("", "RUN_USER")
 
+	CacheAdapter = Cfg.MustValue("cache", "ADAPTER")
+	CacheConfig = Cfg.MustValue("cache", "CONFIG")
+
+	Cache, err = cache.NewCache(CacheAdapter, CacheConfig)
+	if err != nil {
+		fmt.Printf("Init cache system failed, adapter: %s, config: %s, %v\n",
+			CacheAdapter, CacheConfig, err)
+		os.Exit(2)
+	}
+
 	// Determine and create root git reposiroty path.
 	RepoRootPath = Cfg.MustValue("repository", "ROOT")
 	if err = os.MkdirAll(RepoRootPath, os.ModePerm); err != nil {
diff --git a/modules/middleware/context.go b/modules/middleware/context.go
index cb3cbabca6..da051918b1 100644
--- a/modules/middleware/context.go
+++ b/modules/middleware/context.go
@@ -12,6 +12,8 @@ import (
 	"github.com/codegangsta/martini"
 	"github.com/martini-contrib/sessions"
 
+	"github.com/gogits/cache"
+
 	"github.com/gogits/gogs/models"
 	"github.com/gogits/gogs/modules/auth"
 	"github.com/gogits/gogs/modules/log"
@@ -25,6 +27,7 @@ type Context struct {
 	Req      *http.Request
 	Res      http.ResponseWriter
 	Session  sessions.Session
+	Cache    cache.Cache
 	User     *models.User
 	IsSigned bool
 

From 14ddb8b1fa9ccdd877f808112e38d2f0146fe3c2 Mon Sep 17 00:00:00 2001
From: FuXiaoHei <fuxiaohei@hexiaz.com>
Date: Fri, 21 Mar 2014 21:16:13 +0800
Subject: [PATCH 35/41] fix dashboard repo link

---
 public/css/gogs.css           | 3 +--
 templates/user/dashboard.tmpl | 3 ++-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/public/css/gogs.css b/public/css/gogs.css
index aec8f1b328..9f16196616 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -397,7 +397,7 @@ html, body {
 }
 
 #gogs-feed-right .repo-panel .list-group-item a {
-    display: inline-block;
+    display: block;
     margin-left: 0;
     background-color: transparent;
     padding-left: 0;
@@ -427,7 +427,6 @@ html, body {
 
 #gogs-feed-right .repo-panel span.stars {
     color: #666;
-    line-height: 44px;
     margin-right: 1em;
 }
 
diff --git a/templates/user/dashboard.tmpl b/templates/user/dashboard.tmpl
index c528185c01..72c31d3d8f 100644
--- a/templates/user/dashboard.tmpl
+++ b/templates/user/dashboard.tmpl
@@ -33,8 +33,9 @@
             </div>
             <div class="panel-body">
                 <ul class="list-group">{{range .MyRepos}}
-                    <li class="list-group-item"><i class="fa fa-book"></i><a href="/{{$.SignedUserName}}/{{.Name}}">{{.Name}}</a>
+                    <li class="list-group-item"><a href="/{{$.SignedUserName}}/{{.Name}}">
                         <span class="stars pull-right"><i class="fa fa-star"></i>{{.NumStars}}</span>
+                        <i class="fa fa-book"></i>{{.Name}}</a>
                     </li>{{end}}
                 </ul>
             </div>

From 770c78a177c64ba2014f4152da95f0899495772a Mon Sep 17 00:00:00 2001
From: slene <vslene@gmail.com>
Date: Fri, 21 Mar 2014 21:31:47 +0800
Subject: [PATCH 36/41] fix

---
 modules/middleware/context.go | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/modules/middleware/context.go b/modules/middleware/context.go
index da051918b1..a25a3dbbeb 100644
--- a/modules/middleware/context.go
+++ b/modules/middleware/context.go
@@ -16,6 +16,7 @@ import (
 
 	"github.com/gogits/gogs/models"
 	"github.com/gogits/gogs/modules/auth"
+	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/log"
 )
 
@@ -100,6 +101,7 @@ func InitContext() martini.Handler {
 			Req:     r,
 			Res:     res,
 			Session: session,
+			Cache:   base.Cache,
 			Render:  rd,
 		}
 

From 85abe5132e1c67a247839bd819b67311f97a7563 Mon Sep 17 00:00:00 2001
From: FuXiaoHei <fuxiaohei@hexiaz.com>
Date: Fri, 21 Mar 2014 21:36:15 +0800
Subject: [PATCH 37/41] fix navbar button ui

---
 templates/base/navbar.tmpl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/templates/base/navbar.tmpl b/templates/base/navbar.tmpl
index d775191a5a..2c18b038a3 100644
--- a/templates/base/navbar.tmpl
+++ b/templates/base/navbar.tmpl
@@ -11,7 +11,7 @@
             <a class="navbar-right gogs-nav-item{{if .PageIsNewRepo}} active{{end}}" href="/repo/create" data-toggle="tooltip" data-placement="bottom" title="New Repository"><i class="fa fa-plus fa-lg"></i></a>
             <a class="navbar-right gogs-nav-item{{if .PageIsUserSetting}} active{{end}}" href="/user/setting"  data-toggle="tooltip" data-placement="bottom" title="Setting"><i class="fa fa-cogs fa-lg"></i></a>
             {{if .IsAdmin}}<a class="navbar-right gogs-nav-item{{if .PageIsAdmin}} active{{end}}" href="/admin"  data-toggle="tooltip" data-placement="bottom" title="Admin"><i class="fa fa-gear fa-lg"></i></a>{{end}}
-            {{else}}<a id="gogs-nav-signin" class="gogs-nav-item navbar-right navbar-btn btn btn-success" href="/user/login/">Sign In</a>
+            {{else}}<a id="gogs-nav-signin" class="gogs-nav-item navbar-right navbar-btn btn btn-danger" href="/user/login/">Sign In</a>
             <a id="gogs-nav-signup" class="gogs-nav-item navbar-right navbar-btn btn btn-info" href="/user/sign_up/">Sign Up</a>{{end}}
         </nav>
     </div>

From 67c4e5429818b501b0db5527ea38f2be75e5df55 Mon Sep 17 00:00:00 2001
From: FuXiaoHei <fuxiaohei@hexiaz.com>
Date: Fri, 21 Mar 2014 21:48:13 +0800
Subject: [PATCH 38/41] fix navbar button ui

---
 public/css/gogs.css | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/public/css/gogs.css b/public/css/gogs.css
index 9f16196616..36d57536c6 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -145,8 +145,9 @@ html, body {
     float: right;
 }
 
-#gogs-nav-signin {
+#gogs-nav-signin, #gogs-nav-signup {
     float: right;
+    margin-left: 1em;
 }
 
 #gogs-nav-out .fa {
@@ -324,24 +325,24 @@ html, body {
     color: #444;
 }
 
-.gogs-admin-nav{
+.gogs-admin-nav {
     background-color: #FFF;
     padding-top: 10px;
     padding-left: 0;
     padding-right: 0;
-    border:1px solid #D8D8D8;
+    border: 1px solid #D8D8D8;
 }
 
-.gogs-admin-nav li{
+.gogs-admin-nav li {
     margin-bottom: 8px;
     border-left: 4px solid transparent;
 }
 
-.gogs-admin-nav li:hover{
+.gogs-admin-nav li:hover {
     border-left-color: #EEE;
 }
 
-.gogs-admin-nav li.active:hover{
+.gogs-admin-nav li.active:hover {
     border-left: 4px solid #DD4B39;
 }
 

From d40499e7fa3d62655431f160b6909d9751dabe11 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 21 Mar 2014 10:09:57 -0400
Subject: [PATCH 39/41] Finsih mail resend limit

---
 README.md                   |  2 +-
 conf/app.ini                |  8 +++++++-
 gogs.go                     |  2 +-
 models/models.go            |  1 -
 modules/base/conf.go        | 35 +++++++++++++++++++++++++----------
 routers/admin/admin.go      |  3 +++
 routers/user/user.go        | 12 ++++++++++--
 templates/admin/config.tmpl | 11 +++++++++++
 templates/user/active.tmpl  |  2 ++
 9 files changed, 60 insertions(+), 16 deletions(-)

diff --git a/README.md b/README.md
index e78ce8fe99..cbd1f588df 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ Gogs(Go Git Service) is a GitHub-like clone in the Go Programming Language.
 
 Since we choose to use pure Go implementation of Git manipulation, Gogs certainly supports **ALL platforms**  that Go supports, including Linux, Max OS X, and Windows with **ZERO** dependency.
 
-##### Current version: 0.1.4 Alpha
+##### Current version: 0.1.5 Alpha
 
 ## Purpose
 
diff --git a/conf/app.ini b/conf/app.ini
index 71fe81e834..ecb0d2511f 100644
--- a/conf/app.ini
+++ b/conf/app.ini
@@ -61,8 +61,14 @@ USER =
 PASSWD = 
 
 [cache]
+; Either "memory", "redis", or "memcache", default is "memory"
 ADAPTER = memory
-CONFIG = 
+; For "memory" only, GC interval in seconds, default is 60
+INTERVAL = 60
+; For "redis" and "memcache", connection host address
+; redis: ":6039"
+; memcache: "127.0.0.1:11211"
+HOST =
 
 [log]
 ; Either "console", "file", "conn" or "smtp", default is "console"
diff --git a/gogs.go b/gogs.go
index a9f7e6b5c4..41df79280a 100644
--- a/gogs.go
+++ b/gogs.go
@@ -20,7 +20,7 @@ import (
 // Test that go1.2 tag above is included in builds. main.go refers to this definition.
 const go12tag = true
 
-const APP_VER = "0.1.4.0321"
+const APP_VER = "0.1.5.0321"
 
 func init() {
 	base.AppVer = APP_VER
diff --git a/models/models.go b/models/models.go
index a4550d7243..8713ff2896 100644
--- a/models/models.go
+++ b/models/models.go
@@ -35,7 +35,6 @@ func LoadModelsConfig() {
 }
 
 func setEngine() {
-
 	var err error
 	switch DbCfg.Type {
 	case "mysql":
diff --git a/modules/base/conf.go b/modules/base/conf.go
index 3962972cda..2c3ecd72d8 100644
--- a/modules/base/conf.go
+++ b/modules/base/conf.go
@@ -133,6 +133,30 @@ func newLogService() {
 	log.Info("Log Mode: %s(%s)", strings.Title(mode), levelName)
 }
 
+func newCacheService() {
+	CacheAdapter = Cfg.MustValue("cache", "ADAPTER", "memory")
+
+	switch CacheAdapter {
+	case "memory":
+		CacheConfig = fmt.Sprintf(`{"interval":%d}`, Cfg.MustInt("cache", "INTERVAL", 60))
+	case "redis", "memcache":
+		CacheConfig = fmt.Sprintf(`{"conn":"%s"}`, Cfg.MustValue("cache", "HOST"))
+	default:
+		fmt.Printf("Unknown cache adapter: %s\n", CacheAdapter)
+		os.Exit(2)
+	}
+
+	var err error
+	Cache, err = cache.NewCache(CacheAdapter, CacheConfig)
+	if err != nil {
+		fmt.Printf("Init cache system failed, adapter: %s, config: %s, %v\n",
+			CacheAdapter, CacheConfig, err)
+		os.Exit(2)
+	}
+
+	log.Info("Cache Service Enabled")
+}
+
 func newMailService() {
 	// Check mailer setting.
 	if Cfg.MustBool("mailer", "ENABLED") {
@@ -188,16 +212,6 @@ func NewConfigContext() {
 	SecretKey = Cfg.MustValue("security", "SECRET_KEY")
 	RunUser = Cfg.MustValue("", "RUN_USER")
 
-	CacheAdapter = Cfg.MustValue("cache", "ADAPTER")
-	CacheConfig = Cfg.MustValue("cache", "CONFIG")
-
-	Cache, err = cache.NewCache(CacheAdapter, CacheConfig)
-	if err != nil {
-		fmt.Printf("Init cache system failed, adapter: %s, config: %s, %v\n",
-			CacheAdapter, CacheConfig, err)
-		os.Exit(2)
-	}
-
 	// Determine and create root git reposiroty path.
 	RepoRootPath = Cfg.MustValue("repository", "ROOT")
 	if err = os.MkdirAll(RepoRootPath, os.ModePerm); err != nil {
@@ -209,6 +223,7 @@ func NewConfigContext() {
 func NewServices() {
 	newService()
 	newLogService()
+	newCacheService()
 	newMailService()
 	newRegisterMailService()
 }
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
index 6d3831a9f3..d70af3c50c 100644
--- a/routers/admin/admin.go
+++ b/routers/admin/admin.go
@@ -67,5 +67,8 @@ func Config(ctx *middleware.Context) {
 		ctx.Data["Mailer"] = base.MailService
 	}
 
+	ctx.Data["CacheAdapter"] = base.CacheAdapter
+	ctx.Data["CacheConfig"] = base.CacheConfig
+
 	ctx.HTML(200, "admin/config")
 }
diff --git a/routers/user/user.go b/routers/user/user.go
index 40b594ab80..d38eb1ceb3 100644
--- a/routers/user/user.go
+++ b/routers/user/user.go
@@ -167,6 +167,10 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) {
 		ctx.Data["Email"] = u.Email
 		ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60
 		ctx.HTML(200, "user/active")
+
+		if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
+			log.Error("Set cache(MailResendLimit) fail: %v", err)
+		}
 		return
 	}
 	ctx.Redirect("/user/login")
@@ -247,8 +251,12 @@ func Activate(ctx *middleware.Context) {
 		}
 		// Resend confirmation e-mail.
 		if base.Service.RegisterEmailConfirm {
-			ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60
-			mailer.SendActiveMail(ctx.Render, ctx.User)
+			if ctx.Cache.IsExist("MailResendLimit_" + ctx.User.LowerName) {
+				ctx.Data["ResendLimited"] = true
+			} else {
+				ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60
+				mailer.SendActiveMail(ctx.Render, ctx.User)
+			}
 		} else {
 			ctx.Data["ServiceNotEnabled"] = true
 		}
diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl
index 7013c201ae..ad32ec3fb1 100644
--- a/templates/admin/config.tmpl
+++ b/templates/admin/config.tmpl
@@ -63,6 +63,17 @@
                 <div><b>User:</b> {{.Mailer.User}}</div>
             </div>
         </div>
+
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                Cache Configuration
+            </div>
+
+            <div class="panel-body">
+                <div><b>Cache Adapter:</b> {{.CacheAdapter}}</div>
+                <div><b>Cache Config:</b> <code>{{.CacheConfig}}</code></div>
+            </div>
+        </div>
     </div>
 </div>
 {{template "base/footer" .}}
\ No newline at end of file
diff --git a/templates/user/active.tmpl b/templates/user/active.tmpl
index fefd7d3aed..47c87a591c 100644
--- a/templates/user/active.tmpl
+++ b/templates/user/active.tmpl
@@ -6,6 +6,8 @@
         {{if .IsActivatePage}}
             {{if .ServiceNotEnabled}}
             <p>Sorry, Register Mail Confirmation has been disabled.</p>
+            {{else if .ResendLimited}}
+            <p>Sorry, you are sending activation e-mail too frequently, please wait 3 minutes.</p>
             {{else}}
             <p>New confirmation e-mail has been sent to <b>{{.SignedUser.Email}}</b>, please check your inbox within {{.Hours}} hours to complete your registeration.</p>
             <hr/>

From 011134e0aff5d16501b60a6feaaa8c2ccf0d269d Mon Sep 17 00:00:00 2001
From: FuXiaoHei <fuxiaohei@hexiaz.com>
Date: Fri, 21 Mar 2014 23:27:33 +0800
Subject: [PATCH 40/41] add clone link in repo index page

---
 public/css/gogs.css             |  9 +++++++++
 public/js/app.js                | 21 ++++++++++++++-------
 templates/repo/nav.tmpl         | 30 ++++++++++++++++++++++++------
 templates/repo/single_bare.tmpl |  4 ++--
 4 files changed, 49 insertions(+), 15 deletions(-)

diff --git a/public/css/gogs.css b/public/css/gogs.css
index 36d57536c6..78040bee51 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -575,6 +575,15 @@ html, body {
     min-width: 200px;
 }
 
+#gogs-repo-clone .dropdown-menu{
+    width: 400px;
+    padding: 20px;
+}
+
+#gogs-repo-clone .input-group{
+    margin-bottom: 15px;
+}
+
 /* #gogs-source */
 #gogs-source {
     margin-top: -20px;
diff --git a/public/js/app.js b/public/js/app.js
index a264fc94eb..f179342f4b 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -63,6 +63,12 @@ var Gogits = {
         var $tabs = $('[data-init=tabs]');
         $tabs.find("li:eq(0) a").tab("show");
     };
+    // fix dropdown inside click
+    Gogits.initDropDown = function(){
+        $('.dropdown-menu').on('click','a,button,input,select',function(e){
+            e.stopPropagation();
+        });
+    };
 
     // render markdown
     Gogits.renderMarkdown = function () {
@@ -136,6 +142,7 @@ function initCore() {
     Gogits.initPopovers();
     Gogits.initTabs();
     Gogits.initModals();
+    Gogits.initDropDown();
     Gogits.renderMarkdown();
 }
 
@@ -181,18 +188,18 @@ function initUserSetting() {
 }
 
 function initRepository() {
-    // guide box script
+    // clone group button script
     (function () {
-        var $guide = $('.guide-box');
-        if ($guide.length) {
-            var $url = $('#guide-clone-url');
-            $guide.find('button[data-link]').on("click",function () {
+        var $clone = $('.clone-group-btn');
+        if ($clone.length) {
+            var $url = $('.clone-group-url');
+            $clone.find('button[data-link]').on("click",function (e) {
                 var $this = $(this);
                 if (!$this.hasClass('btn-primary')) {
-                    $guide.find('.btn-primary').removeClass('btn-primary').addClass("btn-default");
+                    $clone.find('.btn-primary').removeClass('btn-primary').addClass("btn-default");
                     $(this).addClass('btn-primary').removeClass('btn-default');
                     $url.val($this.data("link"));
-                    $guide.find('span.clone-url').text($this.data('link'));
+                    $clone.find('span.clone-url').text($this.data('link'));
                 }
             }).eq(0).trigger("click");
             // todo copy to clipboard
diff --git a/templates/repo/nav.tmpl b/templates/repo/nav.tmpl
index c61051af25..d4a692fd03 100644
--- a/templates/repo/nav.tmpl
+++ b/templates/repo/nav.tmpl
@@ -5,13 +5,32 @@
                 <h3 class="name"><i class="fa fa-book fa-lg"></i><a href="{{.Owner.HomeLink}}">{{.Owner.Name}}</a> / {{.Repository.Name}}</h3>
                 <p class="desc">{{.Repository.Description}}{{if .Repository.Website}}<a href="{{.Repository.Website}}">{{.Repository.Website}}</a>{{end}}</p>
             </div>
-            <div class="col-md-6 actions text-right">
+            <div class="col-md-6 actions text-right clone-group-btn">
                 {{if not .IsBareRepo}}
-                <div class="btn-group" id="gogs-repo-clone">
+                <!--<div class="btn-group" id="gogs-repo-clone">
                     <button type="button" class="btn btn-default"><i class="fa fa-download fa-lg fa-m"></i></button>
                     <button type="button" class="btn btn-default dropdown-toggle" data-container="body" data-toggle="popover" data-placement="bottom" data-content="<label>SSH:</label><div class='input-group'><input type='text' class='form-control' value='{{.CloneLink.SSH}}'></div>" data-html="1">
                         <span class="caret"></span>
                     </button>
+                </div>-->
+                <div class="btn-group" id="gogs-repo-clone">
+                    <button type="button" class="btn btn-default"><i class="fa fa-download fa-lg fa-m"></i></button>
+                    <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
+                        <span class="caret"></span>
+                    </button>
+                    <div class="dropdown-menu clone-group-btn dropdown-menu-right">
+                        <div class="input-group">
+                            <span class="input-group-btn">
+                                <button class="btn btn-default" data-link="{{.CloneLink.SSH}}" type="button">SSH</button>
+                                <button class="btn btn-default" data-link="{{.CloneLink.HTTPS}}" type="button">HTTPS</button>
+                            </span>
+                            <input type="text" class="form-control clone-group-url" value="" readonly/>
+                            <span class="input-group-btn">
+                                <button class="btn btn-default" type="button"><i class="fa fa-copy" data-toggle="tooltip" title="copy to clipboard" data-placement="top"></i></button>
+                            </span>
+                        </div>
+                        <p class="help-block text-center">Need help cloning? Visit <a href="#">Help</a>!</p>
+                    </div>
                 </div>
                 <div class="btn-group {{if .IsRepositoryWatching}}watching{{else}}no-watching{{end}}" id="gogs-repo-watching" data-watch="/{{.SignedUser.Name}}/{{.Repository.Name}}/action/watch" data-unwatch="/{{.SignedUser.Name}}/{{.Repository.Name}}/action/unwatch">
                     {{if .IsRepositoryWatching}}
@@ -21,9 +40,8 @@
                     {{end}}
                     <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
                         <span class="caret"></span>
-                        <span class="sr-only">Toggle Dropdown</span>
                     </button>
-                    <div class="dropdown-menu" role="menu">
+                    <div class="dropdown-menu">
                         <div class="dropdown-item text-left to-unwatch">
                             <h4 role="presentation" class="dropdown-header {{if not .IsRepositoryWatching}}text-primary{{end}}">Not Watching</h4>
                             <p class="description">You only receive notifications for conversations in which you participate or are @mentioned.</p>
@@ -36,11 +54,11 @@
                     </div>
                 </div>
                 <div class="btn-group">
-                    <button type="button" class="btn btn-default"><i class="fa fa-star"></i>Star&nbsp;&nbsp;{{.Repository.NumStars}}</button>
+                    <button type="button" class="btn btn-default" data-toggle="tooltip" data-placement="top" title="Star"><i class="fa fa-star"></i>&nbsp;{{.Repository.NumStars}}</button>
                 </div>
                 {{end}}
                 <div class="btn-group">
-                    <a type="button" {{if not .IsRepositoryOwner}}href="/{{.Username}}/{{.Reponame}}/fork"{{end}} class="btn btn-default"><i class="fa fa-code-fork"></i>Fork&nbsp;&nbsp;{{.Repository.NumForks}}</a>
+                    <a type="button" {{if not .IsRepositoryOwner}}href="/{{.Username}}/{{.Reponame}}/fork"{{end}} class="btn btn-default" data-toggle="tooltip" data-placement="top" title="Fork"><i class="fa fa-code-fork fa-lg"></i>&nbsp;{{.Repository.NumForks}}</a>
                 </div>
             </div>
         </div>
diff --git a/templates/repo/single_bare.tmpl b/templates/repo/single_bare.tmpl
index bb05c2f9a6..ed182ad28e 100644
--- a/templates/repo/single_bare.tmpl
+++ b/templates/repo/single_bare.tmpl
@@ -1,4 +1,4 @@
-<div class="panel panel-default guide-box">
+<div class="panel panel-default guide-box clone-group-btn">
     <div class="panel-heading guide-head">
         <h4>Quick Guide</h4>
     </div>
@@ -9,7 +9,7 @@
                 <button class="btn btn-default" data-link="{{.CloneLink.SSH}}" type="button">SSH</button>
                 <button class="btn btn-default" data-link="{{.CloneLink.HTTPS}}" type="button">HTTPS</button>
             </span>
-            <input type="text" class="form-control" id="guide-clone-url" value="" readonly/>
+            <input type="text" class="form-control clone-group-url" id="guide-clone-url" value="" readonly/>
             <span class="input-group-btn">
                 <button class="btn btn-default" type="button"><i class="fa fa-copy" data-toggle="tooltip" title="copy to clipboard" data-placement="top"></i></button>
             </span>

From f219ddcf4ef13b9d5de129da4eb2b56dbc899d61 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 21 Mar 2014 12:13:13 -0400
Subject: [PATCH 41/41] Add log config panel in admin

---
 .gopmfile                   |  3 +--
 modules/base/conf.go        | 26 ++++++++++++++------------
 routers/admin/admin.go      |  3 +++
 templates/admin/config.tmpl | 16 +++++++++++++++-
 4 files changed, 33 insertions(+), 15 deletions(-)

diff --git a/.gopmfile b/.gopmfile
index 9e2440f3ef..5b690a06a7 100644
--- a/.gopmfile
+++ b/.gopmfile
@@ -9,13 +9,12 @@ github.com/Unknwon/com=
 github.com/Unknwon/cae=
 github.com/Unknwon/goconfig=
 github.com/dchest/scrypt=
-github.com/go-sql-driver/mysql=
-github.com/lib/pq=
 github.com/lunny/xorm=
 github.com/gogits/logs=
 github.com/gogits/binding=
 github.com/gogits/git=
 github.com/gogits/gfm=
+github.com/gogits/cache=
 
 [res]
 include=templates|public|conf
diff --git a/modules/base/conf.go b/modules/base/conf.go
index 2c3ecd72d8..863daca644 100644
--- a/modules/base/conf.go
+++ b/modules/base/conf.go
@@ -43,6 +43,9 @@ var (
 	Cache        cache.Cache
 	CacheAdapter string
 	CacheConfig  string
+
+	LogMode   string
+	LogConfig string
 )
 
 var Service struct {
@@ -83,15 +86,15 @@ func newService() {
 
 func newLogService() {
 	// Get and check log mode.
-	mode := Cfg.MustValue("log", "MODE", "console")
-	modeSec := "log." + mode
+	LogMode = Cfg.MustValue("log", "MODE", "console")
+	modeSec := "log." + LogMode
 	if _, err := Cfg.GetSection(modeSec); err != nil {
-		fmt.Printf("Unknown log mode: %s\n", mode)
+		fmt.Printf("Unknown log mode: %s\n", LogMode)
 		os.Exit(2)
 	}
 
 	// Log level.
-	levelName := Cfg.MustValue("log."+mode, "LEVEL", "Trace")
+	levelName := Cfg.MustValue("log."+LogMode, "LEVEL", "Trace")
 	level, ok := logLevels[levelName]
 	if !ok {
 		fmt.Printf("Unknown log level: %s\n", levelName)
@@ -99,14 +102,13 @@ func newLogService() {
 	}
 
 	// Generate log configuration.
-	var config string
-	switch mode {
+	switch LogMode {
 	case "console":
-		config = fmt.Sprintf(`{"level":%s}`, level)
+		LogConfig = fmt.Sprintf(`{"level":%s}`, level)
 	case "file":
 		logPath := Cfg.MustValue(modeSec, "FILE_NAME", "log/gogs.log")
 		os.MkdirAll(path.Dir(logPath), os.ModePerm)
-		config = fmt.Sprintf(
+		LogConfig = fmt.Sprintf(
 			`{"level":%s,"filename":%s,"rotate":%v,"maxlines":%d,"maxsize",%d,"daily":%v,"maxdays":%d}`, level,
 			logPath,
 			Cfg.MustBool(modeSec, "LOG_ROTATE", true),
@@ -115,13 +117,13 @@ func newLogService() {
 			Cfg.MustBool(modeSec, "DAILY_ROTATE", true),
 			Cfg.MustInt(modeSec, "MAX_DAYS", 7))
 	case "conn":
-		config = fmt.Sprintf(`{"level":%s,"reconnectOnMsg":%v,"reconnect":%v,"net":%s,"addr":%s}`, level,
+		LogConfig = fmt.Sprintf(`{"level":%s,"reconnectOnMsg":%v,"reconnect":%v,"net":%s,"addr":%s}`, level,
 			Cfg.MustBool(modeSec, "RECONNECT_ON_MSG", false),
 			Cfg.MustBool(modeSec, "RECONNECT", false),
 			Cfg.MustValue(modeSec, "PROTOCOL", "tcp"),
 			Cfg.MustValue(modeSec, "ADDR", ":7020"))
 	case "smtp":
-		config = fmt.Sprintf(`{"level":%s,"username":%s,"password":%s,"host":%s,"sendTos":%s,"subject":%s}`, level,
+		LogConfig = fmt.Sprintf(`{"level":%s,"username":%s,"password":%s,"host":%s,"sendTos":%s,"subject":%s}`, level,
 			Cfg.MustValue(modeSec, "USER", "example@example.com"),
 			Cfg.MustValue(modeSec, "PASSWD", "******"),
 			Cfg.MustValue(modeSec, "HOST", "127.0.0.1:25"),
@@ -129,8 +131,8 @@ func newLogService() {
 			Cfg.MustValue(modeSec, "SUBJECT", "Diagnostic message from serve"))
 	}
 
-	log.NewLogger(Cfg.MustInt64("log", "BUFFER_LEN", 10000), mode, config)
-	log.Info("Log Mode: %s(%s)", strings.Title(mode), levelName)
+	log.NewLogger(Cfg.MustInt64("log", "BUFFER_LEN", 10000), LogMode, LogConfig)
+	log.Info("Log Mode: %s(%s)", strings.Title(LogMode), levelName)
 }
 
 func newCacheService() {
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
index d70af3c50c..2e19b99c10 100644
--- a/routers/admin/admin.go
+++ b/routers/admin/admin.go
@@ -70,5 +70,8 @@ func Config(ctx *middleware.Context) {
 	ctx.Data["CacheAdapter"] = base.CacheAdapter
 	ctx.Data["CacheConfig"] = base.CacheConfig
 
+	ctx.Data["LogMode"] = base.LogMode
+	ctx.Data["LogConfig"] = base.LogConfig
+
 	ctx.HTML(200, "admin/config")
 }
diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl
index ad32ec3fb1..6906f2409d 100644
--- a/templates/admin/config.tmpl
+++ b/templates/admin/config.tmpl
@@ -71,7 +71,21 @@
 
             <div class="panel-body">
                 <div><b>Cache Adapter:</b> {{.CacheAdapter}}</div>
-                <div><b>Cache Config:</b> <code>{{.CacheConfig}}</code></div>
+                <div><b>Cache Config:</b></div>
+                <div style="padding-top: 5px;"><pre>{{.CacheConfig}}</pre></div>
+            </div>
+        </div>
+
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                Log Configuration
+            </div>
+
+            <div class="panel-body">
+                <div><b>Log Mode:</b> {{.LogMode}}</div>
+                <div><b>Log Config:</b></div>
+                <div style="padding-top: 5px;"><pre>{{.LogConfig}}</pre></div>
+                
             </div>
         </div>
     </div>