Adds website

This commit is contained in:
Manu Mtz-Almeida 2014-06-20 22:38:10 +02:00
parent 15216a0883
commit fdbc5851c5
25 changed files with 5155 additions and 965 deletions

277
README.md
View File

@ -1,277 +0,0 @@
#Gin Web Framework
Gin is a web framework written in Golang. It features a martini-like API with much better performance, up to 40 times faster. If you need performance and good productivity, you will love Gin.
[Check out the official web site](http://gingonic.github.com)
## Start using it
Run:
```
go get github.com/gin-gonic/gin
```
Then import it in your Golang code:
```
import "github.com/gin-gonic/gin"
```
##API Examples
#### Create most basic PING/PONG HTTP endpoint
```
func main() {
// Creates a gin router + logger and recovery (crash-free) middlwares
r := gin.Default()
r.GET("/ping", func(c *gin.Context){
c.String("pong")
})
r.POST("/somePost", posting)
r.PUT("/somePut", putting)
r.DELETE("/someDelete", deleting)
r.PATCH("/somePATCH", patching)
// Listen and server on 0.0.0.0:8080
r.Run(":8080")
}
```
#### Parameters in path
```
func main() {
r := gin.Default()
r.GET("/user/:name", func(c *gin.Context) {
name := c.Params.ByName("name")
message := "Hello "+name
c.String(200, message)
})
}
```
#### Grouping routes
```
func main() {
r := gin.Default()
// Simple group: v1
v1 := r.Group("/v1")
{
v1.POST("/login", loginEndpoint)
v1.POST("/submit", submitEndpoint)
v1.POST("/read", readEndpoint)
}
// Simple group: v1
v2 := r.Group("/v2")
{
v2.POST("/login", loginEndpoint)
v2.POST("/submit"", submitEndpoint)
v2.POST("/read"", readEndpoint)
}
// Listen and server on 0.0.0.0:8080
r.Run(":8080")
}
```
#### Blank Gin without middlewares by default
Use
```
r := gin.New()
```
instead of
```
r := gin.Default()
```
#### Using middlewares
```
func main() {
// Creates a router without any middlware by default
r := gin.New()
// Global middlwares
r.Use(gin.Logger())
r.Use(gin.Recovery())
// Per route middlwares, you can add as many as you desire.
r.GET("/benchmark", MyBenchLogger(), benchEndpoint)
// Authorization group
// authorized := r.Group("/", AuthRequired())
// exactly the same than:
authorized := r.Group("/")
// per group middlwares! in this case we use the custom created
// AuthRequired() middlware just in the "authorized" group.
authorized.Use(AuthRequired())
{
authorized.Use.POST("/login", loginEndpoint)
authorized.Use.POST("/submit", submitEndpoint)
authorized.Use.POST("/read", readEndpoint)
// nested group
testing := authorized.Group("testing")
testing.GET("/analytics", analyticsEndpoint)
}
// Listen and server on 0.0.0.0:8080
r.Run(":8080")
}
```
#### JSON parsing and validation
```
type LoginJSON struct {
User string `json:"user" binding:"required"`
Password string `json:"password" binding:"required"`
}
func main() {
r := gin.Default()
r.POST("/login", func(c *gin.Context) {
var json LoginJSON
// If EnsureBody returns false, it will write automatically the error
// in the HTTP stream and return a 400 error. If you want custom error
// handling you should use: c.ParseBody(interface{}) error
if c.EnsureBody(&json) {
if json.User=="manu" && json.Password=="123" {
c.JSON(200, gin.H{"status": "you are logged in"})
}else{
c.JSON(401, gin.H{"status": "unauthorized"})
}
}
})
}
```
#### XML, and JSON rendering
```
func main() {
r := gin.Default()
// gin.H is a shortcup for map[string]interface{}
r.GET("/someJSON", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "hey", "status": 200})
})
r.GET("/moreJSON", func(c *gin.Context) {
// You also can use a struct
var msg struct {
Message string
Status int
}
msg.Message = "hey"
msg.Status = 200
c.JSON(200, msg.Status)
})
r.GET("/someXML", func(c *gin.Context) {
c.XML(200, gin.H{"message": "hey", "status": 200})
})
}
```
####HTML rendering
Using LoadHTMLTemplates()
```
func main() {
r := gin.Default()
r.LoadHTMLTemplates("templates/*")
r.GET("index", func(c *gin.Context) {
obj := gin.h{"title": "Main website"}
c.HTML(200, "templates/index.tmpl", obj)
})
}
```
You can also use your own html template render
```
import "html/template"
func main() {
r := gin.Default()
html := template.ParseFiles("file1", "file2")
r.HTMLTemplates = html
}
```
#### Custom Middlewares
```
func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
t : time.Now()
// Set example variable
c.Set("example", "12345")
// before request
c.Next()
// after request
latency := time.Since(t)
log.Print(latency)
}
}
func main() {
r := gin.New()
r.Use(Logger())
r.GET("test", func(c *gin.Context){
example := r.Get("example").(string)
// it would print: "12345"
log.Println(example)
})
```
#### Custom HTTP configuration
Do not use the `Run()` method, instead use this:
```
func main() {
router := gin.Default()
http.ListenAndServe(":8080", router)
}
```
or
```
func main() {
router := gin.Default()
s := &http.Server{
Addr: ":8080",
Handler: router,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
s.ListenAndServe()
}
```

83
auth.go
View File

@ -1,83 +0,0 @@
package gin
import (
"crypto/subtle"
"encoding/base64"
"errors"
"sort"
)
type (
BasicAuthPair struct {
Code string
User string
}
Account struct {
User string
Password string
}
Accounts []Account
Pairs []BasicAuthPair
)
func (a Pairs) Len() int { return len(a) }
func (a Pairs) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a Pairs) Less(i, j int) bool { return a[i].Code < a[j].Code }
func processCredentials(accounts Accounts) (Pairs, error) {
if len(accounts) == 0 {
return nil, errors.New("Empty list of authorized credentials.")
}
pairs := make(Pairs, 0, len(accounts))
for _, account := range accounts {
if len(account.User) == 0 || len(account.Password) == 0 {
return nil, errors.New("User or password is empty")
}
base := account.User + ":" + account.Password
code := "Basic " + base64.StdEncoding.EncodeToString([]byte(base))
pairs = append(pairs, BasicAuthPair{code, account.User})
}
// We have to sort the credentials in order to use bsearch later.
sort.Sort(pairs)
return pairs, nil
}
func searchCredential(pairs Pairs, auth string) string {
if len(auth) == 0 {
return ""
}
// Search user in the slice of allowed credentials
r := sort.Search(len(pairs), func(i int) bool { return pairs[i].Code >= auth })
if r < len(pairs) && subtle.ConstantTimeCompare([]byte(pairs[r].Code), []byte(auth)) == 1 {
// user is allowed, set UserId to key "user" in this context, the userId can be read later using
// c.Get("user"
return pairs[r].User
} else {
return ""
}
}
// Implements a basic Basic HTTP Authorization. It takes as argument a map[string]string where
// the key is the user name and the value is the password.
func BasicAuth(accounts Accounts) HandlerFunc {
pairs, err := processCredentials(accounts)
if err != nil {
panic(err)
}
return func(c *Context) {
// Search user in the slice of allowed credentials
user := searchCredential(pairs, c.Req.Header.Get("Authorization"))
if len(user) == 0 {
// Credentials doesn't match, we return 401 Unauthorized and abort request.
c.Writer.Header().Set("WWW-Authenticate", "Basic realm=\"Authorization Required\"")
c.Fail(401, errors.New("Unauthorized"))
} else {
// user is allowed, set UserId to key "user" in this context, the userId can be read later using
// c.Get("user")
c.Set("user", user)
}
}
}

