1
0
mirror of https://github.com/labstack/echo.git synced 2025-01-12 01:22:21 +02:00

Moved website from echo to echox

Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
Vishal Rana 2016-03-12 10:35:05 -08:00
parent 5b5df5bf44
commit 861712f469
43 changed files with 0 additions and 1830 deletions

View File

@ -1,7 +0,0 @@
FROM reg.lab.st/argo
MAINTAINER Vishal Rana <vr@labstack.com>
ADD argo.json /etc
ADD public /www
CMD ["-c", "/etc/argo.json"]

View File

@ -1,14 +0,0 @@
{
"www": {
"listen": ":80",
"hosts": {
"*": {
"paths": {
"/*": {
"dir": "/www"
}
}
}
}
}
}

View File

@ -1,27 +0,0 @@
{
"baseurl": "https://labstack.com/echo",
"languageCode": "en-us",
"title": "Echo",
"canonifyurls": true,
"menu": {
"side": [{
"name": "Guide",
"pre": "<i class='fa fa-book'></i>",
"weight": 1,
"identifier": "guide",
"url": "guide"
}, {
"Name": "Recipes",
"Pre": "<i class='fa fa-code'></i>",
"Weight": 2,
"Identifier": "recipes",
"URL": "recipes"
}]
},
"params": {
"description": "Golang micro web framework, High performance, Minimalistic and Fast.",
"googleAnayticsId": "UA-51208124-3"
}
}

View File

@ -1,106 +0,0 @@
---
title: Customization
menu:
side:
parent: guide
weight: 3
---
### HTTP error handler
`Echo#SetHTTPErrorHandler(h HTTPErrorHandler)`
Registers a custom `Echo#HTTPErrorHandler`.
Default handler rules:
- If error is of type `Echo#HTTPError` it sends HTTP response with status code `HTTPError.Code`
and message `HTTPError.Message`.
- Else it sends `500 - Internal Server Error`.
- If debug mode is enabled, it uses `error.Error()` as status message.
### Debug
`Echo#SetDebug(on bool)`
Enable/disable debug mode.
### Log prefix
`Echo#SetLogPrefix(prefix string)`
SetLogPrefix sets the prefix for the logger. Default value is `echo`.
### Log output
`Echo#SetLogOutput(w io.Writer)`
SetLogOutput sets the output destination for the logger. Default value is `os.Stdout`
To completely disable logs use `Echo#SetLogOutput(io.Discard)`
### Log level
`Echo#SetLogLevel(l log.Level)`
SetLogLevel sets the log level for the logger. Default value is `log.ERROR`.
### Engine
#### Standard HTTP server
```go
e.Run(standard.New(":1323"))
```
##### From TLS
```go
e.Run(standard.NewFromTLS(":1323", "<certfile>", "<keyfile>"))
```
##### From config
```go
e.Run(standard.NewFromConfig(&Config{}))
```
#### FastHTTP server
```go
e.Run(fasthttp.New(":1323"))
```
##### From TLS
```go
e.Run(fasthttp.NewFromTLS(":1323", "<certfile>", "<keyfile>"))
```
##### From config
```go
e.Run(fasthttp.NewFromConfig(&Config{}))
```
#### Configuration
##### `Address`
Address to bind.
##### `TLSCertfile`
TLS certificate file path
##### `TLSKeyfile`
TLS key file path
##### `ReadTimeout`
HTTP read timeout
##### `WriteTimeout`
HTTP write timeout

View File

