diff --git a/README.md b/README.md deleted file mode 100644 index f910801f..00000000 --- a/README.md +++ /dev/null @@ -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() -} -``` - - diff --git a/auth.go b/auth.go deleted file mode 100644 index c6a5291a..00000000 --- a/auth.go +++ /dev/null @@ -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) - } - } -} diff --git a/css/gin.webflow.css b/css/gin.webflow.css new file mode 100755 index 00000000..4738ab8b --- /dev/null +++ b/css/gin.webflow.css @@ -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%; + } +} \ No newline at end of file diff --git a/css/normalize.css b/css/normalize.css new file mode 100755 index 00000000..6f39ea80 --- /dev/null +++ b/css/normalize.css @@ -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; +} diff --git a/css/webflow.css b/css/webflow.css new file mode 100755 index 00000000..0d9ee31c --- /dev/null +++ b/css/webflow.css @@ -0,0 +1,1225 @@ +@font-face { + font-family: 'webflow-icons'; + src: url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMg6yAywAAAC8AAAAYGNtYXDmFACHAAABHAAAAERnYXNwAAAAEAAAAWAAAAAIZ2x5Zg0Qb6IAAAFoAAABMGhlYWQARYalAAACmAAAADZoaGVhBwIEhgAAAtAAAAAkaG10eA4AAsAAAAL0AAAAFGxvY2EAPAC2AAADCAAAAAxtYXhwAAkATQAAAxQAAAAgbmFtZXLtdWgAAAM0AAABb3Bvc3QAAwAAAAAEpAAAACAAAwQAAZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAACDmAgPA/8D/wAPAAEAAAAABAAAAAAAAAAAAAAAgAAAAAAACAAAAAwAAABQAAwABAAAAFAAEADAAAAAIAAgAAgAAACDmAv/9//8AAAAg5gD//f///+EaAgADAAEAAAAAAAAAAAABAAH//wAPAAEAAAAAAAAAAAACAAA3OQEAAAAAAQEgAAADIAOAAAUAAAkBBwkBFwMg/kBAAYD+gEABwAHAQP6A/oBAAAEA4AAAAuADgAAFAAATARcJAQfgAcBA/oABgEABwAHAQP6A/oBAAAADAMAA4ANAAsAAGAAxAEoAAAEhIg4CHQEUHgIzITI+Aj0BNC4CIxUhIg4CHQEUHgIzITI+Aj0BNC4CIxUhIg4CHQEUHgIzITI+Aj0BNC4CIwMg/cAHCwkFBQkLBwJABwsJBQUJCwf9wAcLCQUFCQsHAkAHCwkFBQkLB/3ABwsJBQUJCwcCQAcLCQUFCQsHAsAFCQsHIAcLCQUFCQsHIAcLCQXABQkLByAHCwkFBQkLByAHCwkFwAUJCwcgBwsJBQUJCwcgBwsJBQAAAAABAAAAAQAAKY8rQF8PPPUACwQAAAAAAM7zoRQAAAAAzvOhFAAAAAADQAOAAAAACAACAAAAAAAAAAEAAAPA/8AAAAQAAAAAwANAAAEAAAAAAAAAAAAAAAAAAAAFAAAAAAIAAAAEAAEgBAAA4AQAAMAAAAAAAAoAHgAyAJgAAQAAAAUASwADAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAA4ArgABAAAAAAABABoAAAABAAAAAAACAA4AcQABAAAAAAADABoAMAABAAAAAAAEABoAfwABAAAAAAAFABYAGgABAAAAAAAGAA0ASgABAAAAAAAKACgAmQADAAEECQABABoAAAADAAEECQACAA4AcQADAAEECQADABoAMAADAAEECQAEABoAfwADAAEECQAFABYAGgADAAEECQAGABoAVwADAAEECQAKACgAmQB3AGUAYgBmAGwAbwB3AC0AaQBjAG8AbgBzAFYAZQByAHMAaQBvAG4AIAAxAC4AMAB3AGUAYgBmAGwAbwB3AC0AaQBjAG8AbgBzd2ViZmxvdy1pY29ucwB3AGUAYgBmAGwAbwB3AC0AaQBjAG8AbgBzAFIAZQBnAHUAbABhAHIAdwBlAGIAZgBsAG8AdwAtAGkAYwBvAG4AcwBHAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAEkAYwBvAE0AbwBvAG4AAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=) format('truetype'), url(data:application/font-woff;charset=utf-8;base64,d09GRk9UVE8AAAUcAAoAAAAABNQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABDRkYgAAAA9AAAAXEAAAFxTvL96k9TLzIAAAJoAAAAYAAAAGAOsgMsY21hcAAAAsgAAABEAAAAROYUAIdnYXNwAAADDAAAAAgAAAAIAAAAEGhlYWQAAAMUAAAANgAAADYARYalaGhlYQAAA0wAAAAkAAAAJAcCBIZobXR4AAADcAAAABQAAAAUDgACwG1heHAAAAOEAAAABgAAAAYABVAAbmFtZQAAA4wAAAFvAAABb3LtdWhwb3N0AAAE/AAAACAAAAAgAAMAAAEABAQAAQEBDndlYmZsb3ctaWNvbnMAAQIAAQA++BwC+BsD+BgEHgoACXZWJf+Lix4KAAl2ViX/i4sMB4uL+dT51AUdAAAAkg8dAAAAlxEdAAAACR0AAAFoEgAGAQEOGx4jKC13ZWJmbG93LWljb25zd2ViZmxvdy1pY29uc3UyMHVFNjAwdUU2MDF1RTYwMgAAAgGJAAMABQEBBAciPcn+lA78lA75tPhUFfxU+FQFS0sF+BT8FAX8FPwUBctLBQ73dPhUFfhU+FQFy0sF/BT8FAX4FPwUBUtLBQ75tPlUFfzUiwV5i319i3kIi2sFi3mZfZ2LCPjUiwWdi5mZi50Ii6sFi519mXmLCIv7VBX81IsFeYt9fYt5CItrBYt5mX2diwj41IsFnYuZmYudCIurBYudfZl5iwiL+1QV/NSLBXmLfX2LeQiLawWLeZl9nYsI+NSLBZ2LmZmLnQiLqwWLnX2ZeYsIDvqUFPqUFYsMCgAAAAADBAABkAAFAAACmQLMAAAAjwKZAswAAAHrADMBCQAAAAAAAAAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAAAAAEAAIOYCA8D/wP/AA8AAQAAAAAEAAAAAAAAAAAAAACAAAAAAAAIAAAADAAAAFAADAAEAAAAUAAQAMAAAAAgACAACAAAAIOYC//3//wAAACDmAP/9////4RoCAAMAAQAAAAAAAAAAAAEAAf//AA8AAQAAAAEAAOeMsbdfDzz1AAsEAAAAAADO86EUAAAAAM7zoRQAAAAAA0ADgAAAAAgAAgAAAAAAAAABAAADwP/AAAAEAAAAAMADQAABAAAAAAAAAAAAAAAAAAAABQAAAAACAAAABAABIAQAAOAEAADAAABQAAAFAAAAAAAOAK4AAQAAAAAAAQAaAAAAAQAAAAAAAgAOAHEAAQAAAAAAAwAaADAAAQAAAAAABAAaAH8AAQAAAAAABQAWABoAAQAAAAAABgANAEoAAQAAAAAACgAoAJkAAwABBAkAAQAaAAAAAwABBAkAAgAOAHEAAwABBAkAAwAaADAAAwABBAkABAAaAH8AAwABBAkABQAWABoAAwABBAkABgAaAFcAAwABBAkACgAoAJkAdwBlAGIAZgBsAG8AdwAtAGkAYwBvAG4AcwBWAGUAcgBzAGkAbwBuACAAMQAuADAAdwBlAGIAZgBsAG8AdwAtAGkAYwBvAG4Ac3dlYmZsb3ctaWNvbnMAdwBlAGIAZgBsAG8AdwAtAGkAYwBvAG4AcwBSAGUAZwB1AGwAYQByAHcAZQBiAGYAbABvAHcALQBpAGMAbwBuAHMARwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABJAGMAbwBNAG8AbwBuAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) format('woff'); + font-weight: normal; + font-style: normal; +} +[class^="w-icon-"], +[class*=" w-icon-"] { + font-family: 'webflow-icons'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + /* Better Font Rendering =========== */ + + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.w-icon-slider-right:before { + content: "\e600"; +} +.w-icon-slider-left:before { + content: "\e601"; +} +.w-icon-nav-menu:before { + content: "\e602"; +} +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +html { + height: 100%; +} +body { + margin: 0; + min-height: 100%; + background-color: #fff; + color: #333; +} +img { + max-width: 100%; + vertical-align: middle; + display: inline-block; +} +html.w-mod-touch * { + background-attachment: scroll !important; +} +a:focus { + outline: 0; +} +.w-block { + display: block; +} +.w-inline-block { + max-width: 100%; + display: inline-block; +} +.w-clearfix:before, +.w-clearfix:after { + content: " "; + display: table; +} +.w-clearfix:after { + clear: both; +} +.w-hidden { + display: none; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; +} +p { + margin: 0; +} +blockquote { + margin: 0; +} +ul, +ol { + margin-top: 0; + margin-bottom: 0; +} +.w-list-unstyled { + padding-left: 0; + list-style: none; +} +.w-embed:before, +.w-embed:after { + content: " "; + display: table; +} +.w-embed:after { + clear: both; +} +.w-video { + width: 100%; + position: relative; + padding: 0; +} +.w-video iframe, +.w-video object, +.w-video embed { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +.w-form { + margin: 0 0 15px; +} +.w-form-done { + display: none; + padding: 10px; + background-color: #dddddd; +} +.w-form-fail { + display: none; + margin-top: 10px; + padding: 10px; + background-color: #ffdede; +} +label { + display: block; + margin-bottom: 5px; + font-weight: bold; +} +.w-input, +.w-select { + display: block; + width: 100%; + height: 38px; + padding: 8px 12px; + margin-bottom: 10px; + font-size: 14px; + line-height: 1.428571429; + color: #555555; + vertical-align: middle; + background-color: #ffffff; + border: 1px solid #cccccc; +} +.w-input:-moz-placeholder, +.w-select:-moz-placeholder { + color: #999999; +} +.w-input::-moz-placeholder, +.w-select::-moz-placeholder { + color: #999999; + opacity: 1; +} +.w-input:-ms-input-placeholder, +.w-select:-ms-input-placeholder { + color: #999999; +} +.w-input::-webkit-input-placeholder, +.w-select::-webkit-input-placeholder { + color: #999999; +} +.w-input:focus, +.w-select:focus { + border-color: rgba(82, 168, 236, 0.8); + outline: 0; +} +.w-input[disabled], +.w-select[disabled], +.w-input[readonly], +.w-select[readonly], +fieldset[disabled] .w-input, +fieldset[disabled] .w-select { + cursor: not-allowed; + background-color: #eeeeee; +} +textarea.w-input, +textarea.w-select { + height: auto; +} +.w-select[multiple] { + height: auto; +} +.w-button { + display: inline-block; + padding: 12px; + background-color: black; + color: white; + border: 0; + line-height: inherit; +} +.w-form-label { + display: inline-block; + cursor: pointer; + font-weight: normal; + margin-bottom: 0px; +} +.w-checkbox, +.w-radio { + display: block; + margin-bottom: 5px; + padding-left: 20px; +} +.w-checkbox:before, +.w-radio:before, +.w-checkbox:after, +.w-radio:after { + content: " "; + display: table; +} +.w-checkbox:after, +.w-radio:after { + clear: both; +} +.w-checkbox-input, +.w-radio-input { + margin: 4px 0 0; + margin-top: 1px \9; + line-height: normal; + float: left; + margin-left: -20px; +} +.w-radio-input { + margin-top: 3px; +} +.w-container { + margin-left: auto; + margin-right: auto; + max-width: 940px; +} +.w-container:before, +.w-container:after { + content: " "; + display: table; +} +.w-container:after { + clear: both; +} +.w-container .w-row { + margin-left: -10px; + margin-right: -10px; +} +.w-row:before, +.w-row:after { + content: " "; + display: table; +} +.w-row:after { + clear: both; +} +.w-row .w-row { + margin-left: 0; + margin-right: 0; +} +.w-col { + position: relative; + float: left; + width: 100%; + min-height: 1px; + padding-left: 10px; + padding-right: 10px; +} +.w-col .w-col { + padding-left: 0; + padding-right: 0; +} +.w-col-1 { + width: 8.333333333333332%; +} +.w-col-2 { + width: 16.666666666666664%; +} +.w-col-3 { + width: 25%; +} +.w-col-4 { + width: 33.33333333333333%; +} +.w-col-5 { + width: 41.66666666666667%; +} +.w-col-6 { + width: 50%; +} +.w-col-7 { + width: 58.333333333333336%; +} +.w-col-8 { + width: 66.66666666666666%; +} +.w-col-9 { + width: 75%; +} +.w-col-10 { + width: 83.33333333333334%; +} +.w-col-11 { + width: 91.66666666666666%; +} +.w-col-12 { + width: 100%; +} +.w-col-push-1 { + left: 8.333333333333332%; +} +.w-col-push-2 { + left: 16.666666666666664%; +} +.w-col-push-3 { + left: 25%; +} +.w-col-push-4 { + left: 33.33333333333333%; +} +.w-col-push-5 { + left: 41.66666666666667%; +} +.w-col-push-6 { + left: 50%; +} +.w-col-push-7 { + left: 58.333333333333336%; +} +.w-col-push-8 { + left: 66.66666666666666%; +} +.w-col-push-9 { + left: 75%; +} +.w-col-push-10 { + left: 83.33333333333334%; +} +.w-col-push-11 { + left: 91.66666666666666%; +} +.w-col-pull-1 { + right: 8.333333333333332%; +} +.w-col-pull-2 { + right: 16.666666666666664%; +} +.w-col-pull-3 { + right: 25%; +} +.w-col-pull-4 { + right: 33.33333333333333%; +} +.w-col-pull-5 { + right: 41.66666666666667%; +} +.w-col-pull-6 { + right: 50%; +} +.w-col-pull-7 { + right: 58.333333333333336%; +} +.w-col-pull-8 { + right: 66.66666666666666%; +} +.w-col-pull-9 { + right: 75%; +} +.w-col-pull-10 { + right: 83.33333333333334%; +} +.w-col-pull-11 { + right: 91.66666666666666%; +} +.w-col-offset-1 { + margin-left: 8.333333333333332%; +} +.w-col-offset-2 { + margin-left: 16.666666666666664%; +} +.w-col-offset-3 { + margin-left: 25%; +} +.w-col-offset-4 { + margin-left: 33.33333333333333%; +} +.w-col-offset-5 { + margin-left: 41.66666666666667%; +} +.w-col-offset-6 { + margin-left: 50%; +} +.w-col-offset-7 { + margin-left: 58.333333333333336%; +} +.w-col-offset-8 { + margin-left: 66.66666666666666%; +} +.w-col-offset-9 { + margin-left: 75%; +} +.w-col-offset-10 { + margin-left: 83.33333333333334%; +} +.w-col-offset-11 { + margin-left: 91.66666666666666%; +} +.w-hidden-main { + display: none !important; +} +@media screen and (max-width: 991px) { + .w-container { + max-width: 728px; + } + .w-hidden-main { + display: inherit !important; + } + .w-hidden-medium { + display: none !important; + } + .w-col-medium-1 { + width: 8.333333333333332%; + } + .w-col-medium-2 { + width: 16.666666666666664%; + } + .w-col-medium-3 { + width: 25%; + } + .w-col-medium-4 { + width: 33.33333333333333%; + } + .w-col-medium-5 { + width: 41.66666666666667%; + } + .w-col-medium-6 { + width: 50%; + } + .w-col-medium-7 { + width: 58.333333333333336%; + } + .w-col-medium-8 { + width: 66.66666666666666%; + } + .w-col-medium-9 { + width: 75%; + } + .w-col-medium-10 { + width: 83.33333333333334%; + } + .w-col-medium-11 { + width: 91.66666666666666%; + } + .w-col-medium-12 { + width: 100%; + } + .w-col-medium-push-1 { + left: 8.333333333333332%; + } + .w-col-medium-push-2 { + left: 16.666666666666664%; + } + .w-col-medium-push-3 { + left: 25%; + } + .w-col-medium-push-4 { + left: 33.33333333333333%; + } + .w-col-medium-push-5 { + left: 41.66666666666667%; + } + .w-col-medium-push-6 { + left: 50%; + } + .w-col-medium-push-7 { + left: 58.333333333333336%; + } + .w-col-medium-push-8 { + left: 66.66666666666666%; + } + .w-col-medium-push-9 { + left: 75%; + } + .w-col-medium-push-10 { + left: 83.33333333333334%; + } + .w-col-medium-push-11 { + left: 91.66666666666666%; + } + .w-col-medium-pull-1 { + right: 8.333333333333332%; + } + .w-col-medium-pull-2 { + right: 16.666666666666664%; + } + .w-col-medium-pull-3 { + right: 25%; + } + .w-col-medium-pull-4 { + right: 33.33333333333333%; + } + .w-col-medium-pull-5 { + right: 41.66666666666667%; + } + .w-col-medium-pull-6 { + right: 50%; + } + .w-col-medium-pull-7 { + right: 58.333333333333336%; + } + .w-col-medium-pull-8 { + right: 66.66666666666666%; + } + .w-col-medium-pull-9 { + right: 75%; + } + .w-col-medium-pull-10 { + right: 83.33333333333334%; + } + .w-col-medium-pull-11 { + right: 91.66666666666666%; + } + .w-col-medium-offset-1 { + margin-left: 8.333333333333332%; + } + .w-col-medium-offset-2 { + margin-left: 16.666666666666664%; + } + .w-col-medium-offset-3 { + margin-left: 25%; + } + .w-col-medium-offset-4 { + margin-left: 33.33333333333333%; + } + .w-col-medium-offset-5 { + margin-left: 41.66666666666667%; + } + .w-col-medium-offset-6 { + margin-left: 50%; + } + .w-col-medium-offset-7 { + margin-left: 58.333333333333336%; + } + .w-col-medium-offset-8 { + margin-left: 66.66666666666666%; + } + .w-col-medium-offset-9 { + margin-left: 75%; + } + .w-col-medium-offset-10 { + margin-left: 83.33333333333334%; + } + .w-col-medium-offset-11 { + margin-left: 91.66666666666666%; + } + .w-col-stack { + width: 100%; + left: auto; + right: auto; + } +} +@media screen and (max-width: 767px) { + .w-hidden-main { + display: inherit !important; + } + .w-hidden-medium { + display: inherit !important; + } + .w-hidden-small { + display: none !important; + } + .w-row, + .w-container .w-row { + margin-left: 0; + margin-right: 0; + } + .w-col { + width: 100%; + left: auto; + right: auto; + } + .w-col-small-1 { + width: 8.333333333333332%; + } + .w-col-small-2 { + width: 16.666666666666664%; + } + .w-col-small-3 { + width: 25%; + } + .w-col-small-4 { + width: 33.33333333333333%; + } + .w-col-small-5 { + width: 41.66666666666667%; + } + .w-col-small-6 { + width: 50%; + } + .w-col-small-7 { + width: 58.333333333333336%; + } + .w-col-small-8 { + width: 66.66666666666666%; + } + .w-col-small-9 { + width: 75%; + } + .w-col-small-10 { + width: 83.33333333333334%; + } + .w-col-small-11 { + width: 91.66666666666666%; + } + .w-col-small-12 { + width: 100%; + } + .w-col-small-push-1 { + left: 8.333333333333332%; + } + .w-col-small-push-2 { + left: 16.666666666666664%; + } + .w-col-small-push-3 { + left: 25%; + } + .w-col-small-push-4 { + left: 33.33333333333333%; + } + .w-col-small-push-5 { + left: 41.66666666666667%; + } + .w-col-small-push-6 { + left: 50%; + } + .w-col-small-push-7 { + left: 58.333333333333336%; + } + .w-col-small-push-8 { + left: 66.66666666666666%; + } + .w-col-small-push-9 { + left: 75%; + } + .w-col-small-push-10 { + left: 83.33333333333334%; + } + .w-col-small-push-11 { + left: 91.66666666666666%; + } + .w-col-small-pull-1 { + right: 8.333333333333332%; + } + .w-col-small-pull-2 { + right: 16.666666666666664%; + } + .w-col-small-pull-3 { + right: 25%; + } + .w-col-small-pull-4 { + right: 33.33333333333333%; + } + .w-col-small-pull-5 { + right: 41.66666666666667%; + } + .w-col-small-pull-6 { + right: 50%; + } + .w-col-small-pull-7 { + right: 58.333333333333336%; + } + .w-col-small-pull-8 { + right: 66.66666666666666%; + } + .w-col-small-pull-9 { + right: 75%; + } + .w-col-small-pull-10 { + right: 83.33333333333334%; + } + .w-col-small-pull-11 { + right: 91.66666666666666%; + } + .w-col-small-offset-1 { + margin-left: 8.333333333333332%; + } + .w-col-small-offset-2 { + margin-left: 16.666666666666664%; + } + .w-col-small-offset-3 { + margin-left: 25%; + } + .w-col-small-offset-4 { + margin-left: 33.33333333333333%; + } + .w-col-small-offset-5 { + margin-left: 41.66666666666667%; + } + .w-col-small-offset-6 { + margin-left: 50%; + } + .w-col-small-offset-7 { + margin-left: 58.333333333333336%; + } + .w-col-small-offset-8 { + margin-left: 66.66666666666666%; + } + .w-col-small-offset-9 { + margin-left: 75%; + } + .w-col-small-offset-10 { + margin-left: 83.33333333333334%; + } + .w-col-small-offset-11 { + margin-left: 91.66666666666666%; + } +} +@media screen and (max-width: 479px) { + .w-container { + max-width: none; + } + .w-hidden-main { + display: inherit !important; + } + .w-hidden-medium { + display: inherit !important; + } + .w-hidden-small { + display: inherit !important; + } + .w-hidden-tiny { + display: none !important; + } + .w-col { + width: 100%; + } + .w-col-tiny-1 { + width: 8.333333333333332%; + } + .w-col-tiny-2 { + width: 16.666666666666664%; + } + .w-col-tiny-3 { + width: 25%; + } + .w-col-tiny-4 { + width: 33.33333333333333%; + } + .w-col-tiny-5 { + width: 41.66666666666667%; + } + .w-col-tiny-6 { + width: 50%; + } + .w-col-tiny-7 { + width: 58.333333333333336%; + } + .w-col-tiny-8 { + width: 66.66666666666666%; + } + .w-col-tiny-9 { + width: 75%; + } + .w-col-tiny-10 { + width: 83.33333333333334%; + } + .w-col-tiny-11 { + width: 91.66666666666666%; + } + .w-col-tiny-12 { + width: 100%; + } + .w-col-tiny-push-1 { + left: 8.333333333333332%; + } + .w-col-tiny-push-2 { + left: 16.666666666666664%; + } + .w-col-tiny-push-3 { + left: 25%; + } + .w-col-tiny-push-4 { + left: 33.33333333333333%; + } + .w-col-tiny-push-5 { + left: 41.66666666666667%; + } + .w-col-tiny-push-6 { + left: 50%; + } + .w-col-tiny-push-7 { + left: 58.333333333333336%; + } + .w-col-tiny-push-8 { + left: 66.66666666666666%; + } + .w-col-tiny-push-9 { + left: 75%; + } + .w-col-tiny-push-10 { + left: 83.33333333333334%; + } + .w-col-tiny-push-11 { + left: 91.66666666666666%; + } + .w-col-tiny-pull-1 { + right: 8.333333333333332%; + } + .w-col-tiny-pull-2 { + right: 16.666666666666664%; + } + .w-col-tiny-pull-3 { + right: 25%; + } + .w-col-tiny-pull-4 { + right: 33.33333333333333%; + } + .w-col-tiny-pull-5 { + right: 41.66666666666667%; + } + .w-col-tiny-pull-6 { + right: 50%; + } + .w-col-tiny-pull-7 { + right: 58.333333333333336%; + } + .w-col-tiny-pull-8 { + right: 66.66666666666666%; + } + .w-col-tiny-pull-9 { + right: 75%; + } + .w-col-tiny-pull-10 { + right: 83.33333333333334%; + } + .w-col-tiny-pull-11 { + right: 91.66666666666666%; + } + .w-col-tiny-offset-1 { + margin-left: 8.333333333333332%; + } + .w-col-tiny-offset-2 { + margin-left: 16.666666666666664%; + } + .w-col-tiny-offset-3 { + margin-left: 25%; + } + .w-col-tiny-offset-4 { + margin-left: 33.33333333333333%; + } + .w-col-tiny-offset-5 { + margin-left: 41.66666666666667%; + } + .w-col-tiny-offset-6 { + margin-left: 50%; + } + .w-col-tiny-offset-7 { + margin-left: 58.333333333333336%; + } + .w-col-tiny-offset-8 { + margin-left: 66.66666666666666%; + } + .w-col-tiny-offset-9 { + margin-left: 75%; + } + .w-col-tiny-offset-10 { + margin-left: 83.33333333333334%; + } + .w-col-tiny-offset-11 { + margin-left: 91.66666666666666%; + } +} +.w-widget { + position: relative; +} +.w-widget-map { + width: 100%; + height: 400px; +} +.w-widget-map label { + width: auto; + display: inline; +} +.w-widget-map img { + max-width: inherit; +} +.w-widget-map .gm-style-iw { + width: 90% !important; + height: auto !important; + top: 7px !important; + left: 6% !important; + display: inline; + text-align: center; + overflow: hidden; +} +.w-widget-map .gm-style-iw + div { + display: none; +} +.w-widget-twitter { + overflow: hidden; +} +.w-widget-gplus { + overflow: hidden; +} +.w-slider { + position: relative; + height: 300px; + text-align: center; + background: rgba(153, 153, 153, 0.5); + clear: both; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + tap-highlight-color: rgba(0, 0, 0, 0); +} +.w-slider-mask { + position: relative; + display: block; + overflow: hidden; + z-index: 1; + left: 0; + right: 0; + height: 100%; + white-space: nowrap; +} +.w-slide { + position: relative; + display: inline-block; + vertical-align: top; + width: 100%; + height: 100%; + white-space: normal; + text-align: left; +} +.w-slider-nav { + position: absolute; + z-index: 2; + top: auto; + right: 0; + bottom: 0; + left: 0; + margin: auto; + padding-top: 10px; + height: 40px; + text-align: center; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + tap-highlight-color: rgba(0, 0, 0, 0); +} +.w-slider-nav.w-round > div { + -webkit-border-radius: 100%; + -webkit-background-clip: padding-box; + -moz-border-radius: 100%; + -moz-background-clip: padding; + border-radius: 100%; + background-clip: padding-box; +} +.w-slider-nav.w-num > div { + width: auto; + height: auto; + padding: 0.2em 0.5em; + font-size: inherit; + line-height: inherit; +} +.w-slider-nav.w-shadow > div { + -webkit-box-shadow: 0 0 3px rgba(51, 51, 51, 0.4); + -moz-box-shadow: 0 0 3px rgba(51, 51, 51, 0.4); + box-shadow: 0 0 3px rgba(51, 51, 51, 0.4); +} +.w-slider-nav-invert { + color: #fff; +} +.w-slider-nav-invert > div { + background-color: rgba(34, 34, 34, 0.4); +} +.w-slider-nav-invert > div.w-active { + background-color: #222; +} +.w-slider-dot { + position: relative; + display: inline-block; + width: 1em; + height: 1em; + background-color: rgba(255, 255, 255, 0.4); + cursor: pointer; + margin: 0 3px 0.5em; + -webkit-transition: background-color 100ms, color 100ms; + -moz-transition: background-color 100ms, color 100ms; + -o-transition: background-color 100ms, color 100ms; + transition: background-color 100ms, color 100ms; +} +.w-slider-dot.w-active { + background-color: #fff; +} +.w-slider-arrow-left, +.w-slider-arrow-right { + position: absolute; + width: 80px; + top: 0; + right: 0; + bottom: 0; + left: 0; + margin: auto; + cursor: pointer; + overflow: hidden; + color: white; + font-size: 40px; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.w-slider-arrow-left [class^="w-icon-"], +.w-slider-arrow-right [class^="w-icon-"], +.w-slider-arrow-left [class*=" w-icon-"], +.w-slider-arrow-right [class*=" w-icon-"] { + position: absolute; +} +.w-slider-arrow-left { + z-index: 3; + right: auto; +} +.w-slider-arrow-right { + z-index: 4; + left: auto; +} +.w-icon-slider-left, +.w-icon-slider-right { + top: 0; + right: 0; + bottom: 0; + left: 0; + margin: auto; + width: 1em; + height: 1em; +} +.w-nav { + position: relative; + background: #BBB; + z-index: 1000; +} +.w-nav:before, +.w-nav:after { + content: " "; + display: table; +} +.w-nav:after { + clear: both; +} +.w-nav-brand { + position: relative; + float: left; + text-decoration: none; + color: #222; +} +.w-nav-link { + position: relative; + display: inline-block; + vertical-align: top; + text-decoration: none; + color: #222; + padding: 20px; + text-align: left; + margin-left: auto; + margin-right: auto; +} +.w-nav-link.w--current { + color: #339CE1; +} +.w-nav-menu { + position: relative; + float: right; +} +.w--nav-menu-open { + display: block !important; + position: absolute; + top: 100%; + left: 0; + right: 0; + background: #999; + text-align: center; + overflow: visible; + min-width: 200px; +} +.w--nav-link-open { + display: block; +} +.w-nav-overlay { + position: absolute; + overflow: hidden; + display: none; + top: 100%; + left: 0; + right: 0; + width: 100%; +} +.w-nav-overlay .w--nav-menu-open { + top: 0; +} +.w-nav[data-animation="over-left"] .w-nav-overlay { + width: auto; +} +.w-nav[data-animation="over-left"] .w-nav-overlay, +.w-nav[data-animation="over-left"] .w--nav-menu-open { + right: auto; + z-index: 1; + top: 0; +} +.w-nav[data-animation="over-right"] .w-nav-overlay { + width: auto; +} +.w-nav[data-animation="over-right"] .w-nav-overlay, +.w-nav[data-animation="over-right"] .w--nav-menu-open { + left: auto; + z-index: 1; + top: 0; +} +.w-nav-button { + position: relative; + float: right; + padding: 18px; + font-size: 24px; + display: none; + cursor: pointer; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.w-nav-button.w--open { + background-color: #999; + color: white; +} +.w-nav[data-collapse="all"] .w-nav-menu { + display: none; +} +.w-nav[data-collapse="all"] .w-nav-button { + display: block; +} +@media screen and (max-width: 991px) { + .w-nav[data-collapse="medium"] .w-nav-menu { + display: none; + } + .w-nav[data-collapse="medium"] .w-nav-button { + display: block; + } +} +@media screen and (max-width: 767px) { + .w-nav[data-collapse="small"] .w-nav-menu { + display: none; + } + .w-nav[data-collapse="small"] .w-nav-button { + display: block; + } + .w-nav-brand { + padding-left: 10px; + } +} +@media screen and (max-width: 479px) { + .w-nav[data-collapse="tiny"] .w-nav-menu { + display: none; + } + .w-nav[data-collapse="tiny"] .w-nav-button { + display: block; + } +} +.w-tabs { + position: relative; +} +.w-tabs:before, +.w-tabs:after { + content: " "; + display: table; +} +.w-tabs:after { + clear: both; +} +.w-tab-menu { + position: relative; +} +.w-tab-link { + position: relative; + display: inline-block; + vertical-align: top; + text-decoration: none; + padding: 8px 30px; + text-align: left; + cursor: pointer; + background-color: #E8E8E8; +} +.w-tab-link.w--current { + background-color: #BCD3F3; +} +.w-tab-content { + position: relative; + display: block; + overflow: hidden; +} +.w-tab-pane { + position: relative; + display: none; +} +.w--tab-active { + display: block; +} +@media screen and (max-width: 479px) { + .w-tab-link { + display: block; + } +} +.w-ix-emptyfix:after { + content: ""; +} diff --git a/examples/example_basic.go b/examples/example_basic.go deleted file mode 100644 index 575bd89f..00000000 --- a/examples/example_basic.go +++ /dev/null @@ -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") -} diff --git a/gin.go b/gin.go deleted file mode 100644 index 1674f2ef..00000000 --- a/gin.go +++ /dev/null @@ -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) -} diff --git a/images/12-quotes.png b/images/12-quotes.png new file mode 100755 index 00000000..695ef112 Binary files /dev/null and b/images/12-quotes.png differ diff --git a/images/Git-Icon-Black2.png b/images/Git-Icon-Black2.png new file mode 100755 index 00000000..79c1d25f Binary files /dev/null and b/images/Git-Icon-Black2.png differ diff --git a/images/email.png b/images/email.png new file mode 100755 index 00000000..8aa1528b Binary files /dev/null and b/images/email.png differ diff --git a/images/gin.jpg b/images/gin.jpg new file mode 100755 index 00000000..8bb8a4cc Binary files /dev/null and b/images/gin.jpg differ diff --git a/images/globe2.png b/images/globe2.png new file mode 100755 index 00000000..41bb76e9 Binary files /dev/null and b/images/globe2.png differ diff --git a/images/graph.png b/images/graph.png new file mode 100755 index 00000000..aca87ceb Binary files /dev/null and b/images/graph.png differ diff --git a/images/idea2.png b/images/idea2.png new file mode 100755 index 00000000..152bde70 Binary files /dev/null and b/images/idea2.png differ diff --git a/images/pull2.png b/images/pull2.png new file mode 100755 index 00000000..627dc53c Binary files /dev/null and b/images/pull2.png differ diff --git a/images/sample1.png b/images/sample1.png new file mode 100755 index 00000000..885abc8b Binary files /dev/null and b/images/sample1.png differ diff --git a/images/sample11.png b/images/sample11.png new file mode 100755 index 00000000..f9bb814d Binary files /dev/null and b/images/sample11.png differ diff --git a/images/sentry2.png b/images/sentry2.png new file mode 100755 index 00000000..b00745e7 Binary files /dev/null and b/images/sentry2.png differ diff --git a/images/webclip-gallio.png b/images/webclip-gallio.png new file mode 100755 index 00000000..9d7b8b1e Binary files /dev/null and b/images/webclip-gallio.png differ diff --git a/index.html b/index.html new file mode 100755 index 00000000..0b9f64d0 --- /dev/null +++ b/index.html @@ -0,0 +1,184 @@ + + + + + + + Gin Web Framework + + + + + + + + + + + + +
+
+

Gin Gonic

+

Fastest full-featured web framework for Golang. Crystal clear. +

+
API REFERENCE +

go get github.com/gin-gonic/gin +

+
+
+
+
+
+

Performance and productivity can work together

+

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.

+ +
+
+
+
+

Low Overhead Powerful API

+

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 great! Gin uses httprouter internally, the fastest HTTP router for + Golang. Httprouter was created by Julien Schmidt and it’s based in a Radix Tree algorithm. This explains the good performance and scalability of Gin.

+
+
+

Some cool middlewares

+

If you used Martini before, Gin will be familiar to you. If you don’t, you will need 10 minutes to learn everything.

Check out the
Sentry midDlEware
+

More coming soon!

+
+
+

Crystal Clear

+

If you used Martini before, Gin will be familiar to you. If you don’t, you will need 10 minutes to learn everything.

+
+
+
+ 539f93b8f281585418675d91_sample1.png +
+
+ 539f93ccf281585418675d92_sample11.png +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Full Featured

+
+
+
I
+

Fast

+

Radix tree based routing, small memory foot print. No reflection. Predictable API performance. 

+
+
+
II
+

Middleware support

+

A incoming HTTP request can by handled by a chain of middlewares and the final action. +
For example: Logger, Authorization, GZIP and finally post a message in the DB.

+
+
+
III
+

Crash-free

+

Gin can catch a panic occurred during a HTTP request and recover it. This way, your server will be always available. It’s also possible to report this panic to Sentry for example!

+
+
+
+
+
IV
+

JSON validation

+

Gin can parse and validate the JSON of a request, checking for example the existence of required values.

+
+
+
V
+

Routes grouping

+

Organize your routes better. Authorization required vs non required, different API versions... In addition, the groups can be nested unlimitedly without degrading performance!

+
+
+
VI
+

Error management

+

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.

+
+
+
+
+
VII
+

Rendering built-in

+

Gin provides a easy to use API for JSON, XML and HTML rendering.

+
+
+
VIII
+

Extendable

+

Creating a new middleware is so easy, just check out the sample codes.

+
+
+
+
+
+
+
+

How to contribute?

+

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 fork it in Github, add some changes and start posting + Pull Requests, we would love to merge them.

+
+
+
+
1. Fork
+ 539e4fca30eda3837a903182_Git-Icon-Black2.png +
+
+
+
+
2. Commit
+ 539e4fbbaa3db5690ebc0c8c_idea2.png +
+
+
+
+
3. Pull request
+ 539e4fadaa3db5690ebc0c8b_pull2.png +
+
+
+
+
+ + + + + + \ No newline at end of file diff --git a/js/modernizr.js b/js/modernizr.js new file mode 100755 index 00000000..3ecc2844 --- /dev/null +++ b/js/modernizr.js @@ -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=["­",'"].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",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="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)); diff --git a/js/webflow.js b/js/webflow.js new file mode 100755 index 00000000..08584b91 --- /dev/null +++ b/js/webflow.js @@ -0,0 +1,2775 @@ +/*! + * ---------------------------------------------------------------------- + * Webflow: Front-end site library + * @license MIT + * Other scripts may access this api using an async handler: + * var Webflow = Webflow || []; + * Webflow.push(readyFunction); + * ---------------------------------------------------------------------- + */ +var Webflow = { w: Webflow }; +Webflow.init = function () { + 'use strict'; + + var $ = window.$; + var api = {}; + var modules = {}; + var primary = []; + var secondary = this.w || []; + var $win = $(window); + var _ = api._ = underscore(); + var domready = false; + var tram = window.tram; + var Modernizr = window.Modernizr; + tram.config.hideBackface = false; + tram.config.keepInherited = true; + + /** + * Webflow.define() - Define a webflow.js module + * @param {string} name + * @param {function} factory + */ + api.define = function (name, factory) { + var module = modules[name] = factory($, _); + if (!module) return; + // If running in Webflow app, subscribe to design/preview events + if (api.env()) { + $.isFunction(module.design) && window.addEventListener('__wf_design', module.design); + $.isFunction(module.preview) && window.addEventListener('__wf_preview', module.preview); + } + // Look for a ready method on module + if (module.ready && $.isFunction(module.ready)) { + // If domready has already happened, call ready method + if (domready) module.ready(); + // Otherwise push ready method into primary queue + else primary.push(module.ready); + } + }; + + /** + * Webflow.require() - Load a Webflow.js module + * @param {string} name + * @return {object} + */ + api.require = function (name) { + return modules[name]; + }; + + /** + * Webflow.push() - Add a ready handler into secondary queue + * @param {function} ready Callback to invoke on domready + */ + api.push = function (ready) { + // If domready has already happened, invoke handler + if (domready) { + $.isFunction(ready) && ready(); + return; + } + // Otherwise push into secondary queue + secondary.push(ready); + }; + + /** + * Webflow.env() - Get the state of the Webflow app + * @param {string} mode [optional] + * @return {boolean} + */ + api.env = function (mode) { + var designFlag = window.__wf_design; + var inApp = typeof designFlag != 'undefined'; + if (!mode) return inApp; + if (mode == 'design') return inApp && designFlag; + if (mode == 'preview') return inApp && !designFlag; + if (mode == 'slug') return inApp && window.__wf_slug; + }; + + // Feature detects + browser sniffs ಠ_ಠ + var userAgent = navigator.userAgent.toLowerCase(); + var appVersion = navigator.appVersion.toLowerCase(); + api.env.touch = ('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch; + var chrome = api.env.chrome = (window.chrome || /chrome/.test(userAgent)) && parseInt(appVersion.match(/chrome\/(\d+)\./)[1], 10); + var ios = api.env.ios = Modernizr && Modernizr.ios; + api.env.safari = /safari/.test(userAgent) && !chrome && !ios; + + /** + * Webflow.script() - Append script to document head + * @param {string} src + */ + api.script = function (src) { + var doc = document; + var scriptNode = doc.createElement('script'); + scriptNode.type = 'text/javascript'; + scriptNode.src = src; + doc.getElementsByTagName('head')[0].appendChild(scriptNode); + }; + + /** + * Webflow.resize, Webflow.scroll - throttled event proxies + */ + var resizeEvents = 'resize.webflow orientationchange.webflow load.webflow'; + var scrollEvents = 'scroll.webflow ' + resizeEvents; + api.resize = eventProxy($win, resizeEvents); + api.scroll = eventProxy($win, scrollEvents); + api.redraw = eventProxy(); + + // Create a proxy instance for throttled events + function eventProxy(target, types) { + + // Set up throttled method (using custom frame-based _.throttle) + var handlers = []; + var proxy = {}; + proxy.up = _.throttle(function (evt) { + _.each(handlers, function (h) { h(evt); }); + }); + + // Bind events to target + if (target && types) target.on(types, proxy.up); + + /** + * Add an event handler + * @param {function} handler + */ + proxy.on = function (handler) { + if (typeof handler != 'function') return; + if (_.contains(handlers, handler)) return; + handlers.push(handler); + }; + + /** + * Remove an event handler + * @param {function} handler + */ + proxy.off = function (handler) { + handlers = _.filter(handlers, function (h) { + return h !== handler; + }); + }; + return proxy; + } + + // Webflow.location - Wrap window.location in api + api.location = function (url) { + window.location = url; + }; + + // Webflow.app - Designer-specific methods + api.app = api.env() ? {} : null; + if (api.app) { + + // Trigger redraw for specific elements + var Event = window.Event; + var redraw = new Event('__wf_redraw'); + api.app.redrawElement = function (i, el) { el.dispatchEvent(redraw); }; + + // Webflow.location - Re-route location change to trigger an event + api.location = function (url) { + window.dispatchEvent(new CustomEvent('__wf_location', { detail: url })); + }; + } + + // DOM ready - Call primary and secondary handlers + $(function () { + domready = true; + $.each(primary.concat(secondary), function (index, value) { + $.isFunction(value) && value(); + }); + // Trigger resize + api.resize.up(); + }); + + /*! + * Webflow._ (aka) Underscore.js 1.5.2 (custom build) + * _.each + * _.map + * _.filter + * _.any + * _.contains + * _.delay + * _.defer + * _.throttle (webflow) + * _.debounce + * _.keys + * _.has + * + * http://underscorejs.org + * (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Underscore may be freely distributed under the MIT license. + */ + function underscore() { + var _ = {}; + + // Current version. + _.VERSION = '1.5.2-Webflow'; + + // Establish the object that gets returned to break out of a loop iteration. + var breaker = {}; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var + push = ArrayProto.push, + slice = ArrayProto.slice, + concat = ArrayProto.concat, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeForEach = ArrayProto.forEach, + nativeMap = ArrayProto.map, + nativeReduce = ArrayProto.reduce, + nativeReduceRight = ArrayProto.reduceRight, + nativeFilter = ArrayProto.filter, + nativeEvery = ArrayProto.every, + nativeSome = ArrayProto.some, + nativeIndexOf = ArrayProto.indexOf, + nativeLastIndexOf = ArrayProto.lastIndexOf, + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles objects with the built-in `forEach`, arrays, and raw objects. + // Delegates to **ECMAScript 5**'s native `forEach` if available. + var each = _.each = _.forEach = function(obj, iterator, context) { + /* jshint shadow:true */ + if (obj == null) return; + if (nativeForEach && obj.forEach === nativeForEach) { + obj.forEach(iterator, context); + } else if (obj.length === +obj.length) { + for (var i = 0, length = obj.length; i < length; i++) { + if (iterator.call(context, obj[i], i, obj) === breaker) return; + } + } else { + var keys = _.keys(obj); + for (var i = 0, length = keys.length; i < length; i++) { + if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return; + } + } + }; + + // Return the results of applying the iterator to each element. + // Delegates to **ECMAScript 5**'s native `map` if available. + _.map = _.collect = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); + each(obj, function(value, index, list) { + results.push(iterator.call(context, value, index, list)); + }); + return results; + }; + + // Return all the elements that pass a truth test. + // Delegates to **ECMAScript 5**'s native `filter` if available. + // Aliased as `select`. + _.filter = _.select = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); + each(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) results.push(value); + }); + return results; + }; + + // Determine if at least one element in the object matches a truth test. + // Delegates to **ECMAScript 5**'s native `some` if available. + // Aliased as `any`. + var any = _.some = _.any = function(obj, iterator, context) { + iterator || (iterator = _.identity); + var result = false; + if (obj == null) return result; + if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); + each(obj, function(value, index, list) { + if (result || (result = iterator.call(context, value, index, list))) return breaker; + }); + return !!result; + }; + + // Determine if the array or object contains a given value (using `===`). + // Aliased as `include`. + _.contains = _.include = function(obj, target) { + if (obj == null) return false; + if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; + return any(obj, function(value) { + return value === target; + }); + }; + + // Function (ahem) Functions + // -------------------- + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ return func.apply(null, args); }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = function(func) { + return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); + }; + + // Returns a function, that, when invoked, will only be triggered once every + // browser animation frame - using tram's requestAnimationFrame polyfill. + _.throttle = function(func) { + var wait, args, context; + return function () { + if (wait) return; + wait = true; + args = arguments; + context = this; + tram.frame(function () { + wait = false; + func.apply(context, args); + }); + }; + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + _.debounce = function(func, wait, immediate) { + var timeout, args, context, timestamp, result; + return function() { + context = this; + args = arguments; + timestamp = new Date(); + var later = function() { + var last = (new Date()) - timestamp; + if (last < wait) { + timeout = setTimeout(later, wait - last); + } else { + timeout = null; + if (!immediate) result = func.apply(context, args); + } + }; + var callNow = immediate && !timeout; + if (!timeout) { + timeout = setTimeout(later, wait); + } + if (callNow) result = func.apply(context, args); + return result; + }; + }; + + // Object Functions + // ---------------- + + // Retrieve the names of an object's properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = nativeKeys || function(obj) { + if (obj !== Object(obj)) throw new TypeError('Invalid object'); + var keys = []; + for (var key in obj) if (_.has(obj, key)) keys.push(key); + return keys; + }; + + // Shortcut function for checking if an object has a given property directly + // on itself (in other words, not on a prototype). + _.has = function(obj, key) { + return hasOwnProperty.call(obj, key); + }; + + // Export underscore + return _; + } + + // Export api + Webflow = api; +}; +/*! + * ---------------------------------------------------------------------- + * Webflow: 3rd party plugins + */ +/* jshint ignore:start */ +/*! + * tram.js v0.8.0-global + * Cross-browser CSS3 transitions in JavaScript + * https://github.com/bkwld/tram + * MIT License + */ +window.tram=function(t){function i(t,i){var e=new Z.Bare;return e.init(t,i)}function e(t){return t.replace(/[A-Z]/g,function(t){return"-"+t.toLowerCase()})}function n(t){var i=parseInt(t.slice(1),16),e=255&i>>16,n=255&i>>8,r=255&i;return[e,n,r]}function r(t,i,e){return"#"+(1<<24|t<<16|i<<8|e).toString(16).slice(1)}function s(){}function a(t,i){_("Type warning: Expected: ["+t+"] Got: ["+typeof i+"] "+i)}function o(t,i,e){_("Units do not match ["+t+"]: "+i+", "+e)}function u(t,i,e){if(void 0!==i&&(e=i),void 0===t)return e;var n=e;return K.test(t)||!V.test(t)?n=parseInt(t,10):V.test(t)&&(n=1e3*parseFloat(t)),0>n&&(n=0),n===n?n:e}function c(t){for(var i=-1,e=t?t.length:0,n=[];e>++i;){var r=t[i];r&&n.push(r)}return n}var h=function(t,i,e){function n(t){return"object"==typeof t}function r(t){return"function"==typeof t}function s(){}function a(o,u){function c(){var t=new h;return r(t.init)&&t.init.apply(t,arguments),t}function h(){}u===e&&(u=o,o=Object),c.Bare=h;var l,f=s[t]=o[t],d=h[t]=c[t]=new s;return d.constructor=c,c.mixin=function(i){return h[t]=c[t]=a(c,i)[t],c},c.open=function(t){if(l={},r(t)?l=t.call(c,d,f,c,o):n(t)&&(l=t),n(l))for(var e in l)i.call(l,e)&&(d[e]=l[e]);return r(d.init)||(d.init=o),c},c.open(u)}return a}("prototype",{}.hasOwnProperty),l={ease:["ease",function(t,i,e,n){var r=(t/=n)*t,s=r*t;return i+e*(-2.75*s*r+11*r*r+-15.5*s+8*r+.25*t)}],"ease-in":["ease-in",function(t,i,e,n){var r=(t/=n)*t,s=r*t;return i+e*(-1*s*r+3*r*r+-3*s+2*r)}],"ease-out":["ease-out",function(t,i,e,n){var r=(t/=n)*t,s=r*t;return i+e*(.3*s*r+-1.6*r*r+2.2*s+-1.8*r+1.9*t)}],"ease-in-out":["ease-in-out",function(t,i,e,n){var r=(t/=n)*t,s=r*t;return i+e*(2*s*r+-5*r*r+2*s+2*r)}],linear:["linear",function(t,i,e,n){return e*t/n+i}],"ease-in-quad":["cubic-bezier(0.550, 0.085, 0.680, 0.530)",function(t,i,e,n){return e*(t/=n)*t+i}],"ease-out-quad":["cubic-bezier(0.250, 0.460, 0.450, 0.940)",function(t,i,e,n){return-e*(t/=n)*(t-2)+i}],"ease-in-out-quad":["cubic-bezier(0.455, 0.030, 0.515, 0.955)",function(t,i,e,n){return 1>(t/=n/2)?e/2*t*t+i:-e/2*(--t*(t-2)-1)+i}],"ease-in-cubic":["cubic-bezier(0.550, 0.055, 0.675, 0.190)",function(t,i,e,n){return e*(t/=n)*t*t+i}],"ease-out-cubic":["cubic-bezier(0.215, 0.610, 0.355, 1)",function(t,i,e,n){return e*((t=t/n-1)*t*t+1)+i}],"ease-in-out-cubic":["cubic-bezier(0.645, 0.045, 0.355, 1)",function(t,i,e,n){return 1>(t/=n/2)?e/2*t*t*t+i:e/2*((t-=2)*t*t+2)+i}],"ease-in-quart":["cubic-bezier(0.895, 0.030, 0.685, 0.220)",function(t,i,e,n){return e*(t/=n)*t*t*t+i}],"ease-out-quart":["cubic-bezier(0.165, 0.840, 0.440, 1)",function(t,i,e,n){return-e*((t=t/n-1)*t*t*t-1)+i}],"ease-in-out-quart":["cubic-bezier(0.770, 0, 0.175, 1)",function(t,i,e,n){return 1>(t/=n/2)?e/2*t*t*t*t+i:-e/2*((t-=2)*t*t*t-2)+i}],"ease-in-quint":["cubic-bezier(0.755, 0.050, 0.855, 0.060)",function(t,i,e,n){return e*(t/=n)*t*t*t*t+i}],"ease-out-quint":["cubic-bezier(0.230, 1, 0.320, 1)",function(t,i,e,n){return e*((t=t/n-1)*t*t*t*t+1)+i}],"ease-in-out-quint":["cubic-bezier(0.860, 0, 0.070, 1)",function(t,i,e,n){return 1>(t/=n/2)?e/2*t*t*t*t*t+i:e/2*((t-=2)*t*t*t*t+2)+i}],"ease-in-sine":["cubic-bezier(0.470, 0, 0.745, 0.715)",function(t,i,e,n){return-e*Math.cos(t/n*(Math.PI/2))+e+i}],"ease-out-sine":["cubic-bezier(0.390, 0.575, 0.565, 1)",function(t,i,e,n){return e*Math.sin(t/n*(Math.PI/2))+i}],"ease-in-out-sine":["cubic-bezier(0.445, 0.050, 0.550, 0.950)",function(t,i,e,n){return-e/2*(Math.cos(Math.PI*t/n)-1)+i}],"ease-in-expo":["cubic-bezier(0.950, 0.050, 0.795, 0.035)",function(t,i,e,n){return 0===t?i:e*Math.pow(2,10*(t/n-1))+i}],"ease-out-expo":["cubic-bezier(0.190, 1, 0.220, 1)",function(t,i,e,n){return t===n?i+e:e*(-Math.pow(2,-10*t/n)+1)+i}],"ease-in-out-expo":["cubic-bezier(1, 0, 0, 1)",function(t,i,e,n){return 0===t?i:t===n?i+e:1>(t/=n/2)?e/2*Math.pow(2,10*(t-1))+i:e/2*(-Math.pow(2,-10*--t)+2)+i}],"ease-in-circ":["cubic-bezier(0.600, 0.040, 0.980, 0.335)",function(t,i,e,n){return-e*(Math.sqrt(1-(t/=n)*t)-1)+i}],"ease-out-circ":["cubic-bezier(0.075, 0.820, 0.165, 1)",function(t,i,e,n){return e*Math.sqrt(1-(t=t/n-1)*t)+i}],"ease-in-out-circ":["cubic-bezier(0.785, 0.135, 0.150, 0.860)",function(t,i,e,n){return 1>(t/=n/2)?-e/2*(Math.sqrt(1-t*t)-1)+i:e/2*(Math.sqrt(1-(t-=2)*t)+1)+i}],"ease-in-back":["cubic-bezier(0.600, -0.280, 0.735, 0.045)",function(t,i,e,n,r){return void 0===r&&(r=1.70158),e*(t/=n)*t*((r+1)*t-r)+i}],"ease-out-back":["cubic-bezier(0.175, 0.885, 0.320, 1.275)",function(t,i,e,n,r){return void 0===r&&(r=1.70158),e*((t=t/n-1)*t*((r+1)*t+r)+1)+i}],"ease-in-out-back":["cubic-bezier(0.680, -0.550, 0.265, 1.550)",function(t,i,e,n,r){return void 0===r&&(r=1.70158),1>(t/=n/2)?e/2*t*t*(((r*=1.525)+1)*t-r)+i:e/2*((t-=2)*t*(((r*=1.525)+1)*t+r)+2)+i}]},f={"ease-in-back":"cubic-bezier(0.600, 0, 0.735, 0.045)","ease-out-back":"cubic-bezier(0.175, 0.885, 0.320, 1)","ease-in-out-back":"cubic-bezier(0.680, 0, 0.265, 1)"},d=document,p=window,b="bkwld-tram",m=/[\-\.0-9]/g,v=/[A-Z]/,g="number",y=/^(rgb|#)/,w=/(em|cm|mm|in|pt|pc|px)$/,k=/(em|cm|mm|in|pt|pc|px|%)$/,x=/(deg|rad|turn)$/,z="unitless",q=/(all|none) 0s ease 0s/,$=/^(width|height)$/,M=" ",A=d.createElement("a"),B=["Webkit","Moz","O","ms"],R=["-webkit-","-moz-","-o-","-ms-"],F=function(t){if(t in A.style)return{dom:t,css:t};var i,e,n="",r=t.split("-");for(i=0;r.length>i;i++)n+=r[i].charAt(0).toUpperCase()+r[i].slice(1);for(i=0;B.length>i;i++)if(e=B[i]+n,e in A.style)return{dom:e,css:R[i]+t}},S=i.support={bind:Function.prototype.bind,transform:F("transform"),transition:F("transition"),backface:F("backface-visibility"),timing:F("transition-timing-function")};if(S.transition){var j=S.timing.dom;if(A.style[j]=l["ease-in-back"][0],!A.style[j])for(var I in f)l[I][0]=f[I]}var G=i.frame=function(){var t=p.requestAnimationFrame||p.webkitRequestAnimationFrame||p.mozRequestAnimationFrame||p.oRequestAnimationFrame||p.msRequestAnimationFrame;return t&&S.bind?t.bind(p):function(t){p.setTimeout(t,16)}}(),T=i.now=function(){var t=p.performance,i=t&&(t.now||t.webkitNow||t.msNow||t.mozNow);return i&&S.bind?i.bind(t):Date.now||function(){return+new Date}}(),U=h(function(i){function n(t,i){var e=c((""+t).split(M)),n=e[0];i=i||{};var r=W[n];if(!r)return _("Unsupported property: "+n);if(!i.weak||!this.props[n]){var s=r[0],a=this.props[n];return a||(a=this.props[n]=new s.Bare),a.init(this.$el,e,r,i),a}}function r(t,i,e){if(t){var r=typeof t;if(i||(this.timer&&this.timer.destroy(),this.queue=[],this.active=!1),"number"==r&&i)return this.timer=new Y({duration:t,context:this,complete:o}),this.active=!0,void 0;if("string"==r&&i){switch(t){case"hide":d.call(this);break;case"stop":h.call(this);break;case"redraw":p.call(this);break;default:n.call(this,t,e&&e[1])}return o.call(this)}if("function"==r)return t.call(this,this),void 0;if("object"==r){var s=0;m.call(this,t,function(t,i){t.span>s&&(s=t.span),t.stop(),t.animate(i)},function(t){"wait"in t&&(s=u(t.wait,0))}),b.call(this),s>0&&(this.timer=new Y({duration:s,context:this}),this.active=!0,i&&(this.timer.complete=o));var a=this,c=!1,l={};G(function(){m.call(a,t,function(t){t.active&&(c=!0,l[t.name]=t.nextStyle)}),c&&a.$el.css(l)})}}}function s(t){t=u(t,0),this.active?this.queue.push({options:t}):(this.timer=new Y({duration:t,context:this,complete:o}),this.active=!0)}function a(t){return this.active?(this.queue.push({options:t,args:arguments}),this.timer.complete=o,void 0):_("No active transition timer. Use start() or wait() before then().")}function o(){if(this.timer&&this.timer.destroy(),this.active=!1,this.queue.length){var t=this.queue.shift();r.call(this,t.options,!0,t.args)}}function h(t){this.timer&&this.timer.destroy(),this.queue=[],this.active=!1;var i;"string"==typeof t?(i={},i[t]=1):i="object"==typeof t&&null!=t?t:this.props,m.call(this,i,g),b.call(this)}function l(t){h.call(this,t),m.call(this,t,y,w)}function f(t){"string"!=typeof t&&(t="block"),this.el.style.display=t}function d(){h.call(this),this.el.style.display="none"}function p(){this.el.offsetHeight}function b(){var t,i,e=[];this.upstream&&e.push(this.upstream);for(t in this.props)i=this.props[t],i.active&&e.push(i.string);e=e.join(","),this.style!==e&&(this.style=e,this.el.style[S.transition.dom]=e)}function m(t,i,r){var s,a,o,u,c=i!==g,h={};for(s in t)o=t[s],s in J?(h.transform||(h.transform={}),h.transform[s]=o):(v.test(s)&&(s=e(s)),s in W?h[s]=o:(u||(u={}),u[s]=o));for(s in h){if(o=h[s],a=this.props[s],!a){if(!c)continue;a=n.call(this,s)}i.call(this,a,o)}r&&u&&r.call(this,u)}function g(t){t.stop()}function y(t,i){t.set(i)}function w(t){this.$el.css(t)}function k(t,e){i[t]=function(){return this.children?x.call(this,e,arguments):(this.el&&e.apply(this,arguments),this)}}function x(t,i){var e,n=this.children.length;for(e=0;n>e;e++)t.apply(this.children[e],i);return this}i.init=function(i){if(this.$el=t(i),this.el=this.$el[0],this.props={},this.queue=[],this.style="",this.active=!1,C.keepInherited&&!C.fallback){var e=L(this.el,"transition");e&&!q.test(e)&&(this.upstream=e)}S.backface&&C.hideBackface&&D(this.el,S.backface.css,"hidden")},k("add",n),k("start",r),k("wait",s),k("then",a),k("next",o),k("stop",h),k("set",l),k("show",f),k("hide",d),k("redraw",p)}),Z=h(U,function(i){function e(i,e){var n=t.data(i,b)||t.data(i,b,new U.Bare);return n.el||n.init(i),e?n.start(e):n}i.init=function(i,n){var r=t(i);if(!r.length)return this;if(1===r.length)return e(r[0],n);var s=[];return r.each(function(t,i){s.push(e(i,n))}),this.children=s,this}}),H=h(function(t){function i(){var t=this.get();this.update("auto");var i=this.get();return this.update(t),i}function e(t,i,e){return void 0!==i&&(e=i),t in l?t:e}function n(t){var i=/rgba?\((\d+),\s*(\d+),\s*(\d+)/.exec(t);return(i?r(i[1],i[2],i[3]):t).replace(/#(\w)(\w)(\w)$/,"#$1$1$2$2$3$3")}var s={duration:500,ease:"ease",delay:0};t.init=function(t,i,n,r){this.$el=t,this.el=t[0];var a=i[0];n[2]&&(a=n[2]),Q[a]&&(a=Q[a]),this.name=a,this.type=n[1],this.duration=u(i[1],this.duration,s.duration),this.ease=e(i[2],this.ease,s.ease),this.delay=u(i[3],this.delay,s.delay),this.span=this.duration+this.delay,this.active=!1,this.nextStyle=null,this.auto=$.test(this.name),this.unit=r.unit||this.unit||C.defaultUnit,this.angle=r.angle||this.angle||C.defaultAngle,C.fallback||r.fallback?this.animate=this.fallback:(this.animate=this.transition,this.string=this.name+M+this.duration+"ms"+("ease"!=this.ease?M+l[this.ease][0]:"")+(this.delay?M+this.delay+"ms":""))},t.set=function(t){t=this.convert(t,this.type),this.update(t),this.redraw()},t.transition=function(t){this.active=!0,t=this.convert(t,this.type),this.auto&&("auto"==this.el.style[this.name]&&(this.update(this.get()),this.redraw()),"auto"==t&&(t=i.call(this))),this.nextStyle=t},t.fallback=function(t){var e=this.el.style[this.name]||this.convert(this.get(),this.type);t=this.convert(t,this.type),this.auto&&("auto"==e&&(e=this.convert(this.get(),this.type)),"auto"==t&&(t=i.call(this))),this.tween=new X({from:e,to:t,duration:this.duration,delay:this.delay,ease:this.ease,update:this.update,context:this})},t.get=function(){return L(this.el,this.name)},t.update=function(t){D(this.el,this.name,t)},t.stop=function(){(this.active||this.nextStyle)&&(this.active=!1,this.nextStyle=null,D(this.el,this.name,this.get()));var t=this.tween;t&&t.context&&t.destroy()},t.convert=function(t,i){if("auto"==t&&this.auto)return t;var e,r="number"==typeof t,s="string"==typeof t;switch(i){case g:if(r)return t;if(s&&""===t.replace(m,""))return+t;e="number(unitless)";break;case y:if(s){if(""===t&&this.original)return this.original;if(i.test(t))return"#"==t.charAt(0)&&7==t.length?t:n(t)}e="hex or rgb string";break;case w:if(r)return t+this.unit;if(s&&i.test(t))return t;e="number(px) or string(unit)";break;case k:if(r)return t+this.unit;if(s&&i.test(t))return t;e="number(px) or string(unit or %)";break;case x:if(r)return t+this.angle;if(s&&i.test(t))return t;e="number(deg) or string(angle)";break;case z:if(r)return t;if(s&&k.test(t))return t;e="number(unitless) or string(unit or %)"}return a(e,t),t},t.redraw=function(){this.el.offsetHeight}}),N=h(H,function(t,i){t.init=function(){i.init.apply(this,arguments),this.original||(this.original=this.convert(this.get(),y))}}),O=h(H,function(t,i){t.init=function(){i.init.apply(this,arguments),this.animate=this.fallback},t.get=function(){return this.$el[this.name]()},t.update=function(t){this.$el[this.name](t)}}),P=h(H,function(t,i){function e(t,i){var e,n,r,s,a;for(e in t)s=J[e],r=s[0],n=s[1]||e,a=this.convert(t[e],r),i.call(this,n,a,r)}t.init=function(){i.init.apply(this,arguments),this.current||(this.current={},J.perspective&&C.perspective&&(this.current.perspective=C.perspective,D(this.el,this.name,this.style(this.current)),this.redraw()))},t.set=function(t){e.call(this,t,function(t,i){this.current[t]=i}),D(this.el,this.name,this.style(this.current)),this.redraw()},t.transition=function(t){var i=this.values(t);this.tween=new E({current:this.current,values:i,duration:this.duration,delay:this.delay,ease:this.ease});var e,n={};for(e in this.current)n[e]=e in i?i[e]:this.current[e];this.active=!0,this.nextStyle=this.style(n)},t.fallback=function(t){var i=this.values(t);this.tween=new E({current:this.current,values:i,duration:this.duration,delay:this.delay,ease:this.ease,update:this.update,context:this})},t.update=function(){D(this.el,this.name,this.style(this.current))},t.style=function(t){var i,e="";for(i in t)e+=i+"("+t[i]+") ";return e},t.values=function(t){var i,n={};return e.call(this,t,function(t,e,r){n[t]=e,void 0===this.current[t]&&(i=0,~t.indexOf("scale")&&(i=1),this.current[t]=this.convert(i,r))}),n}}),X=h(function(i){function e(t){1===d.push(t)&&G(a)}function a(){var t,i,e,n=d.length;if(n)for(G(a),i=T(),t=n;t--;)e=d[t],e&&e.render(i)}function u(i){var e,n=t.inArray(i,d);n>=0&&(e=d.slice(n+1),d.length=n,e.length&&(d=d.concat(e)))}function c(t){return Math.round(t*p)/p}function h(t,i,e){return r(t[0]+e*(i[0]-t[0]),t[1]+e*(i[1]-t[1]),t[2]+e*(i[2]-t[2]))}var f={ease:l.ease[1],from:0,to:1};i.init=function(t){this.duration=t.duration||0,this.delay=t.delay||0;var i=t.ease||f.ease;l[i]&&(i=l[i][1]),"function"!=typeof i&&(i=f.ease),this.ease=i,this.update=t.update||s,this.complete=t.complete||s,this.context=t.context||this,this.name=t.name;var e=t.from,n=t.to;void 0===e&&(e=f.from),void 0===n&&(n=f.to),this.unit=t.unit||"","number"==typeof e&&"number"==typeof n?(this.begin=e,this.change=n-e):this.format(n,e),this.value=this.begin+this.unit,this.start=T(),t.autoplay!==!1&&this.play()},i.play=function(){this.active||(this.start||(this.start=T()),this.active=!0,e(this))},i.stop=function(){this.active&&(this.active=!1,u(this))},i.render=function(t){var i,e=t-this.start;if(this.delay){if(this.delay>=e)return;e-=this.delay}if(this.duration>e){var n=this.ease(e,0,1,this.duration);return i=this.startRGB?h(this.startRGB,this.endRGB,n):c(this.begin+n*this.change),this.value=i+this.unit,this.update.call(this.context,this.value),void 0}i=this.endHex||this.begin+this.change,this.value=i+this.unit,this.update.call(this.context,this.value),this.complete.call(this.context),this.destroy()},i.format=function(t,i){if(i+="",t+="","#"==t.charAt(0))return this.startRGB=n(i),this.endRGB=n(t),this.endHex=t,this.begin=0,this.change=1,void 0;if(!this.unit){var e=i.replace(m,""),r=t.replace(m,"");e!==r&&o("tween",i,t),this.unit=e}i=parseFloat(i),t=parseFloat(t),this.begin=this.value=i,this.change=t-i},i.destroy=function(){this.stop(),this.context=null,this.ease=this.update=this.complete=s};var d=[],p=1e3}),Y=h(X,function(t){t.init=function(t){this.duration=t.duration||0,this.complete=t.complete||s,this.context=t.context,this.play()},t.render=function(t){var i=t-this.start;this.duration>i||(this.complete.call(this.context),this.destroy())}}),E=h(X,function(t,i){t.init=function(t){this.context=t.context,this.update=t.update,this.tweens=[],this.current=t.current;var i,e;for(i in t.values)e=t.values[i],this.current[i]!==e&&this.tweens.push(new X({name:i,from:this.current[i],to:e,duration:t.duration,delay:t.delay,ease:t.ease,autoplay:!1}));this.play()},t.render=function(t){var i,e,n=this.tweens.length,r=!1;for(i=n;i--;)e=this.tweens[i],e.context&&(e.render(t),this.current[e.name]=e.value,r=!0);return r?(this.update&&this.update.call(this.context),void 0):this.destroy()},t.destroy=function(){if(i.destroy.call(this),this.tweens){var t,e=this.tweens.length;for(t=e;t--;)this.tweens[t].destroy();this.tweens=null,this.current=null}}}),C=i.config={defaultUnit:"px",defaultAngle:"deg",keepInherited:!1,hideBackface:!1,perspective:"",fallback:!S.transition,agentTests:[]};i.fallback=function(t){if(!S.transition)return C.fallback=!0;C.agentTests.push("("+t+")");var i=RegExp(C.agentTests.join("|"),"i");C.fallback=i.test(navigator.userAgent)},i.fallback("6.0.[2-5] Safari"),i.tween=function(t){return new X(t)},i.delay=function(t,i,e){return new Y({complete:i,duration:t,context:e})},t.fn.tram=function(t){return i.call(null,this,t)};var D=t.style,L=t.css,Q={transform:S.transform&&S.transform.css},W={color:[N,y],background:[N,y,"background-color"],"outline-color":[N,y],"border-color":[N,y],"border-top-color":[N,y],"border-right-color":[N,y],"border-bottom-color":[N,y],"border-left-color":[N,y],"border-width":[H,w],"border-top-width":[H,w],"border-right-width":[H,w],"border-bottom-width":[H,w],"border-left-width":[H,w],"border-spacing":[H,w],"letter-spacing":[H,w],margin:[H,w],"margin-top":[H,w],"margin-right":[H,w],"margin-bottom":[H,w],"margin-left":[H,w],padding:[H,w],"padding-top":[H,w],"padding-right":[H,w],"padding-bottom":[H,w],"padding-left":[H,w],"outline-width":[H,w],opacity:[H,g],top:[H,k],right:[H,k],bottom:[H,k],left:[H,k],"font-size":[H,k],"text-indent":[H,k],"word-spacing":[H,k],width:[H,k],"min-width":[H,k],"max-width":[H,k],height:[H,k],"min-height":[H,k],"max-height":[H,k],"line-height":[H,z],"scroll-top":[O,g,"scrollTop"],"scroll-left":[O,g,"scrollLeft"]},J={};S.transform&&(W.transform=[P],J={x:[k,"translateX"],y:[k,"translateY"],rotate:[x],rotateX:[x],rotateY:[x],scale:[g],scaleX:[g],scaleY:[g],skew:[x],skewX:[x],skewY:[x]}),S.transform&&S.backface&&(J.z=[k,"translateZ"],J.rotateZ=[x],J.scaleZ=[g],J.perspective=[w]);var K=/ms/,V=/s|\./,_=function(){var t="warn",i=window.console;return i&&i[t]?function(e){i[t](e)}:s}();return t.tram=i}(window.jQuery);/*! + * jQuery-ajaxTransport-XDomainRequest - v1.0.1 - 2013-10-17 + * https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest + * Copyright (c) 2013 Jason Moon (@JSONMOON) + * Licensed MIT (/blob/master/LICENSE.txt) + */ +(function($){if(!$.support.cors&&$.ajaxTransport&&window.XDomainRequest){var n=/^https?:\/\//i;var o=/^get|post$/i;var p=new RegExp('^'+location.protocol,'i');var q=/text\/html/i;var r=/\/json/i;var s=/\/xml/i;$.ajaxTransport('* text html xml json',function(i,j,k){if(i.crossDomain&&i.async&&o.test(i.type)&&n.test(i.url)&&p.test(i.url)){var l=null;var m=(j.dataType||'').toLowerCase();return{send:function(f,g){l=new XDomainRequest();if(/^\d+$/.test(j.timeout)){l.timeout=j.timeout}l.ontimeout=function(){g(500,'timeout')};l.onload=function(){var a='Content-Length: '+l.responseText.length+'\r\nContent-Type: '+l.contentType;var b={code:200,message:'success'};var c={text:l.responseText};try{if(m==='html'||q.test(l.contentType)){c.html=l.responseText}else if(m==='json'||(m!=='text'&&r.test(l.contentType))){try{c.json=$.parseJSON(l.responseText)}catch(e){b.code=500;b.message='parseerror'}}else if(m==='xml'||(m!=='text'&&s.test(l.contentType))){var d=new ActiveXObject('Microsoft.XMLDOM');d.async=false;try{d.loadXML(l.responseText)}catch(e){d=undefined}if(!d||!d.documentElement||d.getElementsByTagName('parsererror').length){b.code=500;b.message='parseerror';throw'Invalid XML: '+l.responseText;}c.xml=d}}catch(parseMessage){throw parseMessage;}finally{g(b.code,b.message,c,a)}};l.onprogress=function(){};l.onerror=function(){g(500,'error',{text:l.responseText})};var h='';if(j.data){h=($.type(j.data)==='string')?j.data:$.param(j.data)}l.open(i.type,i.url);l.send(h)},abort:function(){if(l){l.abort()}}}}})}})(jQuery); +/*! + * tap.js + * Copyright (c) 2013 Alex Gibson, http://alxgbsn.co.uk/ + * Released under MIT license + */ +(function (window, document) { + + 'use strict'; + + function Tap(el) { + el = typeof el === 'object' ? el : document.getElementById(el); + this.element = el; + this.moved = false; //flags if the finger has moved + this.startX = 0; //starting x coordinate + this.startY = 0; //starting y coordinate + this.hasTouchEventOccured = false; //flag touch event + el.addEventListener('touchstart', this, false); + el.addEventListener('touchmove', this, false); + el.addEventListener('touchend', this, false); + el.addEventListener('touchcancel', this, false); + el.addEventListener('mousedown', this, false); + el.addEventListener('mouseup', this, false); + } + + Tap.prototype.start = function (e) { + if (e.type === 'touchstart') { + this.hasTouchEventOccured = true; + } + this.moved = false; + this.startX = e.type === 'touchstart' ? e.touches[0].clientX : e.clientX; + this.startY = e.type === 'touchstart' ? e.touches[0].clientY : e.clientY; + }; + + Tap.prototype.move = function (e) { + //if finger moves more than 10px flag to cancel + if (Math.abs(e.touches[0].clientX - this.startX) > 10 || Math.abs(e.touches[0].clientY - this.startY) > 10) { + this.moved = true; + } + }; + + Tap.prototype.end = function (e) { + var evt; + + if (this.hasTouchEventOccured && e.type === 'mouseup') { + e.preventDefault(); + e.stopPropagation(); + this.hasTouchEventOccured = false; + return; + } + + if (!this.moved) { + //create custom event + if (typeof document.CustomEvent !== "undefined") { + evt = new document.CustomEvent('tap', { + bubbles: true, + cancelable: true + }); + } else { + evt = document.createEvent('Event'); + evt.initEvent('tap', true, true); + } + e.target.dispatchEvent(evt); + } + }; + + Tap.prototype.cancel = function (e) { + this.hasTouchEventOccured = false; + this.moved = false; + this.startX = 0; + this.startY = 0; + }; + + Tap.prototype.destroy = function () { + var el = this.element; + el.removeEventListener('touchstart', this, false); + el.removeEventListener('touchmove', this, false); + el.removeEventListener('touchend', this, false); + el.removeEventListener('touchcancel', this, false); + el.removeEventListener('mousedown', this, false); + el.removeEventListener('mouseup', this, false); + this.element = null; + }; + + Tap.prototype.handleEvent = function (e) { + switch (e.type) { + case 'touchstart': this.start(e); break; + case 'touchmove': this.move(e); break; + case 'touchend': this.end(e); break; + case 'touchcancel': this.cancel(e); break; + case 'mousedown': this.start(e); break; + case 'mouseup': this.end(e); break; + } + }; + + window.Tap = Tap; + +}(window, document)); +/* jshint ignore:end */ +/** + * ---------------------------------------------------------------------- + * Init lib after plugins + */ +Webflow.init(); +/** + * ---------------------------------------------------------------------- + * Webflow: Interactions + */ +Webflow.define('ix', function ($, _) { + 'use strict'; + + var api = {}; + var designer; + var $win = $(window); + var namespace = '.w-ix'; + var tram = window.tram; + var env = Webflow.env; + var ios = env.ios; + var inApp = env(); + var emptyFix = env.chrome && env.chrome < 35; + var transNone = 'none 0s ease 0s'; + var introEvent = 'w-ix-intro' + namespace; + var outroEvent = 'w-ix-outro' + namespace; + var eventQueue = []; + var $subs = $(); + var config = {}; + var anchors = []; + var loads = []; + var readys = []; + var unique = 0; + var store; + + // ----------------------------------- + // Module methods + + api.init = function (list) { + setTimeout(function () { init(list); }, 1); + }; + + api.preview = function () { + designer = false; + setTimeout(function () { init(window.__wf_ix); }, 1); + }; + + api.design = function () { + designer = true; + $subs.each(teardown); + Webflow.scroll.off(scroll); + asyncEvents(); + anchors = []; + loads = []; + readys = []; + }; + + api.run = run; + api.events = {}; + api.style = inApp ? styleApp : stylePub; + + // ----------------------------------- + // Private methods + + function init(list) { + if (!list) return; + store = {}; + + // Map all interactions to a hash using slug as key. + config = {}; + _.each(list, function (item) { + config[item.slug] = item.value; + }); + + // Build each element's interaction keying from data attribute + var els = $('[data-ix]'); + els.each(teardown); + els.each(build); + + // Listen for scroll events if any anchors exist + if (anchors.length) { + Webflow.scroll.on(scroll); + setTimeout(scroll, 1); + } + + // Handle loads or readys if they exist + if (loads.length) $win.on('load', runLoads); + if (readys.length) setTimeout(runReadys, 1); + + // Init module events + initEvents(); + } + + function build(i, el) { + var $el = $(el); + var id = $el.attr('data-ix'); + var ix = config[id]; + if (!ix) return; + var triggers = ix.triggers; + if (!triggers) return; + var state = store[id] || (store[id] = {}); + var $proxy; + + // Set initial styles, unless we detect an iOS device + any non-iOS triggers + var setStyles = !(ios && _.any(triggers, isNonIOS)); + if (setStyles) api.style($el, ix.style); + + _.each(triggers, function (trigger) { + var type = trigger.type; + var stepsB = trigger.stepsB && trigger.stepsB.length; + + function runA() { run(trigger, $el, { group: 'A' }); } + function runB() { run(trigger, $el, { group: 'B' }); } + + if (type == 'load') { + (trigger.preload && !inApp) ? loads.push(runA) : readys.push(runA); + return; + } + + if (type == 'click') { + var stateKey = 'click:' + unique++; + if (trigger.descend) stateKey += ':descend'; + if (trigger.siblings) stateKey += ':siblings'; + if (trigger.selector) stateKey += ':' + trigger.selector; + + $el.on('click' + namespace, function (evt) { + if ($el.attr('href') === '#') evt.preventDefault(); + + run(trigger, $el, { group: state[stateKey] ? 'B' : 'A' }); + if (stepsB) state[stateKey] = !state[stateKey]; + }); + $subs = $subs.add($el); + return; + } + + if (type == 'hover') { + $el.on('mouseenter' + namespace, runA); + $el.on('mouseleave' + namespace, runB); + $subs = $subs.add($el); + return; + } + + if (type == 'tabs') { + $proxy = $el.closest('.w-tab-link, .w-tab-pane'); + $proxy.on(introEvent, runA).on(outroEvent, runB); + $subs = $subs.add($proxy); + return; + } + + if (type == 'slider') { + $proxy = $el.closest('.w-slide'); + $proxy.on(introEvent, runA).on(outroEvent, runB); + $subs = $subs.add($proxy); + return; + } + + // Ignore the following triggers on iOS devices + if (ios) return; + + if (type == 'scroll') { + anchors.push({ + el: $el, trigger: trigger, state: { active: false }, + offsetTop: convert(trigger.offsetTop), + offsetBot: convert(trigger.offsetBot) + }); + return; + } + }); + } + + function isNonIOS(trigger) { + return trigger.type == 'scroll'; + } + + function convert(offset) { + if (!offset) return 0; + offset = offset + ''; + var result = parseInt(offset, 10); + if (result !== result) return 0; + if (offset.indexOf('%') > 0) { + result = result / 100; + if (result >= 1) result = 0.999; + } + return result; + } + + function teardown(i, el) { + $(el).off(namespace); + } + + function scroll() { + var viewTop = $win.scrollTop(); + var viewHeight = $win.height(); + + // Check each anchor for a valid scroll trigger + var count = anchors.length; + for (var i = 0; i < count; i++) { + var anchor = anchors[i]; + var $el = anchor.el; + var trigger = anchor.trigger; + var stepsB = trigger.stepsB && trigger.stepsB.length; + var state = anchor.state; + var top = $el.offset().top; + var height = $el.outerHeight(); + var offsetTop = anchor.offsetTop; + var offsetBot = anchor.offsetBot; + if (offsetTop < 1 && offsetTop > 0) offsetTop *= viewHeight; + if (offsetBot < 1 && offsetBot > 0) offsetBot *= viewHeight; + var active = (top + height - offsetTop >= viewTop && top + offsetBot <= viewTop + viewHeight); + if (active === state.active) continue; + if (active === false && !stepsB) continue; + state.active = active; + run(trigger, $el, { group: active ? 'A' : 'B' }); + } + } + + function runLoads() { + var count = loads.length; + for (var i = 0; i < count; i++) { + loads[i](); + } + } + + function runReadys() { + var count = readys.length; + for (var i = 0; i < count; i++) { + readys[i](); + } + } + + function run(trigger, $el, opts, replay) { + opts = opts || {}; + var done = opts.done; + + // Do not run in designer unless forced + if (designer && !opts.force) return; + + // Operate on a set of grouped steps + var group = opts.group || 'A'; + var loop = trigger['loop' + group]; + var steps = trigger['steps' + group]; + if (!steps || !steps.length) return; + if (steps.length < 2) loop = false; + + // One-time init before any loops + if (!replay) { + + // Find selector within element descendants, siblings, or query whole document + var selector = trigger.selector; + if (selector) { + $el = ( + trigger.descend ? $el.find(selector) : + trigger.siblings ? $el.siblings(selector) : + $(selector) + ); + if (inApp) $el.attr('data-ix-affect', 1); + } + + // Apply empty fix for certain Chrome versions + if (emptyFix) $el.addClass('w-ix-emptyfix'); + } + + var _tram = tram($el); + + // Add steps + var meta = {}; + for (var i = 0; i < steps.length; i++) { + addStep(_tram, steps[i], meta); + } + + function fin() { + // Run trigger again if looped + if (loop) return run(trigger, $el, opts, true); + + // Reset any 'auto' values + if (meta.width == 'auto') _tram.set({ width: 'auto' }); + if (meta.height == 'auto') _tram.set({ height: 'auto' }); + + // Run callback + done && done(); + } + + // Add final step to queue if tram has started + meta.start ? _tram.then(fin) : fin(); + } + + function addStep(_tram, step, meta) { + var addMethod = 'add'; + var startMethod = 'start'; + + // Once the transition has started, we will always use then() to add to the queue. + if (meta.start) addMethod = startMethod = 'then'; + + // Parse transitions string on the current step + var transitions = step.transition; + if (transitions) { + transitions = transitions.split(','); + for (var i = 0; i < transitions.length; i++) { + _tram[addMethod](transitions[i]); + } + } + + // Build a clean object to pass to the tram method + var clean = tramify(step) || {}; + + // Store last width and height values + if (clean.width != null) meta.width = clean.width; + if (clean.height != null) meta.height = clean.height; + + // When transitions are not present, set values immediately and continue queue. + if (transitions == null) { + + // If we have started, wrap set() in then() and reset queue + if (meta.start) { + _tram.then(function () { + var queue = this.queue; + this.set(clean); + if (clean.display) { + _tram.redraw(); + Webflow.redraw.up(); + } + this.queue = queue; + this.next(); + }); + } else { + _tram.set(clean); + + // Always redraw after setting display + if (clean.display) { + _tram.redraw(); + Webflow.redraw.up(); + } + } + + // Use the wait() method to kick off queue in absence of transitions. + var wait = clean.wait; + if (wait != null) { + _tram.wait(wait); + meta.start = true; + } + + // Otherwise, when transitions are present + } else { + + // If display is present, handle it separately + if (clean.display) { + var display = clean.display; + delete clean.display; + + // If we've already started, we need to wrap it in a then() + if (meta.start) { + _tram.then(function () { + var queue = this.queue; + this.set({ display: display }).redraw(); + Webflow.redraw.up(); + this.queue = queue; + this.next(); + }); + } else { + _tram.set({ display: display }).redraw(); + Webflow.redraw.up(); + } + } + + // Otherwise, start a transition using the current start method. + _tram[startMethod](clean); + meta.start = true; + } + } + + // (In app) Set styles immediately and manage upstream transition + function styleApp(el, data) { + var _tram = tram(el); + + // Get computed transition value + el.css('transition', ''); + var computed = el.css('transition'); + + // If computed is disabled, clear upstream + if (computed === transNone) computed = _tram.upstream = null; + + // Disable upstream temporarily + _tram.upstream = transNone; + + // Set values immediately + _tram.set(tramify(data)); + + // Only restore upstream in preview mode + _tram.upstream = computed; + } + + // (Published) Set styles immediately on specified jquery element + function stylePub(el, data) { + tram(el).set(tramify(data)); + } + + // Build a clean object for tram + function tramify(obj) { + var result = {}; + var found = false; + for (var x in obj) { + if (x === 'transition') continue; + result[x] = obj[x]; + found = true; + } + // If empty, return null for tram.set/stop compliance + return found ? result : null; + } + + // Events used by other webflow modules + var events = { + reset: function (i, el) { + el.__wf_intro = null; + }, + intro: function (i, el) { + if (el.__wf_intro) return; + el.__wf_intro = true; + $(el).triggerHandler(introEvent); + }, + outro: function (i, el) { + if (!el.__wf_intro) return; + el.__wf_intro = null; + $(el).triggerHandler(outroEvent); + } + }; + + // Trigger events in queue + point to sync methods + function initEvents() { + var count = eventQueue.length; + for (var i = 0; i < count; i++) { + var memo = eventQueue[i]; + memo[0](0, memo[1]); + } + eventQueue = []; + $.extend(api.events, events); + } + + // Replace events with async methods prior to init + function asyncEvents() { + _.each(events, function (func, name) { + api.events[name] = function (i, el) { + eventQueue.push([func, el]); + }; + }); + } + + asyncEvents(); + + // Export module + return api; +}); +/** + * ---------------------------------------------------------------------- + * Webflow: Touch events for jQuery based on tap.js + */ +Webflow.define('touch', function ($, _) { + 'use strict'; + + var Tap = window.Tap; + var namespace = '.w-events-'; + var dataKey = namespace + 'tap'; + var fallback = !document.addEventListener; + + // jQuery event "tap" - use click in old + non-touch browsers + $.event.special.tap = (fallback || !Webflow.env.touch) ? { bindType: 'click', delegateType: 'click' } : { + setup: function () { + $.data(this, dataKey, new Tap(this)); + + // Returning false instructs jQuery to use native `addEventListener` on the element. + return false; + }, + teardown: function () { + var tap = $.data(this, dataKey); + if (tap && tap.destroy) { + tap.destroy(); + $.removeData(this, dataKey); + } + + // Returning false makes sure the native event handlers bound above are removed. + return false; + } + }; + + // No swipe events for old browsers + if (fallback || !Object.create) return; + + // jQuery event "swipe" + dataKey = namespace + 'swipe'; + + $.event.special.swipe = { + setup: function () { + $.data(this, dataKey, new Swipe(this)); + + // Returning false instructs jQuery to use native `addEventListener` on the element. + return false; + }, + teardown: function () { + var tap = $.data(this, dataKey); + if (tap && tap.destroy) { + tap.destroy(); + $.removeData(this, dataKey); + } + + // Returning false makes sure the native event handlers bound above are removed. + return false; + } + }; + + /** + * Swipe - extends Tap, supports mouse swipes! + */ + function Swipe(el) { + Tap.call(this, el); + } + + (function () { + var supr = Tap.prototype; + var proto = Swipe.prototype = Object.create(supr); + var threshold = Math.round(screen.width * 0.04) || 20; + if (threshold > 40) threshold = 40; + + proto.start = function (e) { + supr.start.call(this, e); + this.element.addEventListener('mousemove', this, false); + document.addEventListener('mouseup', this, false); + this.velocityX = 0; + this.lastX = this.startX; + this.enabled = true; + }; + + proto.move = _.throttle(function (e) { + if (!this.enabled) return; + var x = e.touches ? e.touches[0].clientX : e.clientX; + this.velocityX = x - this.lastX; + this.lastX = x; + if (Math.abs(this.velocityX) > threshold) { + this.end(e); + } + }); + + proto.end = function (e) { + if (!this.enabled) return; + var velocityX = this.velocityX; + this.cancel(); + if (Math.abs(velocityX) > threshold) { + $(this.element).triggerHandler('swipe', { direction: velocityX > 0 ? 'right' : 'left' }); + } + }; + + proto.destroy = function () { + this.cancel(); + supr.destroy.call(this); + }; + + proto.cancel = function () { + this.enabled = false; + this.element.removeEventListener('mousemove', this, false); + document.removeEventListener('mouseup', this, false); + supr.cancel.call(this); + }; + + proto.handleEvent = function (e) { + if (e.type == 'mousemove') return this.move(e); + supr.handleEvent.call(this, e); + }; + }()); + +}); +/** + * ---------------------------------------------------------------------- + * Webflow: Forms + */ +Webflow.define('forms', function ($, _) { + 'use strict'; + + var api = {}; + var $doc = $(document); + var $forms; + var loc = window.location; + var retro = window.XDomainRequest && !window.atob; + var namespace = '.w-form'; + var siteId; + var emailField = /e(\-)?mail/i; + var emailValue = /^\S+@\S+$/; + var alert = window.alert; + + // MailChimp domains: list-manage.com + mirrors + var chimpRegex = /list-manage[1-9]?.com/i; + + api.ready = function () { + // Init forms + init(); + + // Wire events + listen && listen(); + listen = null; + }; + + api.preview = api.design = function () { + init(); + }; + + function init() { + siteId = $('html').attr('data-wf-site'); + + $forms = $(namespace + ' form'); + $forms.each(build); + } + + function build(i, el) { + // Store form state using namespace + var $el = $(el); + var data = $.data(el, namespace); + if (!data) data = $.data(el, namespace, { form: $el }); // data.form + + reset(data); + var wrap = $el.closest('div.w-form'); + data.done = wrap.find('> .w-form-done'); + data.fail = wrap.find('> .w-form-fail'); + + var action = data.action = $el.attr('action'); + data.handler = null; + data.redirect = $el.attr('data-redirect'); + + // MailChimp form + if (chimpRegex.test(action)) { data.handler = submitMailChimp; return; } + + // Custom form action + if (action) return; + + // Webflow form + if (siteId) { data.handler = submitWebflow; return; } + + // Alert for disconnected Webflow forms + disconnected(); + } + + function listen() { + // Handle form submission for Webflow forms + $doc.on('submit', namespace + ' form', function(evt) { + var data = $.data(this, namespace); + if (data.handler) { + data.evt = evt; + data.handler(data); + } + }); + } + + // Reset data common to all submit handlers + function reset(data) { + var btn = data.btn = data.form.find(':input[type="submit"]'); + data.wait = data.btn.attr('data-wait') || null; + data.success = false; + btn.prop('disabled', false); + data.label && btn.val(data.label); + } + + // Disable submit button + function disableBtn(data) { + var btn = data.btn; + var wait = data.wait; + btn.prop('disabled', true); + // Show wait text and store previous label + if (wait) { + data.label = btn.val(); + btn.val(wait); + } + } + + // Find form fields, validate, and set value pairs + function findFields(form, result) { + var status = null; + result = result || {}; + + // The ":input" selector is a jQuery shortcut to select all inputs, selects, textareas + form.find(':input:not([type="submit"])').each(function(i, el) { + var field = $(el); + var type = field.attr('type'); + var name = field.attr('data-name') || field.attr('name') || ('Field ' + (i + 1)); + var value = field.val(); + + if (type == 'checkbox') { + value = field.is(':checked'); + } if (type == 'radio') { + // Radio group value already processed + if (result[name] === null || typeof result[name] == 'string') { + return; + } + + value = form.find('input[name="' + field.attr('name') + '"]:checked').val() || null; + } + + if (typeof value == 'string') value = $.trim(value); + result[name] = value; + status = status || getStatus(field, name, value); + }); + + return status; + } + + function getStatus(field, name, value) { + var status = null; + if (!field.attr('required')) return null; + if (!value) status = 'Please fill out the required field: ' + name; + else if (emailField.test(name) || emailField.test(field.attr('type'))) { + if (!emailValue.test(value)) status = 'Please enter a valid email address for: ' + name; + } + return status; + } + + // Submit form to Webflow + function submitWebflow(data) { + reset(data); + + var form = data.form; + var payload = { + name: form.attr('data-name') || form.attr('name') || 'Untitled Form', + source: loc.href, + test: Webflow.env(), + fields: {} + }; + + preventDefault(data); + + // Find & populate all fields + var status = findFields(form, payload.fields); + if (status) return alert(status); + + // Disable submit button + disableBtn(data); + + // Read site ID + // NOTE: If this site is exported, the HTML tag must retain the data-wf-site attribute for forms to work + if (!siteId) { afterSubmit(data); return; } + var url = 'https://webflow.com/api/v1/form/' + siteId; + + // Work around same-protocol IE XDR limitation + if (retro && url.indexOf('https://webflow.com') >= 0) { + url = url.replace('https://webflow.com/', 'http://data.webflow.com/'); + } + + $.ajax({ + url: url, + type: 'POST', + data: payload, + dataType: 'json', + crossDomain: true + }).done(function () { + data.success = true; + afterSubmit(data); + }).fail(function () { + afterSubmit(data); + }); + } + + // Submit form to MailChimp + function submitMailChimp(data) { + reset(data); + + var form = data.form; + var payload = {}; + + // Skip Ajax submission if http/s mismatch, fallback to POST instead + if (/^https/.test(loc.href) && !/^https/.test(data.action)) { + form.attr('method', 'post'); + return; + } + + preventDefault(data); + + // Find & populate all fields + var status = findFields(form, payload); + if (status) return alert(status); + + // Disable submit button + disableBtn(data); + + // Use special format for MailChimp params + var fullName; + _.each(payload, function (value, key) { + if (emailField.test(key)) payload.EMAIL = value; + if (/^((full[ _-]?)?name)$/i.test(key)) fullName = value; + if (/^(first[ _-]?name)$/i.test(key)) payload.FNAME = value; + if (/^(last[ _-]?name)$/i.test(key)) payload.LNAME = value; + }); + + if (fullName && !payload.FNAME) { + fullName = fullName.split(' '); + payload.FNAME = fullName[0]; + payload.LNAME = payload.LNAME || fullName[1]; + } + + // Use the (undocumented) MailChimp jsonp api + var url = data.action.replace('/post?', '/post-json?') + '&c=?'; + // Add special param to prevent bot signups + var userId = url.indexOf('u=')+2; + userId = url.substring(userId, url.indexOf('&', userId)); + var listId = url.indexOf('id=')+3; + listId = url.substring(listId, url.indexOf('&', listId)); + payload['b_' + userId + '_' + listId] = ''; + + $.ajax({ + url: url, + data: payload, + dataType: 'jsonp' + }).done(function (resp) { + data.success = (resp.result == 'success' || /already/.test(resp.msg)); + if (!data.success) console.info('MailChimp error: ' + resp.msg); + afterSubmit(data); + }).fail(function () { + afterSubmit(data); + }); + } + + // Common callback which runs after all Ajax submissions + function afterSubmit(data) { + var form = data.form; + var wrap = form.closest('div.w-form'); + var redirect = data.redirect; + var success = data.success; + + // Redirect to a success url if defined + if (success && redirect) { + Webflow.location(redirect); + return; + } + + // Show or hide status divs + data.done.toggle(success); + data.fail.toggle(!success); + + // Hide form on success + form.toggle(!success); + + // Reset data and enable submit button + reset(data); + } + + function preventDefault(data) { + data.evt && data.evt.preventDefault(); + data.evt = null; + } + + var disconnected = _.debounce(function () { + alert('Oops! This page has a form that is powered by Webflow, but important code was removed that is required to make the form work. Please contact support@webflow.com to fix this issue.'); + }, 100); + + // Export module + return api; +}); +/** + * ---------------------------------------------------------------------- + * Webflow: Maps widget + */ +Webflow.define('maps', function ($, _) { + 'use strict'; + + var api = {}; + var $doc = $(document); + var google; + var $maps; + var namespace = '.w-widget-map'; + + // ----------------------------------- + // Module methods + + api.ready = function () { + // Init Maps on the front-end + if (!Webflow.env()) initMaps(); + }; + + api.preview = function () { + // Update active map nodes + $maps = $doc.find(namespace); + // Listen for resize events + Webflow.resize.off(triggerRedraw); + if ($maps.length) { + Webflow.resize.on(triggerRedraw); + triggerRedraw(); + } + }; + + api.design = function (evt) { + // Update active map nodes + $maps = $doc.find(namespace); + // Stop listening for resize events + Webflow.resize.off(triggerRedraw); + // Redraw to account for page changes + $maps.length && _.defer(triggerRedraw); + }; + + // ----------------------------------- + // Private methods + + // Trigger redraw in designer or preview mode + function triggerRedraw() { + if ($maps.length && Webflow.app) { + $maps.each(Webflow.app.redrawElement); + } + } + + function initMaps() { + $maps = $doc.find(namespace); + if ($maps.length) { + Webflow.script('https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=_wf_maps_loaded'); + window._wf_maps_loaded = function () { + window._wf_maps_loaded = function () {}; + google = window.google; + $maps.each(renderMap); + Webflow.resize.on(resizeMaps); + Webflow.redraw.on(resizeMaps); + }; + } + } + + // Render map onto each element + function renderMap(i, el) { + var data = $(el).data(); + getState(el, data); + } + + function resizeMaps() { + $maps.each(resizeMap); + } + + // Resize map when window changes + function resizeMap(i, el) { + var state = getState(el); + google.maps.event.trigger(state.map, 'resize'); + state.setMapPosition(); + } + + // Store state on element data + var store = 'w-widget-map'; + function getState(el, data) { + + var state = $.data(el, store); + if (state) return state; + + var $el = $(el); + state = $.data(el, store, { + // Default options + latLng: '51.511214,-0.119824', + tooltip: '', + style: 'roadmap', + zoom: 12, + + // Marker + marker: new google.maps.Marker({ + draggable: false + }), + + // Tooltip infowindow + infowindow: new google.maps.InfoWindow({ + disableAutoPan: true + }) + }); + + // LatLng center point + var latLng = data.widgetLatlng || state.latLng; + state.latLng = latLng; + var coords = latLng.split(','); + var latLngObj = new google.maps.LatLng(coords[0], coords[1]); + state.latLngObj = latLngObj; + + // Disable touch events + var mapDraggable = (Webflow.env.touch && data.disableTouch) ? false : true; + + // Map instance + state.map = new google.maps.Map(el, { + center: state.latLngObj, + zoom: state.zoom, + maxZoom: 18, + mapTypeControl: false, + panControl: false, + streetViewControl: false, + scrollwheel: !data.disableScroll, + draggable: mapDraggable, + zoomControl: true, + zoomControlOptions: { + style: google.maps.ZoomControlStyle.SMALL + }, + mapTypeId: state.style + }); + state.marker.setMap(state.map); + + // Set map position and offset + state.setMapPosition = function () { + state.map.setCenter(state.latLngObj); + var offsetX = 0; + var offsetY = 0; + var padding = $el.css(['paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft']); + offsetX -= parseInt(padding.paddingLeft, 10); + offsetX += parseInt(padding.paddingRight, 10); + offsetY -= parseInt(padding.paddingTop, 10); + offsetY += parseInt(padding.paddingBottom, 10); + if (offsetX || offsetY) { + state.map.panBy(offsetX, offsetY); + } + $el.css('position', ''); // Remove injected position + }; + + // Fix position after first tiles have loaded + google.maps.event.addListener(state.map, 'tilesloaded', function () { + google.maps.event.clearListeners(state.map, 'tilesloaded'); + state.setMapPosition(); + }); + + // Set initial position + state.setMapPosition(); + state.marker.setPosition(state.latLngObj); + state.infowindow.setPosition(state.latLngObj); + + // Draw tooltip + var tooltip = data.widgetTooltip; + if (tooltip) { + state.tooltip = tooltip; + state.infowindow.setContent(tooltip); + if (!state.infowindowOpen) { + state.infowindow.open(state.map, state.marker); + state.infowindowOpen = true; + } + } + + // Map style - options.style + var style = data.widgetStyle; + if (style) { + state.map.setMapTypeId(style); + } + + // Zoom - options.zoom + var zoom = data.widgetZoom; + if (zoom != null) { + state.zoom = zoom; + state.map.setZoom(+zoom); + } + + // Click marker to open in google maps + google.maps.event.addListener(state.marker, 'click', function() { + window.open('https://maps.google.com/?z=' + state.zoom + '&daddr=' + state.latLng); + }); + + return state; + } + + // Export module + return api; +}); +/** + * ---------------------------------------------------------------------- + * Webflow: Google+ widget + */ +Webflow.define('gplus', function ($) { + 'use strict'; + + var $doc = $(document); + var api = {}; + + api.ready = function () { + // Load Google+ API on the front-end + if (!Webflow.env()) init(); + }; + + function init() { + $doc.find('.w-widget-gplus').length && Webflow.script('https://apis.google.com/js/plusone.js'); + } + + // Export module + return api; +}); +/** + * ---------------------------------------------------------------------- + * Webflow: Smooth scroll + */ +Webflow.define('scroll', function ($) { + 'use strict'; + + var $doc = $(document); + var win = window; + var loc = win.location; + var validHash = /^[a-zA-Z][\w:.-]*$/; + + function ready() { + // If hash is already present on page load, scroll to it right away + if (loc.hash) { + findEl(loc.hash.substring(1)); + } + + // When clicking on a link, check if it links to another part of the page + $doc.on('click', 'a', function(e) { + if (Webflow.env('design')) { + return; + } + + // Ignore links being used by jQuery mobile + if (window.$.mobile && $(e.currentTarget).hasClass('ui-link')) return; + + var hash = this.hash ? this.hash.substring(1) : null; + if (hash) { + findEl(hash, e); + } + }); + } + + function findEl(hash, e) { + if (!validHash.test(hash)) return; + + var el = $('#' + hash); + if (!el.length) { + return; + } + + if (e) { + e.preventDefault(); + e.stopPropagation(); + } + + // Push new history state + if (loc.hash !== hash && win.history && win.history.pushState) { + win.history.pushState(null, null, '#' + hash); + } + + // If a fixed header exists, offset for the height + var header = $('header, body > .header, body > .w-nav'); + var offset = header.css('position') === 'fixed' ? header.outerHeight() : 0; + + win.setTimeout(function() { + scroll(el, offset); + }, e ? 0 : 300); + } + + function scroll(el, offset){ + var start = $(win).scrollTop(); + var end = el.offset().top - offset; + + // If specified, scroll so that the element ends up in the middle of the viewport + if (el.data('scroll') == 'mid') { + var available = $(win).height() - offset; + var elHeight = el.outerHeight(); + if (elHeight < available) { + end -= Math.round((available - elHeight) / 2); + } + } + + var mult = 1; + + // Check for custom time multiplier on the body and the element + $('body').add(el).each(function(i) { + var time = parseFloat($(this).attr('data-scroll-time'), 10); + if (!isNaN(time) && (time === 0 || time > 0)) { + mult = time; + } + }); + + // Shim for IE8 and below + if (!Date.now) { + Date.now = function() { return new Date().getTime(); }; + } + + var clock = Date.now(); + var animate = win.requestAnimationFrame || win.mozRequestAnimationFrame || win.webkitRequestAnimationFrame || function(fn) { win.setTimeout(fn, 15); }; + var duration = (472.143 * Math.log(Math.abs(start - end) +125) - 2000) * mult; + + var step = function() { + var elapsed = Date.now() - clock; + win.scroll(0, getY(start, end, elapsed, duration)); + + if (elapsed <= duration) { + animate(step); + } + }; + + step(); + } + + function getY(start, end, elapsed, duration) { + if (elapsed > duration) { + return end; + } + + return start + (end - start) * ease(elapsed / duration); + } + + function ease(t) { + return t<0.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1; + } + + // Export module + return { ready: ready }; +}); +/** + * ---------------------------------------------------------------------- + * Webflow: Auto-select links to current page or section + */ +Webflow.define('links', function ($, _) { + 'use strict'; + + var api = {}; + var $win = $(window); + var designer; + var inApp = Webflow.env(); + var location = window.location; + var linkCurrent = 'w--current'; + var validHash = /^#[a-zA-Z][\w:.-]*$/; + var indexPage = /index\.(html|php)$/; + var dirList = /\/$/; + var anchors; + + // ----------------------------------- + // Module methods + + api.ready = api.design = api.preview = init; + + // ----------------------------------- + // Private methods + + function init() { + designer = inApp && Webflow.env('design'); + + // Reset scroll listener, init anchors + Webflow.scroll.off(scroll); + anchors = []; + + // Test all links for a selectable href + var links = document.links; + for (var i = 0; i < links.length; ++i) { + select(links[i]); + } + + // Listen for scroll if any anchors exist + if (anchors.length) { + Webflow.scroll.on(scroll); + scroll(); + } + } + + function select(link) { + var href = link.getAttribute('href'); + + // Ignore any hrefs with a colon to safely avoid all uri schemes + if (href.indexOf(':') >= 0) return; + + var $link = $(link); + + // Check for valid hash links w/ sections and use scroll anchor + if (href.indexOf('#') === 0 && validHash.test(href)) { + var $section = $(href); + $section.length && anchors.push({ link: $link, sec: $section, active: false }); + return; + } + + // Determine whether the link should be selected + var slug = (inApp ? Webflow.env('slug') : location.pathname) || ''; + var match = (link.href === location.href) || (href === slug) || (indexPage.test(href) && dirList.test(slug)); + setClass($link, linkCurrent, match); + } + + function scroll() { + var viewTop = $win.scrollTop(); + var viewHeight = $win.height(); + + // Check each anchor for a section in view + _.each(anchors, function (anchor) { + var $link = anchor.link; + var $section = anchor.sec; + var top = $section.offset().top; + var height = $section.outerHeight(); + var offset = viewHeight * 0.5; + var active = ($section.is(':visible') && + top + height - offset >= viewTop && + top + offset <= viewTop + viewHeight); + if (anchor.active === active) return; + anchor.active = active; + setClass($link, linkCurrent, active); + if (designer) $link[0].__wf_current = active; + }); + } + + function setClass($elem, className, add) { + var exists = $elem.hasClass(className); + if (add && exists) return; + if (!add && !exists) return; + add ? $elem.addClass(className) : $elem.removeClass(className); + } + + // Export module + return api; +}); +/** + * ---------------------------------------------------------------------- + * Webflow: Slider component + */ +Webflow.define('slider', function ($, _) { + 'use strict'; + + var api = {}; + var tram = window.tram; + var $doc = $(document); + var $sliders; + var designer; + var inApp = Webflow.env(); + var namespace = '.w-slider'; + var dot = '
'; + var ix = Webflow.require('ix'); + ix = ix && ix.events; + var fallback; + var redraw; + + // ----------------------------------- + // Module methods + + api.ready = function () { + init(); + }; + + api.design = function () { + designer = true; + init(); + }; + + api.preview = function () { + designer = false; + init(); + }; + + api.redraw = function () { + redraw = true; + init(); + }; + + // ----------------------------------- + // Private methods + + function init() { + // Find all sliders on the page + $sliders = $doc.find(namespace); + $sliders.each(build); + redraw = null; + if (fallback) return; + + // Wire events + listen && listen(); + listen = null; + } + + function listen() { + Webflow.resize.on(function () { + $sliders.each(render); + }); + + Webflow.redraw.on(api.redraw); + } + + function build(i, el) { + var $el = $(el); + + // Store slider state in data + var data = $.data(el, namespace); + if (!data) data = $.data(el, namespace, { index: 0, el: $el, config: {} }); + data.mask = $el.children('.w-slider-mask'); + data.left = $el.children('.w-slider-arrow-left'); + data.right = $el.children('.w-slider-arrow-right'); + data.nav = $el.children('.w-slider-nav'); + data.slides = data.mask.children('.w-slide'); + if (ix) data.slides.each(ix.reset); + if (redraw) data.maskWidth = 0; + + // Disable in old browsers + if (!tram.support.transform) { + data.left.hide(); + data.right.hide(); + data.nav.hide(); + fallback = true; + return; + } + + // Remove old events + data.el.off(namespace); + data.left.off(namespace); + data.right.off(namespace); + data.nav.off(namespace); + + // Set config from data attributes + configure(data); + + // Add events based on mode + if (designer) { + data.el.on('setting' + namespace, handler(data)); + killTimer(data); + data.hasTimer = false; + } else { + data.el.on('swipe' + namespace, handler(data)); + data.left.on('tap' + namespace, previous(data)); + data.right.on('tap' + namespace, next(data)); + + // Start timer if autoplay is true, only once + if (data.config.autoplay && !data.hasTimer) { + data.hasTimer = true; + startTimer(data); + } + } + + // Listen to nav events + data.nav.on('tap' + namespace, '> div', handler(data)); + + // Remove gaps from formatted html (for inline-blocks) + if (!inApp) { + data.mask.contents().filter(function() { + return this.nodeType === 3; + }).remove(); + } + + // Run first render + render(i, el); + } + + function configure(data) { + var config = {}; + + config.depth = 1; + config.crossOver = 0; + + // Set config options from data attributes + config.animation = data.el.attr('data-animation') || 'slide'; + if (config.animation == 'outin') { + config.animation = 'cross'; + config.crossOver = 0.5; + } + config.easing = data.el.attr('data-easing') || 'ease'; + + var duration = data.el.attr('data-duration'); + config.duration = duration != null ? +duration : 500; + + if (+data.el.attr('data-infinite')) config.infinite = true; + + if (+data.el.attr('data-hide-arrows')) { + config.hideArrows = true; + } else if (data.config.hideArrows) { + data.left.show(); + data.right.show(); + } + + if (+data.el.attr('data-autoplay')) { + config.autoplay = true; + config.delay = +data.el.attr('data-delay') || 2000; + // Disable timer on first touch or mouse down + var touchEvents = 'mousedown' + namespace + ' touchstart' + namespace; + if (!designer) data.el.off(touchEvents).one(touchEvents, function () { + killTimer(data); + }); + } + + // Use edge buffer to help calculate page count + var arrowWidth = data.right.width(); + config.edge = arrowWidth ? arrowWidth + 40 : 100; + + // Store config in data + data.config = config; + } + + function previous(data) { + return function (evt) { + change(data, { index: data.index - 1, vector: -1 }); + }; + } + + function next(data) { + return function (evt) { + change(data, { index: data.index + 1, vector: 1 }); + }; + } + + function select(data, value) { + // Select page based on slide element index + var found = null; + if (value === data.slides.length) { + init(); layout(data); // Rebuild and find new slides + } + _.each(data.anchors, function (anchor, index) { + $(anchor.els).each(function (i, el) { + if ($(el).index() === value) found = index; + }); + }); + if (found != null) change(data, { index: found, immediate: true }); + } + + function startTimer(data) { + var config = data.config; + stopTimer(data); + config.timer = window.setTimeout(function () { + if (!config.autoplay || designer) return; + next(data)(); + startTimer(data); + }, config.delay); + } + + function stopTimer(data) { + var config = data.config; + window.clearTimeout(config.timer); + config.timer = null; + } + + function killTimer(data) { + var config = data.config; + config.autoplay = false; + stopTimer(data); + } + + function handler(data) { + return function (evt, options) { + options = options || {}; + + // Designer settings + if (designer && evt.type == 'setting') { + if (options.select == 'prev') return previous(data)(); + if (options.select == 'next') return next(data)(); + configure(data); + layout(data); + if (options.select == null) return; + select(data, options.select); + return; + } + + // Swipe event + if (evt.type == 'swipe') { + if (options.direction == 'left') return next(data)(); + if (options.direction == 'right') return previous(data)(); + return; + } + + // Page buttons + if (data.nav.has(evt.target).length) { + change(data, { index: $(evt.target).index() }); + } + }; + } + + function change(data, options) { + options = options || {}; + var config = data.config; + var anchors = data.anchors; + + // Set new index + data.previous = data.index; + var index = options.index; + var shift = {}; + if (index < 0) { + index = anchors.length-1; + if (config.infinite) { + // Shift first slide to the end + shift.x = -data.endX; + shift.from = 0; + shift.to = anchors[0].width; + } + } else if (index >= anchors.length) { + index = 0; + if (config.infinite) { + // Shift last slide to the start + shift.x = anchors[anchors.length-1].width; + shift.from = -anchors[anchors.length-1].x; + shift.to = shift.from - shift.x; + } + } + data.index = index; + + // Select page nav + var active = data.nav.children().eq(data.index).addClass('w-active'); + data.nav.children().not(active).removeClass('w-active'); + + // Hide arrows + if (config.hideArrows) { + data.index === anchors.length-1 ? data.right.hide() : data.right.show(); + data.index === 0 ? data.left.hide() : data.left.show(); + } + + // Get page offset from anchors + var lastOffsetX = data.offsetX || 0; + var offsetX = data.offsetX = -anchors[data.index].x; + var resetConfig = { x: offsetX, opacity: 1, visibility: '' }; + + // Transition slides + var targets = $(anchors[data.index].els); + var previous = $(anchors[data.previous] && anchors[data.previous].els); + var others = data.slides.not(targets); + var animation = config.animation; + var easing = config.easing; + var duration = Math.round(config.duration); + var vector = options.vector || (data.index > data.previous ? 1 : -1); + var fadeRule = 'opacity ' + duration + 'ms ' + easing; + var slideRule = 'transform ' + duration + 'ms ' + easing; + + // Trigger IX events + if (!designer && ix) { + targets.each(ix.intro); + others.each(ix.outro); + } + + // Set immediately after layout changes (but not during redraw) + if (options.immediate && !redraw) { + tram(targets).set(resetConfig); + resetOthers(); + return; + } + + // Exit early if index is unchanged + if (data.index == data.previous) return; + + // Cross Fade / Out-In + if (animation == 'cross') { + var reduced = Math.round(duration - duration * config.crossOver); + var wait = Math.round(duration - reduced); + fadeRule = 'opacity ' + reduced + 'ms ' + easing; + tram(previous) + .set({ visibility: '' }) + .add(fadeRule) + .start({ opacity: 0 }); + tram(targets) + .set({ visibility: '', x: offsetX, opacity: 0, zIndex: config.depth++ }) + .add(fadeRule) + .wait(wait) + .then({ opacity: 1 }) + .then(resetOthers); + return; + } + + // Fade Over + if (animation == 'fade') { + tram(previous) + .set({ visibility: '' }) + .stop(); + tram(targets) + .set({ visibility: '', x: offsetX, opacity: 0, zIndex: config.depth++ }) + .add(fadeRule) + .start({ opacity: 1 }) + .then(resetOthers); + return; + } + + // Slide Over + if (animation == 'over') { + resetConfig = { x: data.endX }; + tram(previous) + .set({ visibility: '' }) + .stop(); + tram(targets) + .set({ visibility: '', zIndex: config.depth++, x: offsetX + anchors[data.index].width * vector }) + .add(slideRule) + .start({ x: offsetX }) + .then(resetOthers); + return; + } + + // Slide - infinite scroll + if (config.infinite && shift.x) { + tram(data.slides.not(previous)) + .set({ visibility: '', x: shift.x }) + .add(slideRule) + .start({ x: offsetX }); + tram(previous) + .set({ visibility: '', x: shift.from }) + .add(slideRule) + .start({ x: shift.to }); + data.shifted = previous; + + } else { + if (config.infinite && data.shifted) { + tram(data.shifted).set({ visibility: '', x: lastOffsetX }); + data.shifted = null; + } + + // Slide - basic scroll + tram(data.slides) + .set({ visibility: '' }) + .add(slideRule) + .start({ x: offsetX }); + } + + // Helper to move others out of view + function resetOthers() { + var targets = $(anchors[data.index].els); + var others = data.slides.not(targets); + if (animation != 'slide') resetConfig.visibility = 'hidden'; + tram(others).set(resetConfig); + } + } + + function render(i, el) { + var data = $.data(el, namespace); + if (maskChanged(data)) return layout(data); + if (designer && slidesChanged(data)) layout(data); + } + + function layout(data) { + // Determine page count from width of slides + var pages = 1; + var offset = 0; + var anchor = 0; + var width = 0; + data.anchors = [{ els: [], x: 0, width: 0 }]; + data.slides.each(function (i, el) { + if (anchor - offset > data.maskWidth - data.config.edge) { + pages++; + offset += data.maskWidth; + // Store page anchor for transition + data.anchors[pages-1] = { els: [], x: anchor, width: 0 }; + } + // Set next anchor using current width + margin + width = $(el).outerWidth(true); + anchor += width; + data.anchors[pages-1].width += width; + data.anchors[pages-1].els.push(el); + }); + data.endX = anchor; + + // Build dots if nav exists and needs updating + if (designer) data.pages = null; + if (data.nav.length && data.pages !== pages){ + data.pages = pages; + buildNav(data); + } + + // Make sure index is still within range and call change handler + var index = data.index; + if (index >= pages) index = pages-1; + change(data, { immediate: true, index: index }); + } + + function buildNav(data) { + var dots = []; + var $dot; + var spacing = data.el.attr('data-nav-spacing'); + if (spacing) spacing = parseFloat(spacing) + 'px'; + for (var i=0; i= 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() - } -} diff --git a/validation.go b/validation.go deleted file mode 100644 index 610d10ac..00000000 --- a/validation.go +++ /dev/null @@ -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 -}