607
css/gin.webflow.css Executable file
View File

@ -0,0 +1,607 @@
body {
background-color: #dbdbdb;
font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;
color: #333;
font-size: 12px;
line-height: 20px;
}
h1 {
margin: 10px 0px;
font-size: 38px;
line-height: 44px;
font-weight: 700;
}
h2 {
margin: 10px 0px;
font-size: 32px;
line-height: 36px;
font-weight: 700;
}
h3 {
margin: 10px 0px 1px;
font-family: Montserrat, sans-serif;
font-size: 21px;
line-height: 30px;
font-weight: 400;
}
h4 {
margin: 10px 0px;
font-size: 18px;
line-height: 24px;
font-weight: 700;
}
h5 {
margin: 10px 0px;
font-size: 14px;
line-height: 20px;
font-weight: 700;
}
h6 {
margin: 10px 0px;
font-size: 12px;
line-height: 18px;
font-weight: 700;
}
p {
margin-bottom: 26px;
font-family:'Varela Round', sans-serif;
color: #848999;
font-size: 14px;
}
.button {
display: inline-block;
width: 180px;
margin-right: 8px;
margin-left: 8px;
padding: 14px 29px;
border-radius: 5px;
background-color: #6d7280;
-webkit-transition: background-color 300ms ease;
-o-transition: background-color 300ms ease;
transition: background-color 300ms ease;
font-family: Montserrat, sans-serif;
color: white;
font-size: 14px;
text-align: center;
text-decoration: none;
text-transform: uppercase;
}
.button:hover {
background-color: #848a9c;
}
.button.nav {
margin-left: 18px;
-webkit-transition: all 200ms ease;
-o-transition: all 200ms ease;
transition: all 200ms ease;
}
.button.nav:hover {
background-color: #9299ad;
}
.button.big-green {
margin-top: 191px;
padding: 25px 22px;
background-color: #32ac97;
-webkit-transition: all 200ms ease;
-o-transition: all 200ms ease;
transition: all 200ms ease;
font-size: 29px;
text-transform: capitalize;
}
.button.big-green:hover {
background-color: #258575;
}
.button.sign-up {
width: 180px;
background-color: #2c9986;
}
.button.sign-up:hover {
background-color: #33b59f;
}
.button.sentrybutton {
display: inline-block;
width: 315px;
margin-right: 0px;
margin-bottom: 26px;
margin-left: 0px;
background-image: url('../images/sentry2.png');
background-position: 50% 50%;
background-size: cover;
font-size: 22px;
line-height: 28px;
}
.button.sentrybutton:hover {
width: 315px;
background-image: -webkit-radial-gradient(circle at 38% 56%, rgba(255, 255, 255, 0), rgba(242, 134, 27, 0.81)), url('../images/sentry2.png');
background-image: -o-radial-gradient(circle at 38% 56%, rgba(255, 255, 255, 0), rgba(242, 134, 27, 0.81)), url('../images/sentry2.png');
background-image: radial-gradient(circle at 38% 56%, rgba(255, 255, 255, 0), rgba(242, 134, 27, 0.81)), url('../images/sentry2.png');
background-position: 0% 0%, 50% 50%;
background-size: auto, cover;
text-decoration: underline;
}
.section {
margin-top: 4px;
padding-top: 65px;
padding-bottom: 65px;
background-color: white;
}
.section.header {
padding-top: 22px;
padding-bottom: 22px;
background-color: #262933;
}
.section.hero {
width: auto;
height: 427px;
margin-top: 4px;
padding-top: 139px;
padding-right: 32%;
padding-bottom: 0px;
background-image: url('../images/gin.jpg');
background-position: 50% 50%;
background-size: cover;
background-repeat: no-repeat;
text-align: center;
}
.section.grey {
background-color: #eff1f4;
text-align: center;
}
.section.centered {
text-align: center;
}
.section.footer {
background-color: #363b48;
text-align: left;
}
.company {
margin-top: 11px;
float: left;
font-family: Montserrat, sans-serif;
color: white;
font-size: 28px;
font-weight: 400;
}
.nav-link {
margin-right: 11px;
margin-left: 11px;
-webkit-transition: color 300ms ease, background-color 300ms ease;
-o-transition: color 300ms ease, background-color 300ms ease;
transition: color 300ms ease, background-color 300ms ease;
font-family: Montserrat, sans-serif;
color: rgba(255, 255, 255, 0.81);
font-size: 14px;
text-decoration: none;
text-transform: uppercase;
}
.nav-link:hover {
color: white;
}
.nav-link.sign-up {
padding: 10px 20px;
border-radius: 5px;
background-color: #2c9986;
}
.nav-link.sign-up:hover {
background-color: #3ac2ab;
}
.nav-column {
padding-top: 10px;
text-align: right;
}
.logo {
margin-right: 11px;
float: left;
}
.hero-heading {
margin-bottom: 25px;
float: none;
border-radius: 0px;
font-family:'Great Vibes', cursive;
color: white;
font-size: 70px;
font-style: normal;
font-weight: 400;
text-decoration: none;
text-transform: none;
list-style-type: none;
text-shadow: none;
}
.hero-subhead {
color: #a3a8b6;
font-size: 14px;
}
.section-title {
font-family: Montserrat, sans-serif;
font-size: 31px;
font-weight: 400;
text-align: center;
}
.section-subtitle {
margin-bottom: 39px;
color: #848999;
text-align: center;
}
.responsive-img {
display: block;
margin-right: auto;
margin-left: auto;
}
.grey-icon {
margin-right: 9px;
}
.content-column {
padding-top: 79px;
text-align: left;
}
.circle {
height: 317px;
margin-bottom: 26px;
padding-top: 21px;
border-radius: 190px;
background-color: #f7f8fa;
}
.number {
display: block;
width: auto;
height: 40px;
margin-right: auto;
margin-bottom: 17px;
margin-left: auto;
padding-top: 10px;
border-radius: 50px;
background-color: #363b48;
font-family: Montserrat, sans-serif;
color: white;
font-size: 20px;
}
.icons {
display: inline-block;
width: 50px;
height: 50px;
margin-top: 30px;
padding-top: 14px;
border-radius: 40px;
background-color: #eff1f4;
font-size: 20px;
font-weight: 700;
}
.quote-box {
padding: 34px 40px 34px 98px;
border-radius: 8px;
background-color: white;
background-image: url('../images/12-quotes.png');
background-position: 8% 22%;
background-size: 50px;
background-repeat: no-repeat;
text-align: left;
}
.quote {
color: #2d303b;
font-size: 15px;
line-height: 24px;
}
.quote-thingy {
display: block;
margin-top: -2px;
margin-right: auto;
margin-left: 45px;
}
.by-section {
text-align: left;
}
.person-icon {
margin-right: 15px;
float: left;
}
.location {
font-family: Varela;
color: #848999;
font-size: 15px;
}
.logo-bottom {
margin-right: 14px;
float: left;
}
.footer-text {
display: inline-block;
margin-top: 11px;
font-family: Montserrat, sans-serif;
color: #7d8391;
font-size: 15px;
text-decoration: none;
}
.social-icon {
width: 40px;
height: 40px;
margin-right: 7px;
margin-left: 7px;
padding-top: 5px;
padding-right: 0px;
border-radius: 40px;
background-color: #596073;
-webkit-transition: all 200ms ease;
-o-transition: all 200ms ease;
transition: all 200ms ease;
text-align: center;
}
.social-icon:hover {
background-color: #7f89a3;
}
.right-footer-col {
text-align: right;
}
.nav-bar {
padding-top: 0px;
padding-bottom: 4px;
background-color: #d6d6d6;
}
.image-crop {
overflow-x: hidden;
overflow-y: hidden;
height: 302px;
box-shadow: red 0px -11px 0px 0px inset;
-webkit-transition: height 300ms ease;
-o-transition: height 300ms ease;
transition: height 300ms ease;
}
.image-crop:hover {
height: 372px;
}
.button-group {
position: static;
margin-top: 26px;
float: none;
}
.center {
text-align: center;
}
.presenting {
padding-right: 0px;
}
.graph-image {
display: inline-block;
}
.graph-block {
display: block;
overflow-x: visible;
overflow-y: visible;
margin-right: auto;
margin-left: auto;
float: none;
text-align: center;
}
.goget {
margin-top: 26px;
}
.goget-text {
padding: 4px 14px;
border-radius: 5px;
background-color: rgba(105, 105, 105, 0.65);
font-family:'Open Sans', sans-serif;
color: white;
}
.footgraph {
margin-top: 22px;
}
.sentry-block {
display: block;
width: 319px;
margin: 17px auto 10px;
padding: 20px 25px;
float: none;
border-radius: 8px;
background-image: url('../images/sentry2.png');
background-position: 50% 50%;
background-size: cover;
font-family: Vollkorn, serif;
color: white;
font-size: 28px;
line-height: 33px;
font-weight: 400;
text-align: center;
}
.samples {
top: -6px;
}
.sliderexamples {
width: auto;
height: 558px;
background-color: #272822;
}
html.w-mod-js.w-mod-no-ios *[data-ix="slicefromleft"] {
opacity: 0;
-webkit-transform: translate(-100px, 0px);
-ms-transform: translate(-100px, 0px);
-o-transform: translate(-100px, 0px);
transform: translate(-100px, 0px);
}
html.w-mod-js *[data-ix="fadein"] {
opacity: 0;
-webkit-transform: scale(0.5) rotate(-25deg);
-ms-transform: scale(0.5) rotate(-25deg);
-o-transform: scale(0.5) rotate(-25deg);
transform: scale(0.5) rotate(-25deg);
}
html.w-mod-js.w-mod-no-ios *[data-ix="slicefromright"] {
opacity: 0;
-webkit-transform: translate(100px, 0px);
-ms-transform: translate(100px, 0px);
-o-transform: translate(100px, 0px);
transform: translate(100px, 0px);
}
@media (max-width: 991px) {
.button.nav {
margin-left: 11px;
padding-right: 10px;
padding-left: 10px;
}
.button.big-green {
margin-top: 148px;
}
.section.hero {
padding-right: 36%;
}
.nav-link {
margin-right: 7px;
margin-left: 7px;
font-size: 13px;
}
.hero-heading {
text-shadow: none;
}
.grey-icon {
margin-top: 19px;
}
.content-column {
padding-top: 0px;
}
.circle {
height: 293px;
}
.frames {
width: 75%;
}
}
@media (max-width: 767px) {
.button {
margin-bottom: 10px;
}
.button.nav {
display: block;
width: 60%;
margin: 23px auto 17px;
}
.button.big-green {
margin-top: 86px;
margin-bottom: 62px;
}
.section {
padding: 32px 15px;
}
.section.hero {
padding-top: 91px;
}
.section.footer {
text-align: center;
}
.company {
display: inline-block;
float: none;
}
.nav-column {
padding-top: 19px;
text-align: center;
}
.logo {
margin-top: -14px;
float: none;
}
.company-column {
margin-top: 35px;
margin-bottom: 23px;
text-align: center;
}
.hero-heading {
margin-bottom: 26px;
font-size: 65px;
line-height: 34px;
text-shadow: none;
}
.grey-icon {
margin-top: 28px;
}
.content-column {
padding-left: 0px;
}
.circle {
display: inline-block;
height: auto;
border-radius: 10px;
}
.frames {
width: 55%;
margin-bottom: 19px;
}
.number {
margin-bottom: 20px;
}
.quote-box {
background-image: url('../images/12-quotes.png');
}
.by-section.first {
margin-bottom: 35px;
}
.logo-bottom {
margin-right: -1px;
margin-bottom: 37px;
float: none;
}
.footer-text {
margin-bottom: 22px;
}
.social-icon.first {
margin-left: 1px;
}
.right-footer-col {
text-align: center;
}
.brand-column {
text-align: center;
}
}
@media (max-width: 479px) {
.button {
display: block;
}
.button.nav {
width: 80%;
}
.button.big-green {
margin-top: 0px;
margin-right: 16px;
margin-left: 16px;
}
.button.sentrybutton {
display: inline-block;
width: 100%;
font-size: 19px;
}
.button.sentrybutton:hover {
width: 100%;
}
.section {
padding-right: 11px;
}
.section.hero {
padding-top: 85px;
padding-right: 15px;
padding-left: 15px;
}
.nav-link {
display: block;
padding-top: 8px;
padding-bottom: 8px;
}
.hero-heading {
margin-top: 0px;
text-shadow: none;
}
.hero-subhead {
margin-bottom: 34px;
}
.grey-icon {
margin-top: 34px;
}
.content-column {
text-align: center;
}
.frames {
width: 75%;
}
.quote-box {
padding-left: 75px;
background-image: url('../images/12-quotes.png');
background-position: 8% 17%;
}
}