@ -1,48 +0,0 @@
---
title: Error Handling
menu:
side:
parent: guide
weight: 8
---
Echo advocates centralized HTTP error handling by returning `error` from middleware
and handlers.
It allows you to:
- Debug by writing stack trace to the HTTP response.
- Customize HTTP responses.
- Recover from panics inside middleware or handlers.
For example, when basic auth middleware finds invalid credentials it returns
`401 - Unauthorized` error, aborting the current HTTP request.
```go
package main
import (
"net/http"
"github.com/labstack/echo"
)
func main() {
e := echo.New()
e.Use(func(c echo.Context) error {
// Extract the credentials from HTTP request header and perform a security
// check
// For invalid credentials
return echo.NewHTTPError(http.StatusUnauthorized)
})
e.Get("/welcome", welcome)
e.Run(":1323")
}
func welcome(c echo.Context) error {
return c.String(http.StatusOK, "Welcome!")
}
```
See how [HTTPErrorHandler](/guide/customization#http-error-handler) handles it.

View File

@ -1,26 +0,0 @@
---
title: Installation
menu:
side:
parent: guide
weight: 1
---
Echo is developed and tested using Go `1.5.x` and `1.6.x`
#### Install the latest stable version of Echo via `go get`
```sh
$ go get github.com/labstack/echo
```
#### Update
```sh
$ go get -u github.com/labstack/echo
```
#### [Migrating from v1](/guide/migrating)
Echo follows [semantic versioning](http://semver.org) managed through GitHub releases.
Specific version of Echo can be installed using a [package manager](https://github.com/avelino/awesome-go#package-management).

View File

@ -1,67 +0,0 @@
---
title: Middleware
menu:
side:
parent: guide
weight: 5
---
Middleware is a function which is chained in the HTTP request-response cycle. Middleware
has access to the request and response objects which it utilizes to perform a specific
action, for example, logging every request.
### Logger
Logs each HTTP request with method, path, status, response time and bytes served.
*Example*
```go
e.Use(Logger())
// Output: `2015/06/07 18:16:16 GET / 200 13.238µs 14`
```
### BasicAuth
BasicAuth middleware provides an HTTP basic authentication.
- For valid credentials it calls the next handler in the chain.
- For invalid Authorization header it sends "404 - Bad Request" response.
- For invalid credentials, it sends "401 - Unauthorized" response.
*Example*
```go
g := e.Group("/admin")
e.Use(middleware.BasicAuth(func(username, password string) bool {
if username == "joe" && password == "secret" {
return true
}
return false
}))
```
### Gzip
Gzip middleware compresses HTTP response using gzip compression scheme.
*Example*
```go
e.Use(mw.Gzip())
```
### Recover
Recover middleware recovers from panics anywhere in the chain and handles the
control to the centralized
[HTTPErrorHandler]({{< relref "guide/customization.md#http-error-handler">}}).
*Example*
```go
e.Use(middleware.Recover())
```
### [Recipes](https://github.com/labstack/echox/tree/master/recipe/middleware)

View File

@ -1,32 +0,0 @@
---
title: Migrating
menu:
side:
parent: guide
weight: 2
---
### Migrating from v1
#### Change log
- Good news, 85% of the API remains the same.
- `Engine` interface to abstract `HTTP` server implementation, allowing
us to use HTTP servers beyond Go standard library. It currently supports standard HTTP server and [FastHTTP](https://github.com/valyala/fasthttp).
- Context, Request and Response are converted to interfaces. [More...](https://github.com/labstack/echo/issues/146)
- Handler signature is changed to `func (c echo.Context) error`.
- Dropped auto wrapping of handler and middleware to enforce compile time check.
- Handler only accepts `Echo#Handler` interface.
- Middleware only accepts `Echo#Middleware` interface.
- `Echo#HandlerFunc` adapter to use ordinary functions as handlers.
- `Echo#MiddlewareFunc` adapter to use ordinary functions as middleware.
- Middleware is run before hitting the router, which doesn't require `Echo#Hook` API as
it can be achieved via middleware.
- Ability to define middleware at route level.
- `Echo#HTTPError` exposed it's fields `Code` and `Message`.
#### How?
Quite easy
- Browse through [recipes](/recipes/hello-world) freshly converted to v2.
- Read documentation and dig into test cases.

View File

@ -1,99 +0,0 @@
---
title: Request
menu:
side:
parent: guide
weight: 6
---
### Handler path
`Context#Path()` returns the registered path for the handler, it can be used in the
middleware for logging purpose.
*Example*
```go
e.Use(func(c echo.Context) error {
println(c.Path()) // Prints `/users/:name`
return nil
})
e.Get("/users/:name", func(c echo.Context) error) {
return c.String(http.StatusOK, name)
})
```
### golang.org/x/net/context
`echo.Context` embeds `context.Context` interface, so all it's properties
are available right from `echo.Context`.
*Example*
```go
e.Get("/users/:name", func(c echo.Context) error) {
c.Context = context.WithValue(nil, "key", "val")
// Pass it down...
// Use it...
println(c.Value("key"))
return c.String(http.StatusOK, name)
})
```
### Path parameter
Path parameter can be retrieved either by name `Context#Param(name string) string`
or by index `Context#P(i int) string`. Getting parameter by index gives a slightly
better performance.
*Example*
```go
e.Get("/users/:name", func(c echo.Context) error {
// By name
name := c.Param("name")
// By index
name := c.P(0)
return c.String(http.StatusOK, name)
})
```
```sh
$ curl http://localhost:1323/users/joe
```
### Query parameter
Query parameter can be retrieved by name using `Context#Query(name string)`.
*Example*
```go
e.Get("/users", func(c echo.Context) error {
name := c.Query("name")
return c.String(http.StatusOK, name)
})
```
```sh
$ curl -G -d "name=joe" http://localhost:1323/users
```
### Form parameter
Form parameter can be retrieved by name using `Context#Form(name string)`.
*Example*
```go
e.Post("/users", func(c echo.Context) error {
name := c.Form("name")
return c.String(http.StatusOK, name)
})
```
```sh
$ curl -d "name=joe" http://localhost:1323/users
```

View File

@ -1,122 +0,0 @@
---
title: Response
menu:
side:
parent: guide
weight: 7
---
### Template
`Context#Render(code int, name string, data interface{}) error`
Renders a template with data and sends a text/html response with status code. Templates
can be registered using `Echo.SetRenderer()`, allowing us to use any template engine.
Below is an example using Go `html/template`
- Implement `echo.Render` interface
```go
type Template struct {
templates *template.Template
}
func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
return t.templates.ExecuteTemplate(w, name, data)
}
```
- Pre-compile templates
`public/views/hello.html`
```html
{{define "hello"}}Hello, {{.}}!{{end}}
```
```go
t := &Template{
templates: template.Must(template.ParseGlob("public/views/*.html")),
}
```
- Register templates
```go
e := echo.New()
e.SetRenderer(t)
e.Get("/hello", Hello)
```
- Render template
```go
func Hello(c echo.Context) error {
return c.Render(http.StatusOK, "hello", "World")
}
```
### JSON
`Context.JSON(code int, v interface{}) error`
Sends a JSON HTTP response with status code.
### JSONP
`Context.JSONP(code int, callback string, i interface{}) error`
Sends a JSONP HTTP response with status code. It uses `callback` to construct the
JSONP payload.
### XML
`Context.XML(code int, v interface{}) error`
Sends an XML HTTP response with status code.
### HTML
`c.HTML(code int, html string) error`
Sends an HTML response with status code.
### String
`Context#String(code int, s string) error`
Sends a string response with status code.
### File
`func (c *context) File(file string) error`
Sends a response with the content of the file.
### Attachment
`Context#Attachment(file string) error`
Sends a response as file attachment, prompting client to save the file.
### Static Files
`Echo#Use(middleware.Static(root string))`
Serves static files from the provided `root` directory.
`Echo#Static(prefix, root string)`
Serves files from provided `root` directory for `/<prefix>*` HTTP path.
`Echo#File(path, file string)`
Serves provided `file` for `/<path>` HTTP path.
*Examples*
- Serving static files with no prefix `e.Use(middleware.Static("public"))`
- Serving static files with a prefix `e.Static("/static", "assets")`
- Serving an index page `e.File("/", "public/index.html")`
- Serving a favicon `e.File("/favicon.ico", "images/facicon.ico")`

View File

@ -1,108 +0,0 @@
---
title: Routing
menu:
side:
parent: guide
weight: 4
---
Echo's router is [fast, optimized]({{< relref "index.md#performance">}}) and
flexible. It's based on [radix tree](http://en.wikipedia.org/wiki/Radix_tree) data
structure which makes route lookup really fast. Router leverages [sync pool](https://golang.org/pkg/sync/#Pool)
to reuse memory and achieve zero dynamic memory allocation with no GC overhead.
Routes can be registered by specifying HTTP method, path and a handler. For example,
code below registers a route for method `GET`, path `/hello` and a handler which sends
`Hello!` HTTP response.
```go
e.Get("/hello", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello!")
})
```
You can use `Echo.Any(path string, h Handler)` to register a handler for all HTTP methods.
If you want to register it for some methods use `Echo.Match(methods []string, path string, h Handler)`.
Echo defines handler function as `func(echo.Context) error` where `echo.Context` primarily
holds HTTP request and response interfaces.
### Match-any
Matches zero or more characters in the path. For example, pattern `/users/*` will
match:
- `/users/`
- `/users/1`
- `/users/1/files/1`
- `/users/anything...`
### Path matching order
- Static
- Param
- Match any
#### Example
```go
e.Get("/users/:id", func(c echo.Context) error {
return c.String(http.StatusOK, "/users/:id")
})
e.Get("/users/new", func(c echo.Context) error {
return c.String(http.StatusOK, "/users/new")
})
e.Get("/users/1/files/*", func(c echo.Context) error {
return c.String(http.StatusOK, "/users/1/files/*")
})
```
Above routes would resolve in the following order:
- `/users/new`
- `/users/:id`
- `/users/1/files/*`
> Routes can be written in any order.
### Group
`Echo#Group(prefix string, m ...Middleware) *Group`
Routes with common prefix can be grouped to define a new sub-router with optional
middleware. In addition to specified middleware group also inherits parent middleware.
To add middleware later in the group you can use `Group.Use(m ...Middleware)`.
Groups can also be nested.
In the code below, we create an admin group which requires basic HTTP authentication
for routes `/admin/*`.
```go
e.Group("/admin")
e.Use(middleware.BasicAuth(func(username, password string) bool {
if username == "joe" && password == "secret" {
return true
}
return false
}))
```
### URI building
`Echo.URI` can be used to generate URI for any handler with specified path parameters.
It's helpful to centralize all your URI patterns which ease in refactoring your
application.
`e.URI(h, 1)` will generate `/users/1` for the route registered below
```go
// Handler
h := func(c echo.Context) error {
return c.String(http.StatusOK, "OK")
}
// Route
e.Get("/users/:id", h)
```

View File

@ -1,100 +0,0 @@
---
title: Index
---
# ![Echo](/images/echo.svg) Echo
A fast and unfancy micro web framework for Go.
---
## Features
- Fast HTTP router which smartly prioritize routes.
- Run with standard HTTP server or FastHTTP server.
- Extensible middleware framework.
- Router groups with nesting.
- Handy functions to send variety of HTTP responses.
- Centralized HTTP error handling.
- Template rendering with any template engine.
## Performance
<iframe width="600" height="371" seamless frameborder="0" scrolling="no" src="https://docs.google.com/spreadsheets/d/1phsG_NPmEOaTVTw6lasK3CeEwBlbkhzAWPiyrBznm1g/pubchart?oid=178095723&amp;format=interactive"></iframe>
## Getting Started
### Installation
```sh
$ go get github.com/labstack/echo
```
### Hello, World!
Create `main.go`
```go
package main
import (
"net/http"
"github.com/labstack/echo"
"github.com/labstack/echo/engine/standard"
"github.com/labstack/echo/middleware"
)
// Handler
func hello() echo.HandlerFunc {
return func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!\n")
}
}
func main() {
// Echo instance
e := echo.New()
// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Routes
e.Get("/", hello())
// Start server
e.Run(standard.New(":1323"))
}
```
Start server
```sh
$ go run main.go
```
Browse to [http://localhost:1323](http://localhost:1323) and you should see
Hello, World! on the page.
### Next?
- Browse [recipes](/recipes/hello-world)
- Head over to [guide](/guide/installation)
## Contribute
**Use issues for everything**
- Report issues
- Discuss before sending pull request
- Suggest new features
- Improve/fix documentation
## Credits
- [Vishal Rana](https://github.com/vishr) - Author
- [Nitin Rana](https://github.com/nr17) - Consultant
- [Contributors](https://github.com/labstack/echo/graphs/contributors)
## License
[MIT](https://github.com/labstack/echo/blob/master/LICENSE)

View File

@ -1,19 +0,0 @@
---
title: CORS
menu:
side:
parent: recipes
weight: 3
---
### Server
`main.go`
{{< embed "cors/main.go" >}}
### Maintainers
- [vishr](https://github.com/vishr)
### [Source Code]({{< source "cors" >}})

View File

@ -1,19 +0,0 @@
---
title: CRUD
menu:
side:
parent: recipes
weight: 2
---
### Server
`main.go`
{{< embed "crud/main.go" >}}
### Maintainers
- [vishr](https://github.com/vishr)
### [Source Code]({{< source "crud" >}})

View File

@ -1,20 +0,0 @@
---
title: Embed Resources
menu:
side:
identifier: "embed-resources"
parent: recipes
weight: 14
---
### With go.rice
`main.go`
{{< embed "embed-resources/main.go" >}}
### Maintainers
- [caarlos0](https://github.com/caarlos0)
### [Source Code]({{< source "embed-resources" >}})

View File

@ -1,53 +0,0 @@
---
title: File Upload
menu:
side:
parent: recipes
weight: 7
---
- Multipart/form-data file upload
- Multiple form fields and files
Use `req.ParseMultipartForm(16 << 20)` for manually parsing multipart form. It gives
us an option to specify the maximum memory used while parsing the request body.
If you just want to upload a single file:
```go
file, fh, err := req.FormFile("file")
if err != nil {
return err
}
defer file.Close()
// Destination
dst, err := os.Create(fh.Filename)
if err != nil {
return err
}
defer dst.Close()
// Copy
if _, err = io.Copy(dst, file); err != nil {
return err
}
```
### Server
`main.go`
{{< embed "file-upload/main.go" >}}
### Client
`index.html`
{{< embed "file-upload/public/index.html" >}}
### Maintainers
- [vishr](https://github.com/vishr)
### [Source Code]({{< source "file-upload" >}})

View File

@ -1,135 +0,0 @@
---
title: Google App Engine
menu:
side:
parent: recipes
weight: 12
---
Google App Engine (GAE) provides a range of hosting options from pure PaaS (App Engine Classic)
through Managed VMs to fully self-managed or container-driven Compute Engine instances. Echo
works great with all of these but requires a few changes to the usual examples to run on the
AppEngine Classic and Managed VM options. With a small amount of effort though it's possible
to produce a codebase that will run on these and also non-managed platforms automatically.
We'll walk through the changes needed to support each option.
### Standalone
Wait? What? I thought this was about AppEngine! Bear with me - the easiest way to show the changes
required is to start with a setup for standalone and work from there plus there's no reason we
wouldn't want to retain the ability to run our app anywhere, right?
We take advantage of the go [build constraints or tags](http://golang.org/pkg/go/build/) to change
how we create and run the Echo server for each platform while keeping the rest of the application
(e.g. handler wireup) the same across all of them.
First, we have the normal setup based on the examples but we split it into two files - `app.go` will
be common to all variations and holds the Echo instance variable. We initialise it from a function
and because it is a `var` this will happen _before_ any `init()` functions run - a feature that we'll
use to connect our handlers later.
`app.go`
{{< embed "google-app-engine/app.go" >}}
A separate source file contains the function to create the Echo instance and add the static
file handlers and middleware. Note the build tag on the first line which says to use this when _not_
bulding with appengine or appenginevm tags (which thoese platforms automatically add for us). We also
have the `main()` function to start serving our app as normal. This should all be very familiar.
`app-standalone.go`
{{< embed "google-app-engine/app-standalone.go" >}}
The handler-wireup that would normally also be a part of this Echo setup moves to separate files which
take advantage of the ability to have multiple `init()` functions which run _after_ the `e` Echo var is
initialised but _before_ the `main()` function is executed. These allow additional handlers to attach
themselves to the instance - I've found the `Group` feature naturally fits into this pattern with a file
per REST endpoint, often with a higher-level `api` group created that they attach to instead of the root
Echo instance directly (so things like CORS middleware can be added at this higher common-level).
`users.go`
{{< embed "google-app-engine/users.go" >}}
If we run our app it should execute as it did before when everything was in one file although we have
at least gained the ability to organize our handlers a little more cleanly.
### AppEngine Classic and Managed VMs
So far we've seen how to split apart the Echo creation and setup but still have the same app that
still only runs standalone. Now we'll see hwo those changes allow us to add support for AppEngine
hosting.
Refer to the [AppEngine site](https://cloud.google.com/appengine/docs/go/) for full configuration
and deployment information.
#### app.yaml configuration file
Both of these are Platform as as Service options running on either sandboxed micro-containers
or managed Compute Engine instances. Both require an `app.yaml` file to describe the app to
the service. While the app _could_ still serve all it's static files itself, one of the benefits
of the platform is having Google's infrastructure handle that for us so it can be offloaded and
the app only has to deal with dynamic requests. The platform also handles logging and http gzip
compression so these can be removed from the codebase as well.
The yaml file also contains other options to control instance size and auto-scaling so for true
deployment freedom you would likely have separate `app-classic.yaml` and `app-vm.yaml` files and
this can help when making the transition from AppEngine Classic to Managed VMs.
`app-engine.yaml`
{{< embed "google-app-engine/app-engine.yaml" >}}
#### Router configuration
We'll now use the [build constraints](http://golang.org/pkg/go/build/) again like we did when creating
our `app-standalone.go` instance but this time with the opposite tags to use this file _if_ the build has
the appengine or appenginevm tags (added automatically when deploying to these platforms).
This allows us to replace the `createMux()` function to create our Echo server _without_ any of the
static file handling and logging + gzip middleware which is no longer required. Also worth nothing is
that GAE classic provides a wrapper to handle serving the app so instead of a `main()` function where
we run the server, we instead wire up the router to the default `http.Handler` instead.
`app-engine.go`
{{< embed "google-app-engine/app-engine.go" >}}
Managed VMs are slightly different. They are expected to respond to requests on port 8080 as well
as special health-check requests used by the service to detect if an instance is still running in
order to provide automated failover and instance replacement. The `google.golang.org/appengine`
package provides this for us so we have a slightly different version for Managed VMs:
`app-managed.go`
{{< embed "google-app-engine/app-managed.go" >}}
So now we have three different configurations. We can build and run our app as normal so it can
be executed locally, on a full Compute Engine instance or any other traditional hosting provider
(including EC2, Docker etc...). This build will ignore the code in appengine and appenginevm tagged
files and the `app.yaml` file is meaningless to anything other than the AppEngine platform.
We can also run locally using the [Google AppEngine SDK for Go](https://cloud.google.com/appengine/downloads)
either emulating [AppEngine Classic](https://cloud.google.com/appengine/docs/go/tools/devserver):
goapp serve
Or [Managed VMs](https://cloud.google.com/appengine/docs/managed-vms/sdk#run-local):
gcloud config set project [your project id]
gcloud preview app run .
And of course we can deploy our app to both of these platforms for easy and inexpensive auto-scaling joy.
Depending on what your app actually does it's possible you may need to make other changes to allow
switching between AppEngine provided service such as Datastore and alternative storage implementations
such as MongoDB. A combination of go interfaces and build constraints can make this fairly straightforward
but is outside the scope of this recipe.
### Maintainers
- [CaptainCodeman](https://github.com/CaptainCodeman)
### [Source Code]({{< source "google-app-engine" >}})

View File

@ -1,28 +0,0 @@
---
title: Graceful Shutdown
menu:
side:
parent: recipes
weight: 13
---
### With [grace](https://github.com/facebookgo/grace)
`main.go`
{{< embed "graceful-shutdown/grace/main.go" >}}
### With [graceful](https://github.com/tylerb/graceful)
`main.go`
{{< embed "graceful-shutdown/graceful/main.go" >}}
### Maintainers
- [mertenvg](https://github.com/mertenvg)
### Source Code
- [graceful]({{< source "graceful-shutdown/graceful" >}})
- [grace]({{< source "graceful-shutdown/grace" >}})

View File

@ -1,19 +0,0 @@
---
title: Hello World
menu:
side:
parent: recipes
weight: 1
---
### Server
`main.go`
{{< embed "hello-world/main.go" >}}
### Maintainers
- [vishr](https://github.com/vishr)
### [Source Code]({{< source "hello-world" >}})

View File

@ -1,27 +0,0 @@
---
title: JSONP
menu:
side:
parent: recipes
weight: 6
---
JSONP is a method that allows cross-domain server calls. You can read more about it at the JSON versus JSONP Tutorial.
### Server
`main.go`
{{< embed "jsonp/main.go" >}}
### Client
`index.html`
{{< embed "jsonp/public/index.html" >}}
### Maintainers
- [willf](https://github.com/willf)
### [Source Code]({{< source "jsonp" >}})

View File

@ -1,58 +0,0 @@
---
title: JWT Authentication
menu:
side:
parent: recipes
weight: 11
---
Most applications dealing with client authentication will require a more secure
mechanism than that provided by [basic authentication](https://github.com/labstack/echo/blob/master/middleware/auth.go). [JSON Web Tokens](http://jwt.io/)
are one such mechanism - JWTs are a compact means of transferring cryptographically
signed claims between the client and server.
This recipe demonstrates the use of a simple JWT authentication Echo middleware
using Dave Grijalva's [jwt-go](https://github.com/dgrijalva/jwt-go). This middleware
expects the token to be present in an Authorization HTTP header using the method
"Bearer", although JWTs are also frequently sent using cookies, the request URL,
or even the request body. We will use the HS236 signing method, note that several
other algorithms are available.
`main.go`
{{< embed "jwt-authentication/main.go" >}}
Run `main.go` and making a request to the root path `/` returns a 200 OK response,
as this route does not use our JWT authentication middleware. Sending requests to
`/restricted` (our authenticated route) with either no Authorization header or invalid
Authorization headers / tokens will return 401 Unauthorized.
```sh
# Unauthenticated route
$ curl localhost:1323/ => No auth required for this route.
# No Authentication header
$ curl localhost:1323/restricted => Unauthorized
# Invalid Authentication method
$ curl localhost:1323/restricted -H "Authorization: Invalid " => Unauthorized
# Invalid token
$ curl localhost:1323/restricted -H "Authorization: Bearer InvalidToken" => Unauthorized
```
Running `token.go` (source) will print JWT that is valid against this middleware
to stdout. You can use this token to test succesful authentication on the `/restricted` path.
{{< embed "jwt-authentication/token/token.go" >}}
```sh
# Valid token
$ curl localhost:1323/restricted -H "Authorization: Bearer <token>" => Access granted with JWT.
```
### Maintainers
- [axdg](https://github.com/axdg)
### [Source Code]({{< source "jwt-authentication" >}})

View File

@ -1,20 +0,0 @@
---
title: Middleware
menu:
side:
identifier: "recipe-miiddleware"
parent: recipes
weight: 3
---
### Server
`main.go`
{{< embed "middleware/main.go" >}}
### Maintainers
- [vishr](https://github.com/vishr)
### [Source Code]({{< source "middleware" >}})

View File

@ -1,28 +0,0 @@
---
title: Streaming File Upload
menu:
side:
parent: recipes
weight: 8
---
- Streaming multipart/form-data file upload
- Multiple form fields and files
### Server
`main.go`
{{< embed "streaming-file-upload/main.go" >}}
### Client
`index.html`
{{< embed "streaming-file-upload/public/index.html" >}}
### Maintainers
- [vishr](https://github.com/vishr)
### [Source Code]({{< source "streaming-file-upload" >}})

View File

@ -1,38 +0,0 @@
---
title: Streaming Response
menu:
side:
parent: recipes
weight: 9
---
- Send data as it is produced
- Streaming JSON response with chunked transfer encoding
### Server
`main.go`
{{< embed "streaming-response/main.go" >}}
### Client
```sh
$ curl localhost:1323
```
## Output
```sh
{"Altitude":-97,"Latitude":37.819929,"Longitude":-122.478255}
{"Altitude":1899,"Latitude":39.096849,"Longitude":-120.032351}
{"Altitude":2619,"Latitude":37.865101,"Longitude":-119.538329}
{"Altitude":42,"Latitude":33.812092,"Longitude":-117.918974}
{"Altitude":15,"Latitude":37.77493,"Longitude":-122.419416}
```
### Maintainers
- [vishr](https://github.com/vishr)
### [Source Code]({{< source "streaming-response" >}})

View File

@ -1,18 +0,0 @@
---
title: Subdomains
menu:
side:
parent: recipes
weight: 10
---
`main.go`
{{< embed "subdomains/main.go" >}}
### Maintainers
- [axdg](https://github.com/axdg)
- [vishr](https://github.com/vishr)
### [Source Code]({{< source "subdomains" >}})

View File

@ -1,26 +0,0 @@
---
title: Website
draft: true
menu:
side:
parent: recipes
weight: 4
---
### Server
`server.go`
{{< embed "website/main.go" >}}
### Client
`index.html`
{{< embed "website/public/index.html" >}}
### Maintainers
- [vishr](https://github.com/vishr)
### [Source Code]({{< source "website" >}})

View File

@ -1,47 +0,0 @@
---
title: WebSocket
menu:
side:
parent: recipes
weight: 5
---
### Server
`server.go`
{{< embed "websocket/main.go" >}}
### Client
`index.html`
{{< embed "websocket/public/index.html" >}}
### Output
`Client`
```sh
Hello, Client!
Hello, Client!
Hello, Client!
Hello, Client!
Hello, Client!
```
`Server`
```sh
Hello, Server!
Hello, Server!
Hello, Server!
Hello, Server!
Hello, Server!
```
### Maintainers
- [vishr](https://github.com/vishr)
### [Source Code]({{< source "websocket" >}})

View File

@ -1,45 +0,0 @@
{{ partial "head.html" . }}
<body>
{{ . }}
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
{{ partial "header.html" . }}
<main class="mdl-layout__content">
<div class="page-content single">
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--3-col">
{{ partial "menu.html" . }}
</div>
<div class="mdl-cell mdl-cell--9-col">
<article>
<header>
<h2>{{ .Title }}</h2>
</header>
<section class="content">
{{ .Content }}
</section>
<footer style="margin-top: 80px;">
<div id="disqus_thread"></div>
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES * * */
var disqus_shortname = 'labstack';
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script');
dsq.type = 'text/javascript';
dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
</footer>
</article>
</div>
</div>
</div>
{{ partial "footer.html" . }}
</main>
</div>
</body>
</html>

View File

@ -1,24 +0,0 @@
{{ partial "head.html" . }}
<body>
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
{{ partial "header.html" . }}
<main class="mdl-layout__content">
<div class="page-content">
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--3-col">
{{ partial "menu.html" . }}
</div>
<div class="mdl-cell mdl-cell--9-col">
{{ range where .Data.Pages "Title" "Index" }}
{{ .Content }}
{{ end }}
</div>
</div>
</div>
{{ partial "footer.html" . }}
</main>
</div>
</body>
</html>

View File

@ -1,49 +0,0 @@
<footer class="mdl-mini-footer">
<div class="mdl-mini-footer__left-section">
<span class="mdl-typography__font-light">© 2015 LabStack</span>
</div>
<div class="mdl-mini-footer__right-section">
<ul class="mdl-mini-footer__link-list">
<li class="github">
<a href="https://github.com/labstack" target="_blank">
<i class="fa fa-github fa-2x"></i>
</a>
</li>
<li class="facebook">
<a href="https://facebook.com/labstack" target="_blank">
<i class="fa fa-facebook fa-2x"></i>
</a>
</li>
<li class="twitter">
<a href="https://twitter.com/labstack" target="_blank">
<i class="fa fa-twitter-square fa-2x"></i>
</a>
</li>
<li class="google">
<a href="https://plus.google.com/+labstack" target="_blank">
<i class="fa fa-google-plus-square fa-2x"></i>
</a>
</li>
</ul>
</div>
</footer>
<!-- <script src="/scripts/highlight.pack.min.js"></script> -->
<script src="/scripts/prism.js"></script>
<script src="/scripts/echo.js"></script>
<!-- <script>hljs.initHighlightingOnLoad();</script> -->
<script>
(function(i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function() {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o),
m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', '{{ .Site.Params.googleAnayticsId }}', 'auto');
ga('send', 'pageview');
</script>

View File

@ -1,23 +0,0 @@
<!doctype html>
<html lang="{{ .Site.LanguageCode }}">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>
{{ .Site.Title }} - {{ .Site.Params.description }}{{ if ne .URL "/" }} - {{ .Title }} {{ end }}
</title>
<meta name="description" content="{{ .Site.Params.description }}">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- <link rel="apple-touch-icon" href="apple-touch-icon.png"> -->
<!-- Place favicon.ico in the root directory -->
<link rel="stylesheet" href="//storage.googleapis.com/code.getmdl.io/1.0.5/material.blue-pink.min.css">
<link rel="stylesheet" href="//fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:300,400,500,700">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<!-- <link rel="stylesheet" href="/styles/monokai.css"> -->
<link rel="stylesheet" href="/styles/prism.css">
<link rel="stylesheet" href="/styles/echo.css">
<script src="//storage.googleapis.com/code.getmdl.io/1.0.5/material.min.js"></script>
</head>

View File

@ -1,17 +0,0 @@
<header class="mdl-layout__header">
<div class="mdl-layout__header-row">
<a href="{{ .Site.BaseURL }}" class="mdl-navigation__link mdl-layout-title">
<img src="/images/logo.svg" alt="LabStack">
</a>
<div class="mdl-layout-spacer"></div>
<nav class="mdl-navigation mdl-layout--large-screen-only">
<a href="https://github.com/labstack/echo" class="mdl-navigation__link">
<i class="fa fa-github fa-2x"></i>
</a>
</nav>
</div>
</header>
<div style="padding: 4px; text-align: center; background: #ff851b; color: #fff;">
This is Echo v2 website. If you are looking for v1 docs, they can be found <a style=
"color: #fff;" href="https://github.com/labstack/echo/tree/v1/website/content"><b>here</b>.</a>
</div>

View File

@ -1,17 +0,0 @@
<aside class="menu">
<div>
{{ range .Site.Menus.side }}
{{ if .HasChildren }}
<h4>
{{ .Pre }}
{{ .Name }}
</h4>
{{ range .Children }}
<a href="{{ .URL }}">
{{ .Name }}
</a>
{{ end }}
{{ end }}
{{ end }}
</div>
</aside>

View File

@ -1,14 +0,0 @@
<span class="share">
<a href="https://www.facebook.com/sharer/sharer.php?u={{ .Permalink }}" target="_blank">
<i class="fa fa-facebook-square fa-2x"></i>
</a>
<a href="http://twitter.com/share?text={{ .Title }}&amp;url={{ .Permalink }}" target="_blank">
<i class="fa fa-twitter-square fa-2x"></i>
</a>
<a href="https://plus.google.com/share?url={{ .Permalink }}" target="_blank">
<i class="fa fa-google-plus-square fa-2x"></i>
</a>
<a class="ui reddit icon button" href="http://www.reddit.com/submit?url={{ .Permalink }}&amp;title={{ .Title }}" target="_blank">
<i class="fa fa-reddit-square fa-2x"></i>
</a>
</span>

View File

@ -1,2 +0,0 @@
<pre data-src="https://raw.githubusercontent.com/labstack/echox/master/recipe/{{ .Get 0 }}">
</pre>

View File

@ -1 +0,0 @@
https://github.com/labstack/echox/tree/master/recipe/{{ .Get 0 }}

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="46px" height="46px" viewBox="0 0 46 46" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g sketch:type="MSArtboardGroup" transform="translate(-639.000000, -1341.000000)">
<g sketch:type="MSLayerGroup" transform="translate(133.000000, 1155.000000)">
<g id="Aim" transform="translate(507.000000, 187.000000)" sketch:type="MSShapeGroup">
<g id="Main">
<circle id="Oval-88" stroke="#2196f3" stroke-width="2" cx="22" cy="22" r="22"></circle>
<circle id="Oval-89" stroke="#2196f3" stroke-width="2" cx="22" cy="22" r="15.3043478"></circle>
<circle id="Oval-90" stroke="#2196f3" stroke-width="2" cx="22" cy="22" r="8.60869565"></circle>
<circle id="Oval-91" fill="#2196f3" cx="22" cy="22" r="1.91304348"></circle>
</g>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1 +0,0 @@
<svg width="127" height="19" viewBox="0 0 127 19" xmlns="http://www.w3.org/2000/svg"><title>LabStack</title><path d="M16.242 19H2.344c-.22 0-.422-.04-.61-.117a1.49 1.49 0 0 1-.486-.322 1.49 1.49 0 0 1-.322-.486 1.568 1.568 0 0 1-.117-.61V2.195h3.045v13.76h12.387V19zm14.977-4.195c0 .422-.075.877-.224 1.365a4.08 4.08 0 0 1-.72 1.36 4.018 4.018 0 0 1-1.3 1.048c-.537.28-1.187.422-1.953.422h-5.496a4.71 4.71 0 0 1-1.365-.223 4.08 4.08 0 0 1-1.36-.72 4.018 4.018 0 0 1-1.048-1.3c-.28-.536-.422-1.187-.422-1.952 0-.422.074-.88.223-1.37a4.07 4.07 0 0 1 .72-1.367 4.018 4.018 0 0 1 1.3-1.048c.536-.282 1.187-.422 1.952-.422h5.496v2.906h-5.496c-.414 0-.734.127-.96.38-.227.255-.34.57-.34.944 0 .4.13.71.392.932.26.222.57.334.93.334h5.473c.415 0 .735-.125.96-.375.228-.25.34-.564.34-.94v-4.253c0-.398-.122-.714-.368-.95-.246-.233-.557-.35-.932-.35h-6.69V6.332h6.69c.422 0 .877.074 1.366.223.487.148.94.388 1.358.72.418.332.768.766 1.05 1.3.28.536.42 1.187.42 1.952v4.278zm16.57-.082a4.696 4.696 0 0 1-.41 1.87c-.142.315-.323.618-.546.907-.223.29-.492.545-.81.768-.315.222-.68.4-1.094.533-.414.134-.883.2-1.407.2h-5.496a4.696 4.696 0 0 1-1.87-.41 4.445 4.445 0 0 1-.907-.545 3.697 3.697 0 0 1-.768-.81 4.01 4.01 0 0 1-.533-1.1c-.134-.418-.2-.89-.2-1.412V.977h3.047v13.746c0 .375.117.673.35.896.236.222.53.333.88.333h5.496c.383 0 .682-.113.897-.34.215-.226.322-.523.322-.89v-4.125c0-.383-.113-.682-.34-.897-.226-.214-.52-.32-.88-.32h-5.495V6.33h5.496a4.696 4.696 0 0 1 1.87.41c.316.14.62.322.908.545.29.223.544.492.763.81.218.315.394.68.527 1.094.133.415.2.884.2 1.408v4.125zm19.09-.668a5.36 5.36 0 0 1-.23 1.623c-.152.48-.353.904-.603 1.27a4.03 4.03 0 0 1-.88.94 5.39 5.39 0 0 1-1.042.632c-.36.164-.725.285-1.096.363-.372.078-.72.117-1.05.117H50.227v-3.047H61.98c.586 0 1.04-.172 1.366-.515.324-.344.486-.805.486-1.383 0-.282-.043-.54-.13-.774a1.783 1.783 0 0 0-.368-.608 1.626 1.626 0 0 0-.586-.4 2.02 2.02 0 0 0-.768-.14h-7.007a5.43 5.43 0 0 1-1.594-.263 4.78 4.78 0 0 1-1.59-.85c-.487-.39-.894-.903-1.218-1.536-.324-.632-.486-1.406-.486-2.32 0-.914.162-1.685.486-2.314.324-.63.73-1.14 1.22-1.536a4.727 4.727 0 0 1 1.587-.855 5.43 5.43 0 0 1 1.593-.265h10.37v3.047h-10.37c-.578 0-1.03.176-1.354.528-.325.35-.487.816-.487 1.394 0 .586.162 1.05.486 1.39.323.34.775.508 1.353.508h7.031a5.38 5.38 0 0 1 2.14.516c.362.172.708.39 1.036.65.328.262.62.577.873.944.254.367.455.79.603 1.265.15.477.223 1.016.223 1.618zM80.05 9.38h-5.32V19h-3.082V9.38h-3.96V6.33h3.96V2.195h3.082v4.137h5.32V9.38zm14.356 5.425c0 .422-.074.877-.222 1.365a4.08 4.08 0 0 1-.72 1.36 4.018 4.018 0 0 1-1.302 1.048c-.535.28-1.185.422-1.95.422h-5.497a4.71 4.71 0 0 1-1.365-.223 4.08 4.08 0 0 1-1.36-.72 4.018 4.018 0 0 1-1.05-1.3c-.28-.536-.42-1.187-.42-1.952 0-.422.074-.88.222-1.37a4.07 4.07 0 0 1 .72-1.367 4.018 4.018 0 0 1 1.302-1.048c.535-.282 1.185-.422 1.95-.422h5.497v2.906h-5.495c-.414 0-.735.127-.96.38-.228.255-.34.57-.34.944 0 .4.13.71.392.932.26.222.572.334.93.334h5.474c.415 0 .735-.125.962-.375.226-.25.34-.564.34-.94v-4.253c0-.398-.123-.714-.37-.95-.246-.233-.556-.35-.93-.35H83.52V6.332h6.69c.423 0 .878.074 1.366.223.488.148.942.388 1.36.72.418.332.767.766 1.048 1.3.282.536.422 1.187.422 1.952v4.278zM109.276 19h-8.26c-.422 0-.883-.074-1.383-.223a4.067 4.067 0 0 1-1.39-.732c-.425-.34-.78-.78-1.065-1.324-.285-.542-.428-1.208-.428-1.997v-4.125a4.696 4.696 0 0 1 .41-1.87c.14-.316.322-.62.545-.908.223-.29.492-.543.81-.76.315-.22.68-.396 1.094-.53.413-.132.882-.198 1.406-.198h8.26V9.38h-8.26c-.4 0-.702.1-.91.304-.206.203-.31.515-.31.937v4.103c0 .398.106.703.317.914.21.21.52.316.926.316h8.237V19zm17.404 0h-4.395l-6.14-5.93a1.415 1.415 0 0 1-.48-1.172 1.59 1.59 0 0 1 .17-.615c.097-.19.23-.353.403-.486l5.567-4.488h4.875l-7.172 5.776L126.68 19zm-11.79 0h-3.046V.977h3.047V19z" fill="#FFF" fill-rule="evenodd"/></svg>

Before

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -1,10 +0,0 @@
(function() {
var menu = document.querySelectorAll('.menu a');
for (var i = 0; i < menu.length; i++) {
var m = menu[i];
if (location.href === m.href) {
m.className += 'active';
}
}
})();

View File

@ -1,8 +0,0 @@
/* http://prismjs.com/download.html?themes=prism-coy&languages=markup+css+clike+javascript+go&plugins=file-highlight */
var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=_self.Prism={util:{encode:function(e){return e instanceof n?new n(e.type,t.util.encode(e.content),e.alias):"Array"===t.util.type(e)?e.map(t.util.encode):e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},clone:function(e){var n=t.util.type(e);switch(n){case"Object":var a={};for(var r in e)e.hasOwnProperty(r)&&(a[r]=t.util.clone(e[r]));return a;case"Array":return e.map&&e.map(function(e){return t.util.clone(e)})}return e}},languages:{extend:function(e,n){var a=t.util.clone(t.languages[e]);for(var r in n)a[r]=n[r];return a},insertBefore:function(e,n,a,r){r=r||t.languages;var l=r[e];if(2==arguments.length){a=arguments[1];for(var i in a)a.hasOwnProperty(i)&&(l[i]=a[i]);return l}var o={};for(var s in l)if(l.hasOwnProperty(s)){if(s==n)for(var i in a)a.hasOwnProperty(i)&&(o[i]=a[i]);o[s]=l[s]}return t.languages.DFS(t.languages,function(t,n){n===r[e]&&t!=e&&(this[t]=o)}),r[e]=o},DFS:function(e,n,a){for(var r in e)e.hasOwnProperty(r)&&(n.call(e,r,e[r],a||r),"Object"===t.util.type(e[r])?t.languages.DFS(e[r],n):"Array"===t.util.type(e[r])&&t.languages.DFS(e[r],n,r))}},plugins:{},highlightAll:function(e,n){for(var a,r=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'),l=0;a=r[l++];)t.highlightElement(a,e===!0,n)},highlightElement:function(n,a,r){for(var l,i,o=n;o&&!e.test(o.className);)o=o.parentNode;o&&(l=(o.className.match(e)||[,""])[1],i=t.languages[l]),n.className=n.className.replace(e,"").replace(/\s+/g," ")+" language-"+l,o=n.parentNode,/pre/i.test(o.nodeName)&&(o.className=o.className.replace(e,"").replace(/\s+/g," ")+" language-"+l);var s=n.textContent,u={element:n,language:l,grammar:i,code:s};if(!s||!i)return t.hooks.run("complete",u),void 0;if(t.hooks.run("before-highlight",u),a&&_self.Worker){var g=new Worker(t.filename);g.onmessage=function(e){u.highlightedCode=e.data,t.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,r&&r.call(u.element),t.hooks.run("after-highlight",u),t.hooks.run("complete",u)},g.postMessage(JSON.stringify({language:u.language,code:u.code,immediateClose:!0}))}else u.highlightedCode=t.highlight(u.code,u.grammar,u.language),t.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,r&&r.call(n),t.hooks.run("after-highlight",u),t.hooks.run("complete",u)},highlight:function(e,a,r){var l=t.tokenize(e,a);return n.stringify(t.util.encode(l),r)},tokenize:function(e,n){var a=t.Token,r=[e],l=n.rest;if(l){for(var i in l)n[i]=l[i];delete n.rest}e:for(var i in n)if(n.hasOwnProperty(i)&&n[i]){var o=n[i];o="Array"===t.util.type(o)?o:[o];for(var s=0;s<o.length;++s){var u=o[s],g=u.inside,c=!!u.lookbehind,f=0,h=u.alias;u=u.pattern||u;for(var p=0;p<r.length;p++){var d=r[p];if(r.length>e.length)break e;if(!(d instanceof a)){u.lastIndex=0;var m=u.exec(d);if(m){c&&(f=m[1].length);var y=m.index-1+f,m=m[0].slice(f),v=m.length,k=y+v,b=d.slice(0,y+1),w=d.slice(k+1),P=[p,1];b&&P.push(b);var A=new a(i,g?t.tokenize(m,g):m,h);P.push(A),w&&P.push(w),Array.prototype.splice.apply(r,P)}}}}}return r},hooks:{all:{},add:function(e,n){var a=t.hooks.all;a[e]=a[e]||[],a[e].push(n)},run:function(e,n){var a=t.hooks.all[e];if(a&&a.length)for(var r,l=0;r=a[l++];)r(n)}}},n=t.Token=function(e,t,n){this.type=e,this.content=t,this.alias=n};if(n.stringify=function(e,a,r){if("string"==typeof e)return e;if("Array"===t.util.type(e))return e.map(function(t){return n.stringify(t,a,e)}).join("");var l={type:e.type,content:n.stringify(e.content,a,r),tag:"span",classes:["token",e.type],attributes:{},language:a,parent:r};if("comment"==l.type&&(l.attributes.spellcheck="true"),e.alias){var i="Array"===t.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}t.hooks.run("wrap",l);var o="";for(var s in l.attributes)o+=(o?" ":"")+s+'="'+(l.attributes[s]||"")+'"';return"<"+l.tag+' class="'+l.classes.join(" ")+'" '+o+">"+l.content+"</"+l.tag+">"},!_self.document)return _self.addEventListener?(_self.addEventListener("message",function(e){var n=JSON.parse(e.data),a=n.language,r=n.code,l=n.immediateClose;_self.postMessage(t.highlight(r,t.languages[a],a)),l&&_self.close()},!1),_self.Prism):_self.Prism;var a=document.getElementsByTagName("script");return a=a[a.length-1],a&&(t.filename=a.src,document.addEventListener&&!a.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
Prism.languages.markup={comment:/<!--[\w\W]*?-->/,prolog:/<\?[\w\W]+?\?>/,doctype:/<!DOCTYPE[\w\W]+?>/,cdata:/<!\[CDATA\[[\w\W]*?]]>/i,tag:{pattern:/<\/?[^\s>\/=.]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&amp;/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup;
Prism.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.util.clone(Prism.languages.css),Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/(<style[\w\W]*?>)[\w\W]*?(?=<\/style>)/i,lookbehind:!0,inside:Prism.languages.css,alias:"language-css"}}),Prism.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:Prism.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:Prism.languages.css}},alias:"language-css"}},Prism.languages.markup.tag));
Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/};
Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}}),Prism.languages.insertBefore("javascript","class-name",{"template-string":{pattern:/`(?:\\`|\\?[^`])*`/,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/(<script[\w\W]*?>)[\w\W]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript"}}),Prism.languages.js=Prism.languages.javascript;
Prism.languages.go=Prism.languages.extend("clike",{keyword:/\b(break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,builtin:/\b(bool|byte|complex(64|128)|error|float(32|64)|rune|string|u?int(8|16|32|64|)|uintptr|append|cap|close|complex|copy|delete|imag|len|make|new|panic|print(ln)?|real|recover)\b/,"boolean":/\b(_|iota|nil|true|false)\b/,operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,number:/\b(-?(0x[a-f\d]+|(\d+\.?\d*|\.\d+)(e[-+]?\d+)?)i?)\b/i,string:/("|'|`)(\\?.|\r|\n)*?\1/}),delete Prism.languages.go["class-name"];
!function(){"undefined"!=typeof self&&self.Prism&&self.document&&document.querySelector&&(self.Prism.fileHighlight=function(){var e={js:"javascript",html:"markup",svg:"markup",xml:"markup",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell"};Array.prototype.forEach&&Array.prototype.slice.call(document.querySelectorAll("pre[data-src]")).forEach(function(t){for(var r,a=t.getAttribute("data-src"),s=t,n=/\blang(?:uage)?-(?!\*)(\w+)\b/i;s&&!n.test(s.className);)s=s.parentNode;if(s&&(r=(t.className.match(n)||[,""])[1]),!r){var o=(a.match(/\.(\w+)$/)||[,""])[1];r=e[o]||o}var l=document.createElement("code");l.className="language-"+r,t.textContent="",l.textContent="Loading…",t.appendChild(l);var i=new XMLHttpRequest;i.open("GET",a,!0),i.onreadystatechange=function(){4==i.readyState&&(i.status<400&&i.responseText?(l.textContent=i.responseText,Prism.highlightElement(l)):l.textContent=i.status>=400?"✖ Error "+i.status+" while fetching file: "+i.statusText:"✖ Error: File does not exist or is empty")},i.send(null)})},self.Prism.fileHighlight())}();

View File

@ -1,55 +0,0 @@
body, p, ol, ul {
font-size: 16px;
}
footer {
background-color: inherit !important;
border-top: 2px solid #e0e0e0;
}
.facebook a:hover {
color: #3B5998;
}
.twitter a:hover {
color: #55ACEE;
}
.google a:hover {
color: #DC4E41;
}
.github a:hover {
color: #333;
}
:not(pre) > code {
padding: 0 4px;
background: #eee;
color: #424242;
font-size: .95em;
font-family: Source Code Pro, Monaco, Menlo, Consolas, monospace;
border: 1px solid #e0e0e0;
border-radius: 2px;
}
a:link {
text-decoration: none;
}
.page-content {
padding: 20px 0;
max-width: 960px;
margin: auto;
}
.page-content header {
padding-bottom: 16px;
}
.menu {
margin-right: 40px;
}
.menu a {
display: block;
color: #757575;
padding: 5px;
border-left:4px #F06292 solid;
}
.menu a:hover:not(.active) {
background-color: #E0E0E0;
}
.menu .active {
color: #FFF;
background-color: #F06292;
}

View File

@ -1,236 +0,0 @@
/* http://prismjs.com/download.html?themes=prism-coy&languages=markup+css+clike+javascript+go&plugins=file-highlight */
/**
* prism.js Coy theme for JavaScript, CoffeeScript, CSS and HTML
* Based on https://github.com/tshedor/workshop-wp-theme (Example: http://workshop.kansan.com/category/sessions/basics or http://workshop.timshedor.com/category/sessions/basics);
* @author Tim Shedor
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
/* Code blocks */
pre[class*="language-"] {
position: relative;
margin: .5em 0;
-webkit-box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf;
-moz-box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf;
box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf;
border-left: 10px solid #358ccb;
background-color: #fdfdfd;
background-image: -webkit-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-image: -moz-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-image: -ms-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-image: -o-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-image: linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-size: 3em 3em;
background-origin: content-box;
overflow: visible;
max-height: 30em;
padding: 0;
}
code[class*="language"] {
max-height: inherit;
height: 100%;
padding: 0 1em;
display: block;
overflow: auto;
}
/* Margin bottom to accomodate shadow */
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background-color: #fdfdfd;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
margin-bottom: 1em;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
position: relative;
padding: .2em;
-webkit-border-radius: 0.3em;
-moz-border-radius: 0.3em;
-ms-border-radius: 0.3em;
-o-border-radius: 0.3em;
border-radius: 0.3em;
color: #c92c2c;
border: 1px solid rgba(0, 0, 0, 0.1);
display: inline;
}
pre[class*="language-"]:before,
pre[class*="language-"]:after {
content: '';
z-index: -2;
display: block;
position: absolute;
bottom: 0.75em;
left: 0.18em;
width: 40%;
height: 20%;
-webkit-box-shadow: 0px 13px 8px #979797;
-moz-box-shadow: 0px 13px 8px #979797;
box-shadow: 0px 13px 8px #979797;
-webkit-transform: rotate(-2deg);
-moz-transform: rotate(-2deg);
-ms-transform: rotate(-2deg);
-o-transform: rotate(-2deg);
transform: rotate(-2deg);
}
:not(pre) > code[class*="language-"]:after,
pre[class*="language-"]:after {
right: 0.75em;
left: auto;
-webkit-transform: rotate(2deg);
-moz-transform: rotate(2deg);
-ms-transform: rotate(2deg);
-o-transform: rotate(2deg);
transform: rotate(2deg);
}
.token.comment,
.token.block-comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #7D8B99;
}
.token.punctuation {
color: #5F6364;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.function-name,
.token.constant,
.token.symbol,
.token.deleted {
color: #c92c2c;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.function,
.token.builtin,
.token.inserted {
color: #2f9c0a;
}
.token.operator,
.token.entity,
.token.url,
.token.variable {
color: #a67f59;
background: rgba(255, 255, 255, 0.5);
}
.token.atrule,
.token.attr-value,
.token.keyword,
.token.class-name {
color: #1990b8;
}
.token.regex,
.token.important {
color: #e90;
}
.language-css .token.string,
.style .token.string {
color: #a67f59;
background: rgba(255, 255, 255, 0.5);
}
.token.important {
font-weight: normal;
}
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
.namespace {
opacity: .7;
}
@media screen and (max-width: 767px) {
pre[class*="language-"]:before,
pre[class*="language-"]:after {
bottom: 14px;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
}
/* Plugin styles */
.token.tab:not(:empty):before,
.token.cr:before,
.token.lf:before {
color: #e0d7d1;
}
/* Plugin styles: Line Numbers */
pre[class*="language-"].line-numbers {
padding-left: 0;
}
pre[class*="language-"].line-numbers code {
padding-left: 3.8em;
}
pre[class*="language-"].line-numbers .line-numbers-rows {
left: 0;
}
/* Plugin styles: Line Highlight */
pre[class*="language-"][data-line] {
padding-top: 0;
padding-bottom: 0;
padding-left: 0;
}
pre[data-line] code {
position: relative;
padding-left: 4em;
}
pre .line-highlight {
margin-top: 0;
}