beego入门到实战
一、安装beego和bee工具
使用官网最新的v2版本
go get github.com/beego/beego/v2
go get github.com/beego/bee/v2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
或者,使用的是v1版本
go get github.com/astaxie/beego
go get github.com/beego/bee
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
二、使用bee工具构建项目框架
bee new beego_project(项目名)
将会创建一个典型的MVC框架应用
或者
bee api beego_project(项目名)
将构建一个纯后端项目
直接运行bee
查看更多命令
这里使用bee new
来构建MVC项目
三、启动项目开始愉快的coding
1.进入项目目录
使用bee run
启动
或者go run
启动
建议使用bee run
,这样会监听代码是否修改,自动重启
2.开始coding
四、路由详解
1.固定路由
1.响应所有类型的请求
beego.Router("/", &controllers.MainController{})
对应的Controller如下
package controllers
import (
"github.com/astaxie/beego"
)
type MainController struct {
beego.Controller
}
func (c *MainController) Get() {
c.Ctx.WriteString("Get")
}
func (c *MainController) Post() {
c.Ctx.WriteString("Post")
}
func (c *MainController) Put() {
c.Ctx.WriteString("Put")
}
func (c *MainController) Delete() {
c.Ctx.WriteString("Delete")
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
我们在调用get方法时,会执行对应控制器的get方法,同理post则会执行post方法,其他方法同样如此
2.响应基本路由
即将Router改为对应的方法类型,比如get和post
package routers
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
)
func init() {
beego.Get("/", func(ctx *context.Context) {
ctx.Output.Body([]byte("get"))
})
beego.Post("/", func(ctx *context.Context) {
ctx.Output.Body([]byte("post"))
})
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
支持以下所有类型
beego.Get(router, beego.FilterFunc)
beego.Post(router, beego.FilterFunc)
beego.Put(router, beego.FilterFunc)
beego.Patch(router, beego.FilterFunc)
beego.Head(router, beego.FilterFunc)
beego.Options(router, beego.FilterFunc)
beego.Delete(router, beego.FilterFunc)
beego.Any(router, beego.FilterFunc)
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
3.更改对应的响应方法
beego.Router("/", &controllers.MainController{}, "get:MyGet;post:MyPost")
beego.Router("/", &controllers.MainController{}, "get,post:MyPost")
beego.Router("/", &controllers.MainController{}, "*:MyPost")
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
如果同时存在 * 和对应的请求方法,那么优先执行对应请求的方法,例如同时注册了以下路由:
beego.Router("/",&controllers.MainController{},"*:AllFunc;post:MyPost")
那么执行POST请求的时候,执行MyPost而不执行 AllFunc
2.正则路由
beego.Router("/?:id", &controllers.MainController{})
匹配"/“或者”/123",此时变量":id"值为即为"/"后面的参数,及123
beego.Router("/:id", &controllers.MainController{})
匹配"/123",“/“后必须要参数,此时变量”:id"值为即为”/"后面的参数,及123
beego.Router("/:id([0-9]+)", &controllers.MainController{})
自定义正则匹配,只能匹配数字0-9, 例如对于"/123"可以匹配成功,此时id值为123
beego.Router("/*.*", &controllers.MainController{})
对于"/123.png"可以匹配成功,此时变量":path"值为"123",“:ext"值为"png”
beego.Router("/*", &controllers.MainController{})
全匹配,对于"/123"可以匹配成功,此时变量":splat"值为" 123
beego.Router("/:id:int", &controllers.MainController{})
int类型设置方式,匹配 :id为int类型,也可其他类型,如string类型,”/:id:string“,匹配 :id为string类型
beego.Router("/:id.html", &controllers.MainController{})
带有前缀的匹配,例如对于"/123.html"可以匹配成功,此时:id为123
可以在Controller中通过如下方式获取上面的变量
id := c.Ctx.Input.Param(":id")
id := c.Ctx.Input.Param(":splat")
id := c.Ctx.Input.Param(":path")
id := c.Ctx.Input.Param(":ext")
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
2
3
4
3.自动路由
注册路由的时候不需要指定url,只需要注册控制器即可
beego.AutoRouter(&controllers.MainController{})
/main/api
调用MainController中的api
方法
/main/api2
调用MainController中的api2
方法
除了前缀两个 /:controller/:method 的匹配之外,剩下的参数beego会帮解析为参数
保存在Ctx.Input.Params当中:
/main/api/1/2/3 调用MainController中的api方法,
参数如下map[0:1 1:2 2:3]
4.注解路由
// CMS API
type CMSController struct {
web.Controller
}
// @router /staticblock/:key [get]
func (this *CMSController) StaticBlock() {
}
// @router /all/:key [get]
func (this *CMSController) AllBlock() {
}
web.Include(&CMSController{})
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
5.命名空间
//初始化 namespace
ns :=
web.NewNamespace("/v1",
web.NSCond(func(ctx *context.Context) bool {
if ctx.Input.Domain() == "api.beego.me" {
return true
}
return false
}),
web.NSBefore(auth),
web.NSGet("/notallowed", func(ctx *context.Context) {
ctx.Output.Body([]byte("notAllowed"))
}),
web.NSRouter("/version", &AdminController{}, "get:ShowAPIVersion"),
web.NSRouter("/changepassword", &UserController{}),
web.NSNamespace("/shop",
web.NSBefore(sentry),
web.NSGet("/:id", func(ctx *context.Context) {
ctx.Output.Body([]byte("notAllowed"))
}),
),
web.NSNamespace("/cms",
web.NSInclude(
&controllers.MainController{},
&controllers.CMSController{},
&controllers.BlockController{},
),
),
)
//注册 namespace
web.AddNamespace(ns)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
五、解析参数
1.获取url上的参数,?后面的
GetString获取数据:
路由: beego.Router("/", &controllers.MainController{})
访问路径:http://127.0.0.1:8080/?id=111
获取数据:
id := c.GetString("id")
id2 := c.Input().Get("id")
这种方式不行:
id3 := c.Ctx.Input.Param(":id")
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2.获取url上的参数,/:id类型的
路由:beego.Router("/?:id:int", &controllers.MainController{})
访问路径:http://127.0.0.1:8080/111
获取数据:
id := c.GetString(":id")
id2 := c.Ctx.Input.Param(":id")
这种方式不行:
id3 := c.Input().Get(":id")
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
2
3
4
5
6
7
3.获取form表单数据
1.直接获取
GetString(key string) string
GetStrings(key string) []string
GetInt(key string) (int64, error) --返回两个值
GetBool(key string) (bool, error) --返回两个值
GetFloat(key string) (float64, error) --返回两个值
举例:
前端form表单:
姓名1:<input type="text" name="name">
姓名2:<input type="text" name="name">
年龄:<input type="text" name="age">
是: <input type="radio" name="is_true" value="true">
价格: <input type="text" name="price">
获取数据:
name := c.Input().Get("name") 获取的是第一个name的值
names := c.GetStrings("name") 获取所有的name的值,是个数组
age, err := c.GetInt("age")
is_true , err := c.GetBool("is_true")
price , err := c.GetFloat("price")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2…解析到结构体
type Student struct {
Id int
Name string `form:"user_name"`
Password string `form:"password"`
}
func (s *StudentController) Post() {
student := Student{}
if err := s.ParseForm(&student); err != nil {
return
}
fmt.Println(student)
fmt.Println(student.Name)
fmt.Println(student.Age)
fmt.Println(student.Addr)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6