356
css/normalize.css vendored Executable file
View File

@ -0,0 +1,356 @@
/*! normalize.css v2.1.3 | MIT License | git.io/normalize */
/* ==========================================================================
HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined in IE 8/9.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
display: block;
}
/**
* Correct `inline-block` display not defined in IE 8/9.
*/
audio,
canvas,
video {
display: inline-block;
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address `[hidden]` styling not present in IE 8/9.
* Hide the `template` element in IE, Safari, and Firefox < 22.
*/
[hidden],
template {
display: none;
}
/* ==========================================================================
Base
========================================================================== */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS text size adjust after orientation change, without disabling
* user zoom.
*/
html {
font-family: sans-serif;
/* 1 */
-ms-text-size-adjust: 100%;
/* 2 */
-webkit-text-size-adjust: 100%;
/* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* ==========================================================================
Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background: transparent;
}
/**
* Address `outline` inconsistency between Chrome and other browsers.
*/
a:focus {
outline: thin dotted;
}
/**
* Improve readability when focused and also mouse hovered in all browsers.
*/
a:active,
a:hover {
outline: 0;
}
/* ==========================================================================
Typography
========================================================================== */
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari 5, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9, Safari 5, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/**
* Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
*/
b,
strong {
font-weight: bold;
}
/**
* Address styling not present in Safari 5 and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address differences between Firefox and other browsers.
*/
hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
/**
* Address styling not present in IE 8/9.
*/
mark {
background: #ff0;
color: #000;
}
/**
* Correct font family set oddly in Safari 5 and Chrome.
*/
code,
kbd,
pre,
samp {
font-family: monospace, serif;
font-size: 1em;
}
/**
* Improve readability of pre-formatted text in all browsers.
*/
pre {
white-space: pre-wrap;
}
/**
* Set consistent quote types.
*/
q {
quotes: "\201C" "\201D" "\2018" "\2019";
}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* ==========================================================================
Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9.
*/
img {
border: 0;
}
/**
* Correct overflow displayed oddly in IE 9.
*/
svg:not(:root) {
overflow: hidden;
}
/* ==========================================================================
Figures
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari 5.
*/
figure {
margin: 0;
}
/* ==========================================================================
Forms
========================================================================== */
/**
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct `color` not being inherited in IE 8/9.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0;
/* 1 */
padding: 0;
/* 2 */
}
/**
* 1. Correct font family not being inherited in all browsers.
* 2. Correct font size not being inherited in all browsers.
* 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
*/
button,
input,
select,
textarea {
font-family: inherit;
/* 1 */
font-size: 100%;
/* 2 */
margin: 0;
/* 3 */
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
button,
input {
line-height: normal;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
* Correct `select` style inheritance in Firefox 4+ and Opera.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
html input[type="button"],
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button;
/* 2 */
cursor: pointer;
/* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box;
/* 1 */
padding: 0;
/* 2 */
}
/**
* 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
* (include `-moz` to future-proof).
*/
input[type="search"] {
-webkit-appearance: textfield;
/* 1 */
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box;
/* 2 */
box-sizing: content-box;
}
/**
* Remove inner padding and search cancel button in Safari 5 and Chrome
* on OS X.
*/
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* 1. Remove default vertical scrollbar in IE 8/9.
* 2. Improve readability and alignment in all browsers.
*/
textarea {
overflow: auto;
/* 1 */
vertical-align: top;
/* 2 */
}
/* ==========================================================================
Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}

1225
css/webflow.css Executable file

File diff suppressed because it is too large Load Diff

View File

@ -1,55 +0,0 @@
package main
import (
"github.com/gin-gonic/gin"
)
var DB = make(map[string]string)
func main() {
r := gin.Default()
// Ping test
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
// Get user value
r.GET("/user/:name", func(c *gin.Context) {
user := c.Params.ByName("name")
value, ok := DB[user]
if ok {
c.JSON(200, gin.H{"user": user, "value": value})
} else {
c.JSON(200, gin.H{"user": user, "status": "no value"})
}
})
// Authorized group (uses gin.BasicAuth() middleware)
// Same than:
// authorized := r.Group("/")
// authorized.Use(gin.BasicAuth(gin.Credentials{
// "foo": "bar",
// "manu": "123",
//}))
authorized := r.Group("/", gin.BasicAuth(gin.Accounts{
{"foo", "bar"}, //1. user:foo password:bar
{"manu", "123"}, //2. user:manu password:123
}))
authorized.POST("admin", func(c *gin.Context) {
user := c.Get("user").(string)
// Parse JSON
var json struct {
Value string `json:"value" binding:"required"`
}
if c.EnsureBody(&json) {
DB[user] = json.Value
c.JSON(200, gin.H{"status": "ok"})
}
})
// Listen and Server in 0.0.0.0:8080
r.Run(":8081")
}

377
gin.go
View File

@ -1,377 +0,0 @@
package gin
import (
"encoding/json"
"encoding/xml"
"github.com/julienschmidt/httprouter"
"html/template"
"log"
"math"
"net/http"
"path"
)
const (
AbortIndex = math.MaxInt8 / 2
)
type (
HandlerFunc func(*Context)
H map[string]interface{}
// Used internally to collect a error ocurred during a http request.
ErrorMsg struct {
Message string `json:"msg"`
Meta interface{} `json:"meta"`
}
ResponseWriter interface {
http.ResponseWriter
Status() int
Written() bool
}
responseWriter struct {
http.ResponseWriter
status int
}
// Context is the most important part of gin. It allows us to pass variables between middleware,
// manage the flow, validate the JSON of a request and render a JSON response for example.
Context struct {
Req *http.Request
Writer ResponseWriter
Keys map[string]interface{}
Errors []ErrorMsg
Params httprouter.Params
handlers []HandlerFunc
engine *Engine
index int8
}
// Used internally to configure router, a RouterGroup is associated with a prefix
// and an array of handlers (middlewares)
RouterGroup struct {
Handlers []HandlerFunc
prefix string
parent *RouterGroup
engine *Engine
}
// Represents the web framework, it wrappers the blazing fast httprouter multiplexer and a list of global middlewares.
Engine struct {
*RouterGroup
handlers404 []HandlerFunc
router *httprouter.Router
HTMLTemplates *template.Template
}
)
func (rw *responseWriter) WriteHeader(s int) {
rw.ResponseWriter.WriteHeader(s)
rw.status = s
}
func (rw *responseWriter) Write(b []byte) (int, error) {
return rw.ResponseWriter.Write(b)
}
func (rw *responseWriter) Status() int {
return rw.status
}
func (rw *responseWriter) Written() bool {
return rw.status != 0
}
// Returns a new blank Engine instance without any middleware attached.
// The most basic configuration
func New() *Engine {
engine := &Engine{}
engine.RouterGroup = &RouterGroup{nil, "/", nil, engine}
engine.router = httprouter.New()
engine.router.NotFound = engine.handle404
return engine
}
// Returns a Engine instance with the Logger and Recovery already attached.
func Default() *Engine {
engine := New()
engine.Use(Recovery(), Logger())
return engine
}
func (engine *Engine) LoadHTMLTemplates(pattern string) {
engine.HTMLTemplates = template.Must(template.ParseGlob(pattern))
}
// Adds handlers for NotFound. It return a 404 code by default.
func (engine *Engine) NotFound404(handlers ...HandlerFunc) {
engine.handlers404 = handlers
}
func (engine *Engine) handle404(w http.ResponseWriter, req *http.Request) {
handlers := engine.allHandlers(engine.handlers404)
c := engine.createContext(w, req, nil, handlers)
c.Next()
if !c.Writer.Written() {
http.NotFound(c.Writer, c.Req)
}
}
// ServeFiles serves files from the given file system root.
// The path must end with "/*filepath", files are then served from the local
// path /defined/root/dir/*filepath.
// For example if root is "/etc" and *filepath is "passwd", the local file
// "/etc/passwd" would be served.
// Internally a http.FileServer is used, therefore http.NotFound is used instead
// of the Router's NotFound handler.
// To use the operating system's file system implementation,
// use http.Dir:
// router.ServeFiles("/src/*filepath", http.Dir("/var/www"))
func (engine *Engine) ServeFiles(path string, root http.FileSystem) {
engine.router.ServeFiles(path, root)
}
// ServeHTTP makes the router implement the http.Handler interface.
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
engine.router.ServeHTTP(w, req)
}
func (engine *Engine) Run(addr string) {
http.ListenAndServe(addr, engine)
}
/************************************/
/********** ROUTES GROUPING *********/
/************************************/
func (group *RouterGroup) createContext(w http.ResponseWriter, req *http.Request, params httprouter.Params, handlers []HandlerFunc) *Context {
return &Context{
Writer: &responseWriter{w, 0},
Req: req,
index: -1,
engine: group.engine,
Params: params,
handlers: handlers,
}
}
// Adds middlewares to the group, see example code in github.
func (group *RouterGroup) Use(middlewares ...HandlerFunc) {
group.Handlers = append(group.Handlers, middlewares...)
}
// Greates a new router group. You should create add all the routes that share that have common middlwares or same path prefix.
// For example, all the routes that use a common middlware for authorization could be grouped.
func (group *RouterGroup) Group(component string, handlers ...HandlerFunc) *RouterGroup {
prefix := path.Join(group.prefix, component)
return &RouterGroup{
Handlers: handlers,
parent: group,
prefix: prefix,
engine: group.engine,
}
}
// Handle registers a new request handle and middlewares with the given path and method.
// The last handler should be the real handler, the other ones should be middlewares that can and should be shared among different routes.
// See the example code in github.
//
// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut
// functions can be used.
//
// This function is intended for bulk loading and to allow the usage of less
// frequently used, non-standardized or custom methods (e.g. for internal
// communication with a proxy).
func (group *RouterGroup) Handle(method, p string, handlers []HandlerFunc) {
p = path.Join(group.prefix, p)
handlers = group.allHandlers(handlers)
group.engine.router.Handle(method, p, func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
group.createContext(w, req, params, handlers).Next()
})
}
// POST is a shortcut for router.Handle("POST", path, handle)
func (group *RouterGroup) POST(path string, handlers ...HandlerFunc) {
group.Handle("POST", path, handlers)
}
// GET is a shortcut for router.Handle("GET", path, handle)
func (group *RouterGroup) GET(path string, handlers ...HandlerFunc) {
group.Handle("GET", path, handlers)
}
// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func (group *RouterGroup) DELETE(path string, handlers ...HandlerFunc) {
group.Handle("DELETE", path, handlers)
}
// PATCH is a shortcut for router.Handle("PATCH", path, handle)
func (group *RouterGroup) PATCH(path string, handlers ...HandlerFunc) {
group.Handle("PATCH", path, handlers)
}
// PUT is a shortcut for router.Handle("PUT", path, handle)
func (group *RouterGroup) PUT(path string, handlers ...HandlerFunc) {
group.Handle("PUT", path, handlers)
}
func (group *RouterGroup) allHandlers(handlers []HandlerFunc) []HandlerFunc {
local := append(group.Handlers, handlers...)
if group.parent != nil {
return group.parent.allHandlers(local)
} else {
return local
}
}
/************************************/
/****** FLOW AND ERROR MANAGEMENT****/
/************************************/
// Next should be used only in the middlewares.
// It executes the pending handlers in the chain inside the calling handler.
// See example in github.
func (c *Context) Next() {
c.index++
s := int8(len(c.handlers))
for ; c.index < s; c.index++ {
c.handlers[c.index](c)
}
}
// Forces the system to do not continue calling the pending handlers.
// For example, the first handler checks if the request is authorized. If it's not, context.Abort(401) should be called.
// The rest of pending handlers would never be called for that request.
func (c *Context) Abort(code int) {
c.Writer.WriteHeader(code)
c.index = AbortIndex
}
// Fail is the same than Abort plus an error message.
// Calling `context.Fail(500, err)` is equivalent to:
// ```
// context.Error("Operation aborted", err)
// context.Abort(500)
// ```
func (c *Context) Fail(code int, err error) {
c.Error(err, "Operation aborted")
c.Abort(code)
}
// Attachs an error to the current context. The error is pushed to a list of errors.
// It's a gooc idea to call Error for each error ocurred during the resolution of a request.
// A middleware can be used to collect all the errors and push them to a database together, print a log, or append it in the HTTP response.
func (c *Context) Error(err error, meta interface{}) {
c.Errors = append(c.Errors, ErrorMsg{
Message: err.Error(),
Meta: meta,
})
}
/************************************/
/******** METADATA MANAGEMENT********/
/************************************/
// Sets a new pair key/value just for the specefied context.
// It also lazy initializes the hashmap
func (c *Context) Set(key string, item interface{}) {
if c.Keys == nil {
c.Keys = make(map[string]interface{})
}
c.Keys[key] = item
}
// Returns the value for the given key.
// It panics if the value doesn't exist.
func (c *Context) Get(key string) interface{} {
var ok bool
var item interface{}
if c.Keys != nil {
item, ok = c.Keys[key]
} else {
item, ok = nil, false
}
if !ok || item == nil {
log.Panicf("Key %s doesn't exist", key)
}
return item
}
/************************************/
/******** ENCOGING MANAGEMENT********/
/************************************/
// Like ParseBody() but this method also writes a 400 error if the json is not valid.
func (c *Context) EnsureBody(item interface{}) bool {
if err := c.ParseBody(item); err != nil {
c.Fail(400, err)
return false
}
return true
}
// Parses the body content as a JSON input. It decodes the json payload into the struct specified as a pointer.
func (c *Context) ParseBody(item interface{}) error {
decoder := json.NewDecoder(c.Req.Body)
if err := decoder.Decode(&item); err == nil {
return Validate(c, item)
} else {
return err
}
}
// Serializes the given struct as a JSON into the response body in a fast and efficient way.
// It also sets the Content-Type as "application/json"
func (c *Context) JSON(code int, obj interface{}) {
c.Writer.WriteHeader(code)
c.Writer.Header().Set("Content-Type", "application/json")
encoder := json.NewEncoder(c.Writer)
if err := encoder.Encode(obj); err != nil {
c.Error(err, obj)
http.Error(c.Writer, err.Error(), 500)
}
}
// Serializes the given struct as a XML into the response body in a fast and efficient way.
// It also sets the Content-Type as "application/xml"
func (c *Context) XML(code int, obj interface{}) {
c.Writer.WriteHeader(code)
c.Writer.Header().Set("Content-Type", "application/xml")
encoder := xml.NewEncoder(c.Writer)
if err := encoder.Encode(obj); err != nil {
c.Error(err, obj)
http.Error(c.Writer, err.Error(), 500)
}
}
// Renders the HTTP template specified by his file name.
// It also update the HTTP code and sets the Content-Type as "text/html".
// See http://golang.org/doc/articles/wiki/
func (c *Context) HTML(code int, name string, data interface{}) {
c.Writer.WriteHeader(code)
c.Writer.Header().Set("Content-Type", "text/html")
if err := c.engine.HTMLTemplates.ExecuteTemplate(c.Writer, name, data); err != nil {
c.Error(err, map[string]interface{}{
"name": name,
"data": data,
})
http.Error(c.Writer, err.Error(), 500)
}
}
// Writes the given string into the response body and sets the Content-Type to "text/plain"
func (c *Context) String(code int, msg string) {
c.Writer.Header().Set("Content-Type", "text/plain")
c.Writer.WriteHeader(code)
c.Writer.Write([]byte(msg))
}
// Writes some data into the body stream and updates the HTTP code
func (c *Context) Data(code int, data []byte) {
c.Writer.WriteHeader(code)
c.Writer.Write(data)
}

BIN
images/12-quotes.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
images/Git-Icon-Black2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
images/email.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
images/gin.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
images/globe2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
images/graph.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
images/idea2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
images/pull2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
images/sample1.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
images/sample11.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
images/sentry2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
images/webclip-gallio.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

184
index.html Executable file
View File

@ -0,0 +1,184 @@
<!DOCTYPE html>
<!-- This site was created in Webflow. http://www.webflow.com-->
<!-- Last Published: Fri Jun 20 2014 17:48:26 GMT+0000 (UTC) -->
<html data-wf-site="539b89a7a7990e780bfd7c67">
<head>
<meta charset="utf-8">
<title>Gin Web Framework</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content="Webflow">
<link rel="stylesheet" type="text/css" href="css/normalize.css">
<link rel="stylesheet" type="text/css" href="css/webflow.css">
<link rel="stylesheet" type="text/css" href="css/gin.webflow.css">
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.4.7/webfont.js"></script>
<script>
WebFont.load({
google: {
families: ["Montserrat:400,700","Varela Round:400","Great Vibes:400","Varela:400","Open Sans:300,300italic,400,400italic,600,600italic,700,700italic,800,800italic","Vollkorn:400,400italic,700,700italic"]
}
});
</script>
<script type="text/javascript" src="js/modernizr.js"></script>
<link rel="shortcut icon" type="image/x-icon" href="https://y7v4p6k4.ssl.hwcdn.net/placeholder/favicon.ico">
<link rel="apple-touch-icon" href="images/webclip-gallio.png">
</head>
<body>
<div class="section hero">
<div class="w-container presenting" data-ix="fadein">
<h1 class="hero-heading">Gin Gonic</h1>
<p class="hero-subhead">Fastest full-featured web framework for Golang. <strong>Crystal clear.</strong>
</p>
<div class="button-group"><a class="button sign-up" href="https://github.com/gin-gonic/gin" data-ix="shaking">github pagE</a><a class="button" href="http://godoc.org/github.com/gin-gonic/gin">API REFERENCE</a>
<p class="goget"><span class="goget-text">go get github.com/gin-gonic/gin</span>
</p>
</div>
</div>
</div>
<div class="section" id="mobile">
<div class="w-container">
<h2 class="section-title">Performance and productivity can work together</h2>
<p class="section-subtitle">Gin is a web framework written in Golang. It features a martini-like API with much better performance, up to 40 times faster. If you need performance and good productivity, you will love Gin.</p>
<div class="graph-block">
<img class="graph-image" src="images/graph.png" alt="Martini vs Gin" width="827">
<p class="footgraph"><a href="https://github.com/gin-gonic/go-http-routing-benchmark">Run the tests by yourself</a>
</p>
</div>
</div>
</div>
<div class="section grey" id="features">
<div class="w-container" data-ix="slicefromleft">
<h2 class="section-title">Low Overhead Powerful API</h2>
<p class="section-subtitle">You can add global, per-group, and per-route middlewares, thousands of nested groups, nice JSON validation and rendering. And the performance will be still&nbsp;great!&nbsp;Gin uses <strong>httprouter</strong> internally, the fastest HTTP router for
Golang. Httprouter was created by&nbsp;<em>Julien Schmidt</em> and its based in a <a href="http://en.wikipedia.org/wiki/Radix_tree">Radix Tree</a>&nbsp;algorithm. This explains the good performance and scalability of Gin.</p>
<div class="w-row">
<div class="w-col w-col-6">
<h3>Some cool middlewares</h3>
<p>If you used Martini before, Gin will be familiar to you. If you dont, you will need 10 minutes to learn everything.</p><a class="button sentrybutton" href="https://github.com/gin-gonic/gin-sentry">Check out the<br>Sentry midDlEware</a>
<p>More coming soon!</p>
</div>
<div class="w-col w-col-6">
<h3>Crystal Clear</h3>
<p>If you used Martini before, Gin will be familiar to you. If you dont, you will need 10 minutes to learn everything.</p>
<div class="w-slider sliderexamples" data-animation="slide" data-duration="500" data-infinite="1" data-hide-arrows="1">
<div class="w-slider-mask">
<div class="w-slide">
<img src="images/sample1.png" width="550" alt="539f93b8f281585418675d91_sample1.png">
</div>
<div class="w-slide">
<img src="images/sample11.png" width="550" alt="539f93ccf281585418675d92_sample11.png">
</div>
</div>
<div class="w-slider-arrow-left">
<div class="w-icon-slider-left"></div>
</div>
<div class="w-slider-arrow-right">
<div class="w-icon-slider-right"></div>
</div>
<div class="w-slider-nav w-round"></div>
</div>
</div>
</div>
</div>
</div>
<div class="section centered">
<div class="w-container" data-ix="slicefromright">
<h2 class="section-title">Full Featured</h2>
<div class="w-row">
<div class="w-col w-col-4 w-col-small-4">
<div class="icons">I</div>
<h3>Fast</h3>
<p>Radix tree based routing, small memory foot print. No reflection.&nbsp;Predictable API performance.&nbsp;</p>
</div>
<div class="w-col w-col-4 w-col-small-4">
<div class="icons">II</div>
<h3>Middleware support</h3>
<p>A incoming HTTP request can by handled by a chain of middlewares and the final action.
<br>For example: Logger, Authorization, GZIP and finally post a message in the DB.</p>
</div>
<div class="w-col w-col-4 w-col-small-4">
<div class="icons">III</div>
<h3>Crash-free</h3>
<p>Gin can catch a panic occurred during a HTTP request and recover it. This way, your server will be always available. Its also possible to report this panic to Sentry for example!</p>
</div>
</div>
<div class="w-row">
<div class="w-col w-col-4 w-col-small-4">
<div class="icons">IV</div>
<h3>JSON validation</h3>
<p>Gin can parse and validate the JSON of a request, checking for example the existence of required values.</p>
</div>
<div class="w-col w-col-4 w-col-small-4">
<div class="icons">V</div>
<h3>Routes grouping</h3>
<p>Organize your routes better. Authorization required vs non required, different API versions... In addition, the groups can be nested unlimitedly without degrading performance!</p>
</div>
<div class="w-col w-col-4 w-col-small-4">
<div class="icons">VI</div>
<h3>Error management</h3>
<p>Gin provides a convenient way to collect all the errors occurred during a HTTP request. Eventually, a middleware can write them to a log file, to a database and send them through the network.</p>
</div>
</div>
<div class="w-row">
<div class="w-col w-col-4 w-col-small-4">
<div class="icons">VII</div>
<h3>Rendering built-in</h3>
<p>Gin provides a easy to use API for JSON, XML and HTML rendering.</p>
</div>
<div class="w-col w-col-4 w-col-small-4">
<div class="icons">VIII</div>
<h3>Extendable</h3>
<p>Creating a new middleware is so easy, just check out the sample codes.</p>
</div>
<div class="w-col w-col-4 w-col-small-4"></div>
</div>
</div>
</div>
<div class="section grey" id="features">
<div class="w-container" data-ix="slicefromleft">
<h2 class="section-title">How to contribute?</h2>
<p class="section-subtitle">Gin uses a MIT license, this means that you can do whatever you want, but please, keep the reference to the original authors! To contribute you should <a href="https://github.com/gin-gonic/gin">fork it in Github</a>, add some changes and start posting
Pull Requests, we would love to merge them.</p>
<div class="w-row">
<div class="w-col w-col-4">
<div class="circle">
<div class="number">1. Fork</div>
<img class="frames" src="images/Git-Icon-Black2.png" width="175" alt="539e4fca30eda3837a903182_Git-Icon-Black2.png">
</div>
</div>
<div class="w-col w-col-4">
<div class="circle">
<div class="number">2. Commit</div>
<img class="frames" src="images/idea2.png" width="134" height="169" alt="539e4fbbaa3db5690ebc0c8c_idea2.png">
</div>
</div>
<div class="w-col w-col-4">
<div class="circle">
<div class="number">3. Pull request</div>
<img class="frames" src="images/pull2.png" width="218" alt="539e4fadaa3db5690ebc0c8b_pull2.png">
</div>
</div>
</div>
</div>
</div>
<footer class="section footer">
<div class="w-container">
<div class="w-row">
<div class="w-col w-col-6">
<div class="footer-text">Gin is developed and maintained by <em>Manu Martinez-Almeida</em>. It uses the fantastic <em>Julien Schmidt</em>s httprouter.</div>
</div>
<div class="w-col w-col-6 right-footer-col">
<a class="w-inline-block social-icon" href="mailto:manu.valladolid@gmail.com">
<img src="images/email.png" width="30" alt="539f9748f281585418675de9_email.png">
</a>
<a class="w-inline-block social-icon" href="http://forzefield.com">
<img src="images/globe2.png" width="30" alt="539f982eb9e5e952181edbc2_globe2.png">
</a>
</div>
</div>
</div>
</footer>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script type="text/javascript" src="js/webflow.js"></script>
<!--[if lte IE 9]><script src="https://cdnjs.cloudflare.com/ajax/libs/placeholders/3.0.2/placeholders.min.js"></script><![endif]-->
</body>
</html>

8
js/modernizr.js Executable file
View File

@ -0,0 +1,8 @@
/* Modernizr 2.7.1 (Custom Build) | MIT & BSD
* Build: http://modernizr.com/download/#-video-touch-shiv-cssclasses-teststyles-prefixes-cssclassprefix:w!mod!
*/
;window.Modernizr=function(a,b,c){function w(a){j.cssText=a}function x(a,b){return w(m.join(a+";")+(b||""))}function y(a,b){return typeof a===b}function z(a,b){return!!~(""+a).indexOf(b)}function A(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:y(f,"function")?f.bind(d||b):f}return!1}var d="2.7.1",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k,l={}.toString,m=" -webkit- -moz- -o- -ms- ".split(" "),n={},o={},p={},q=[],r=q.slice,s,t=function(a,c,d,e){var f,i,j,k,l=b.createElement("div"),m=b.body,n=m||b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:h+(d+1),l.appendChild(j);return f=["&#173;",'<style id="s',h,'">',a,"</style>"].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},u={}.hasOwnProperty,v;!y(u,"undefined")&&!y(u.call,"undefined")?v=function(a,b){return u.call(a,b)}:v=function(a,b){return b in a&&y(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=r.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(r.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(r.call(arguments)))};return e}),n.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:t(["@media (",m.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},n.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c};for(var B in n)v(n,B)&&(s=B.toLowerCase(),e[s]=n[B](),q.push((e[s]?"":"no-")+s));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)v(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" w-mod-"+(b?"":"no-")+a),e[a]=b}return e},w(""),i=k=null,function(a,b){function l(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function m(){var a=s.elements;return typeof a=="string"?a.split(" "):a}function n(a){var b=j[a[h]];return b||(b={},i++,a[h]=i,j[i]=b),b}function o(a,c,d){c||(c=b);if(k)return c.createElement(a);d||(d=n(c));var g;return d.cache[a]?g=d.cache[a].cloneNode():f.test(a)?g=(d.cache[a]=d.createElem(a)).cloneNode():g=d.createElem(a),g.canHaveChildren&&!e.test(a)&&!g.tagUrn?d.frag.appendChild(g):g}function p(a,c){a||(a=b);if(k)return a.createDocumentFragment();c=c||n(a);var d=c.frag.cloneNode(),e=0,f=m(),g=f.length;for(;e<g;e++)d.createElement(f[e]);return d}function q(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return s.shivMethods?o(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/[\w\-]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(s,b.frag)}function r(a){a||(a=b);var c=n(a);return s.shivCSS&&!g&&!c.hasCSS&&(c.hasCSS=!!l(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),k||q(a,c),a}var c="3.7.0",d=a.html5||{},e=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,f=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,g,h="_html5shiv",i=0,j={},k;(function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",g="hidden"in a,k=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){g=!0,k=!0}})();var s={elements:d.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:c,shivCSS:d.shivCSS!==!1,supportsUnknownElements:k,shivMethods:d.shivMethods!==!1,type:"default",shivDocument:r,createElement:o,createDocumentFragment:p};a.html5=s,r(b)}(this,b),e._version=d,e._prefixes=m,e.testStyles=t,g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" w-mod-js w-mod-"+q.join(" w-mod-"):""),e}(this,this.document);
/**
* Webflow: Custom tests
*/
Modernizr.addTest('ios', /(ipod|iphone|ipad)/i.test(navigator.userAgent));

2775
js/webflow.js Executable file

File diff suppressed because one or more lines are too long

View File

@ -1,20 +0,0 @@
package gin
import (
"log"
"time"
)
func Logger() HandlerFunc {
return func(c *Context) {
// Start timer
t := time.Now()
// Process request
c.Next()
// Calculate resolution time
log.Printf("[%d] %s in %v", c.Writer.Status(), c.Req.RequestURI, time.Since(t))
}
}

View File

@ -1,97 +0,0 @@
package gin
import (
"bytes"
"fmt"
"io/ioutil"
"log"
"net/http"
"runtime"
)
var (
dunno = []byte("???")
centerDot = []byte("·")
dot = []byte(".")
slash = []byte("/")
)
// stack returns a nicely formated stack frame, skipping skip frames
func stack(skip int) []byte {
buf := new(bytes.Buffer) // the returned data
// As we loop, we open files and read them. These variables record the currently
// loaded file.
var lines [][]byte
var lastFile string
for i := skip; ; i++ { // Skip the expected number of frames
pc, file, line, ok := runtime.Caller(i)
if !ok {
break
}
// Print this much at least. If we can't find the source, it won't show.
fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
if file != lastFile {
data, err := ioutil.ReadFile(file)
if err != nil {
continue
}
lines = bytes.Split(data, []byte{'\n'})
lastFile = file
}
fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
}
return buf.Bytes()
}
// source returns a space-trimmed slice of the n'th line.
func source(lines [][]byte, n int) []byte {
n-- // in stack trace, lines are 1-indexed but our array is 0-indexed
if n < 0 || n >= len(lines) {
return dunno
}
return bytes.TrimSpace(lines[n])
}
// function returns, if possible, the name of the function containing the PC.
func function(pc uintptr) []byte {
fn := runtime.FuncForPC(pc)
if fn == nil {
return dunno
}
name := []byte(fn.Name())
// The name includes the path name to the package, which is unnecessary
// since the file name is already included. Plus, it has center dots.
// That is, we see
// runtime/debug.*T·ptrmethod
// and want
// *T.ptrmethod
// Also the package path might contains dot (e.g. code.google.com/...),
// so first eliminate the path prefix
if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
name = name[lastslash+1:]
}
if period := bytes.Index(name, dot); period >= 0 {
name = name[period+1:]
}
name = bytes.Replace(name, centerDot, dot, -1)
return name
}
// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
// While Martini is in development mode, Recovery will also output the panic as HTML.
func Recovery() HandlerFunc {
return func(c *Context) {
defer func() {
if len(c.Errors) > 0 {
log.Println(c.Errors)
}
if err := recover(); err != nil {
stack := stack(3)
log.Printf("PANIC: %s\n%s", err, stack)
c.Writer.WriteHeader(http.StatusInternalServerError)
}
}()
c.Next()
}
}

View File

@ -1,56 +0,0 @@
package gin
import (
"errors"
"reflect"
"strings"
)
func (c *Context) ErrorRender() HandlerFunc {
return func(c *Context) {
defer func() {
if len(c.Errors) > 0 {
c.JSON(-1, c.Errors)
}
}()
c.Next()
}
}
func Validate(c *Context, obj interface{}) error {
var err error
typ := reflect.TypeOf(obj)
val := reflect.ValueOf(obj)
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
val = val.Elem()
}
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
fieldValue := val.Field(i).Interface()
zero := reflect.Zero(field.Type).Interface()
// Validate nested and embedded structs (if pointer, only do so if not nil)
if field.Type.Kind() == reflect.Struct ||
(field.Type.Kind() == reflect.Ptr && !reflect.DeepEqual(zero, fieldValue)) {
err = Validate(c, fieldValue)
}
if strings.Index(field.Tag.Get("binding"), "required") > -1 {
if reflect.DeepEqual(zero, fieldValue) {
name := field.Name
if j := field.Tag.Get("json"); j != "" {
name = j
} else if f := field.Tag.Get("form"); f != "" {
name = f
}
err = errors.New("Required " + name)
c.Error(err, "json validation")
}
}
}
return err
}