- update pintoto

master
李光春 2 years ago
parent b1cc4bbdc0
commit b56a52027a

@ -37,12 +37,12 @@ type ApiOrderCreateSoonOrderResult struct {
Err error // 错误
}
func NewApiOrderCreateSoonOrderResult(result ApiOrderCreateSoonOrderResponse, body []byte, http gorequest.Response, err error) *ApiOrderCreateSoonOrderResult {
func newApiOrderCreateSoonOrderResult(result ApiOrderCreateSoonOrderResponse, body []byte, http gorequest.Response, err error) *ApiOrderCreateSoonOrderResult {
return &ApiOrderCreateSoonOrderResult{Result: result, Body: body, Http: http, Err: err}
}
// ApiOrderCreateSoonOrder 秒出单下单 https://www.showdoc.com.cn/1154868044931571/6437295495912025
func (app *App) ApiOrderCreateSoonOrder(param ApiOrderCreateSoonOrder) *ApiOrderCreateSoonOrderResult {
func (c *Client) ApiOrderCreateSoonOrder(param ApiOrderCreateSoonOrder) *ApiOrderCreateSoonOrderResult {
// api params
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
@ -51,9 +51,9 @@ func (app *App) ApiOrderCreateSoonOrder(param ApiOrderCreateSoonOrder) *ApiOrder
for k, v := range m {
params[k] = v
}
request, err := app.request("https://movieapi2.pintoto.cn/api/order/create-soon-order", params)
request, err := c.request(apiUrl+"/api/order/create-soon-order", params)
// 定义
var response ApiOrderCreateSoonOrderResponse
err = json.Unmarshal(request.ResponseBody, &response)
return NewApiOrderCreateSoonOrderResult(response, request.ResponseBody, request, err)
return newApiOrderCreateSoonOrderResult(response, request.ResponseBody, request, err)
}

@ -18,18 +18,18 @@ type ApiOrderCreateResult struct {
Err error // 错误
}
func NewApiOrderCreateResult(result ApiOrderCreateResponse, body []byte, http gorequest.Response, err error) *ApiOrderCreateResult {
func newApiOrderCreateResult(result ApiOrderCreateResponse, body []byte, http gorequest.Response, err error) *ApiOrderCreateResult {
return &ApiOrderCreateResult{Result: result, Body: body, Http: http, Err: err}
}
// ApiOrderCreate 下单api https://www.showdoc.com.cn/1154868044931571/5891022916496848
func (app *App) ApiOrderCreate(notMustParams ...Params) *ApiOrderCreateResult {
func (c *Client) ApiOrderCreate(notMustParams ...gorequest.Params) *ApiOrderCreateResult {
// 参数
params := app.NewParamsWith(notMustParams...)
params := gorequest.NewParamsWith(notMustParams...)
// 请求
request, err := app.request("https://movieapi2.pintoto.cn/api/order/create", params)
request, err := c.request(apiUrl+"/api/order/create", params)
// 定义
var response ApiOrderCreateResponse
err = json.Unmarshal(request.ResponseBody, &response)
return NewApiOrderCreateResult(response, request.ResponseBody, request, err)
return newApiOrderCreateResult(response, request.ResponseBody, request, err)
}

@ -40,20 +40,20 @@ type ApiOrderQueryResult struct {
Err error // 错误
}
func NewApiOrderQueryResult(result ApiOrderQueryResponse, body []byte, http gorequest.Response, err error) *ApiOrderQueryResult {
func newApiOrderQueryResult(result ApiOrderQueryResponse, body []byte, http gorequest.Response, err error) *ApiOrderQueryResult {
return &ApiOrderQueryResult{Result: result, Body: body, Http: http, Err: err}
}
// ApiOrderQuery 订单查询 https://www.showdoc.com.cn/1154868044931571/5965244588489845
func (app *App) ApiOrderQuery(thirdOrderId string) *ApiOrderQueryResult {
func (c *Client) ApiOrderQuery(thirdOrderId string) *ApiOrderQueryResult {
// 测试
param := NewParams()
param := gorequest.NewParams()
param.Set("thirdOrderId", thirdOrderId)
params := app.NewParamsWith(param)
params := gorequest.NewParamsWith(param)
// 请求
request, err := app.request("https://movieapi2.pintoto.cn/api/order/query", params)
request, err := c.request(apiUrl+"/api/order/query", params)
// 定义
var response ApiOrderQueryResponse
err = json.Unmarshal(request.ResponseBody, &response)
return NewApiOrderQueryResult(response, request.ResponseBody, request, err)
return newApiOrderQueryResult(response, request.ResponseBody, request, err)
}

@ -24,15 +24,15 @@ type ApiUserInfoResult struct {
Err error // 错误
}
func NewApiUserInfoResult(result ApiUserInfoResponse, body []byte, http gorequest.Response, err error) *ApiUserInfoResult {
func newApiUserInfoResult(result ApiUserInfoResponse, body []byte, http gorequest.Response, err error) *ApiUserInfoResult {
return &ApiUserInfoResult{Result: result, Body: body, Http: http, Err: err}
}
// ApiUserInfo 账号信息查询 https://www.showdoc.com.cn/1154868044931571/6269224958928211
func (app *App) ApiUserInfo() *ApiUserInfoResult {
request, err := app.request("https://movieapi2.pintoto.cn/api/user/info", map[string]interface{}{})
func (c *Client) ApiUserInfo() *ApiUserInfoResult {
request, err := c.request(apiUrl+"/api/user/info", map[string]interface{}{})
// 定义
var response ApiUserInfoResponse
err = json.Unmarshal(request.ResponseBody, &response)
return NewApiUserInfoResult(response, request.ResponseBody, request, err)
return newApiUserInfoResult(response, request.ResponseBody, request, err)
}

@ -1,88 +0,0 @@
package pintoto
import (
"go.dtapp.net/library/utils/golog"
"go.dtapp.net/library/utils/gomongo"
"go.dtapp.net/library/utils/gorequest"
"gorm.io/gorm"
"math"
"strconv"
"time"
)
// App 电影票服务
type App struct {
appKey string
appSecret string
mongo *gomongo.Client // 日志数据库
pgsql *gorm.DB // pgsql数据库
client *gorequest.App // 请求客户端
log *golog.Api // 日志服务
logTableName string // 日志表名
logStatus bool // 日志状态
}
func NewApp(appKey string, appSecret string, pgsql *gorm.DB) *App {
app := &App{appKey: appKey, appSecret: appSecret}
app.client = gorequest.NewHttp()
if pgsql != nil {
app.pgsql = pgsql
app.logStatus = true
app.logTableName = "pintoto"
app.log = golog.NewApi(&golog.ApiConfig{
Db: pgsql,
TableName: app.logTableName,
})
}
return app
}
// 请求
func (app *App) request(url string, params map[string]interface{}) (resp gorequest.Response, err error) {
// 公共参数
params["time"] = time.Now().Unix()
params["appKey"] = app.appKey
// 签名
params["sign"] = app.getSign(app.appSecret, params)
// 创建请求
client := app.client
// 设置请求地址
client.SetUri(url)
// 设置格式
client.SetContentTypeForm()
// 设置参数
client.SetParams(params)
// 发起请求
request, err := client.Post()
if err != nil {
return gorequest.Response{}, err
}
// 日志
if app.logStatus == true {
go app.postgresqlLog(request)
}
return request, err
}
func (app *App) GradeToFloat64(i interface{}) float64 {
switch v := i.(type) {
case string:
float, _ := strconv.ParseFloat(v, 64)
return float
case float64:
return v
case int64:
return float64(v) / math.Pow10(0)
default:
return 0
}
}

@ -0,0 +1,59 @@
package pintoto
import (
"go.dtapp.net/library/utils/golog"
"go.dtapp.net/library/utils/gomongo"
"go.dtapp.net/library/utils/gorequest"
"gorm.io/gorm"
"math"
"strconv"
)
type ConfigClient struct {
AppKey string
AppSecret string
MongoDb *gomongo.Client // 日志数据库
PgsqlDb *gorm.DB // pgsql数据库
}
// Client 电影票服务
type Client struct {
client *gorequest.App // 请求客户端
log *golog.ApiClient // 日志服务
logStatus bool // 日志状态
config *ConfigClient // 配置
}
func NewClient(config *ConfigClient) (*Client, error) {
var err error
c := &Client{config: config}
c.client = gorequest.NewHttp()
if c.config.PgsqlDb != nil {
c.logStatus = true
c.log, err = golog.NewApiClient(&golog.ConfigApiClient{
Db: c.config.PgsqlDb,
TableName: logTable,
})
if err != nil {
return nil, err
}
}
return c, nil
}
func (c *Client) GradeToFloat64(i interface{}) float64 {
switch v := i.(type) {
case string:
float, _ := strconv.ParseFloat(v, 64)
return float
case float64:
return v
case int64:
return float64(v) / math.Pow10(0)
default:
return 0
}
}

@ -0,0 +1,9 @@
package pintoto
const (
apiUrl = "https://movieapi2.pintoto.cn"
)
const (
logTable = "pintoto"
)

@ -0,0 +1,8 @@
package pintoto
func (c *Client) GetAppKey() string {
return c.config.AppKey
}
func (c *Client) GetAppSecret() string {
return c.config.AppSecret
}

@ -32,21 +32,21 @@ type GetCinemaListResult struct {
Err error // 错误
}
func NewGetCinemaListResult(result GetCinemaListResponse, body []byte, http gorequest.Response, err error) *GetCinemaListResult {
func newGetCinemaListResult(result GetCinemaListResponse, body []byte, http gorequest.Response, err error) *GetCinemaListResult {
return &GetCinemaListResult{Result: result, Body: body, Http: http, Err: err}
}
// GetCinemaList 影院列表 https://www.showdoc.com.cn/1154868044931571/5866426126744792
func (app *App) GetCinemaList(cityId int) *GetCinemaListResult {
func (c *Client) GetCinemaList(cityId int) *GetCinemaListResult {
// 参数
param := NewParams()
param := gorequest.NewParams()
param.Set("cityId", cityId)
// 转换
params := app.NewParamsWith(param)
params := gorequest.NewParamsWith(param)
// 请求
request, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-cinema-list", params)
request, err := c.request(apiUrl+"/movieapi/movie-info/get-cinema-list", params)
// 定义
var response GetCinemaListResponse
err = json.Unmarshal(request.ResponseBody, &response)
return NewGetCinemaListResult(response, request.ResponseBody, request, err)
return newGetCinemaListResult(response, request.ResponseBody, request, err)
}

@ -24,20 +24,20 @@ type GetCityAreaResult struct {
Err error // 错误
}
func NewGetCityAreaResult(result GetCityAreaResponse, body []byte, http gorequest.Response, err error) *GetCityAreaResult {
func newGetCityAreaResult(result GetCityAreaResponse, body []byte, http gorequest.Response, err error) *GetCityAreaResult {
return &GetCityAreaResult{Result: result, Body: body, Http: http, Err: err}
}
// GetCityArea 城市下区域
// https://www.showdoc.com.cn/1154868044931571/6243539682553126
func (app *App) GetCityArea(cityId int) *GetCityAreaResult {
func (c *Client) GetCityArea(cityId int) *GetCityAreaResult {
// 测试
param := NewParams()
param := gorequest.NewParams()
param.Set("cityId", cityId)
params := app.NewParamsWith(param)
params := gorequest.NewParamsWith(param)
// 请求
request, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-city-area", params)
request, err := c.request(apiUrl+"/movieapi/movie-info/get-city-area", params)
var response GetCityAreaResponse
err = json.Unmarshal(request.ResponseBody, &response)
return NewGetCityAreaResult(response, request.ResponseBody, request, err)
return newGetCityAreaResult(response, request.ResponseBody, request, err)
}

@ -27,15 +27,15 @@ type GetCityListResult struct {
Err error // 错误
}
func NewGetCityListResult(result GetCityListResponse, body []byte, http gorequest.Response, err error) *GetCityListResult {
func newGetCityListResult(result GetCityListResponse, body []byte, http gorequest.Response, err error) *GetCityListResult {
return &GetCityListResult{Result: result, Body: body, Http: http, Err: err}
}
// GetCityList 城市列表
// https://www.showdoc.com.cn/1154868044931571/5865562425538244
func (app *App) GetCityList() *GetCityListResult {
request, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-city-list", map[string]interface{}{})
func (c *Client) GetCityList() *GetCityListResult {
request, err := c.request(apiUrl+"/movieapi/movie-info/get-city-list", map[string]interface{}{})
var response GetCityListResponse
err = json.Unmarshal(request.ResponseBody, &response)
return NewGetCityListResult(response, request.ResponseBody, request, err)
return newGetCityListResult(response, request.ResponseBody, request, err)
}

@ -37,21 +37,21 @@ type GetHotListResult struct {
Err error // 错误
}
func NewGetHotListResult(result GetHotListResponse, body []byte, http gorequest.Response, err error) *GetHotListResult {
func newGetHotListResult(result GetHotListResponse, body []byte, http gorequest.Response, err error) *GetHotListResult {
return &GetHotListResult{Result: result, Body: body, Http: http, Err: err}
}
// GetHotList 正在热映 https://www.showdoc.com.cn/1154868044931571/5866125707634369
func (app *App) GetHotList(cityId int) *GetHotListResult {
func (c *Client) GetHotList(cityId int) *GetHotListResult {
// 参数
param := NewParams()
param := gorequest.NewParams()
param.Set("cityId", cityId)
// 转换
params := app.NewParamsWith(param)
params := gorequest.NewParamsWith(param)
// 请求
request, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-hot-list", params)
request, err := c.request(apiUrl+"/movieapi/movie-info/get-hot-list", params)
// 定义
var response GetHotListResponse
err = json.Unmarshal(request.ResponseBody, &response)
return NewGetHotListResult(response, request.ResponseBody, request, err)
return newGetHotListResult(response, request.ResponseBody, request, err)
}

@ -41,21 +41,21 @@ type GetScheduleListResult struct {
Err error // 错误
}
func NewGetScheduleListResult(result GetScheduleListResponse, body []byte, http gorequest.Response, err error) *GetScheduleListResult {
func newGetScheduleListResult(result GetScheduleListResponse, body []byte, http gorequest.Response, err error) *GetScheduleListResult {
return &GetScheduleListResult{Result: result, Body: body, Http: http, Err: err}
}
// GetScheduleList 场次排期 https://www.showdoc.com.cn/1154868044931571/5866708808899217
func (app *App) GetScheduleList(cinemaId int) *GetScheduleListResult {
func (c *Client) GetScheduleList(cinemaId int) *GetScheduleListResult {
// 参数
param := NewParams()
param := gorequest.NewParams()
param.Set("cinemaId", cinemaId)
// 转换
params := app.NewParamsWith(param)
params := gorequest.NewParamsWith(param)
// 请求
request, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-schedule-list", params)
request, err := c.request(apiUrl+"/movieapi/movie-info/get-schedule-list", params)
// 定义
var response GetScheduleListResponse
err = json.Unmarshal(request.ResponseBody, &response)
return NewGetScheduleListResult(response, request.ResponseBody, request, err)
return newGetScheduleListResult(response, request.ResponseBody, request, err)
}

@ -38,21 +38,21 @@ type GetSeatResult struct {
Err error // 错误
}
func NewGetSeatResult(result GetSeatResponse, body []byte, http gorequest.Response, err error) *GetSeatResult {
func newGetSeatResult(result GetSeatResponse, body []byte, http gorequest.Response, err error) *GetSeatResult {
return &GetSeatResult{Result: result, Body: body, Http: http, Err: err}
}
// GetSeat 座位 https://www.showdoc.com.cn/1154868044931571/5866824368760475
func (app *App) GetSeat(showId string) *GetSeatResult {
func (c *Client) GetSeat(showId string) *GetSeatResult {
// 参数
param := NewParams()
param := gorequest.NewParams()
param.Set("showId", showId)
// 转换
params := app.NewParamsWith(param)
params := gorequest.NewParamsWith(param)
// 请求
request, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-seat", params)
request, err := c.request(apiUrl+"/movieapi/movie-info/get-seat", params)
// 定义
var response GetSeatResponse
err = json.Unmarshal(request.ResponseBody, &response)
return NewGetSeatResult(response, request.ResponseBody, request, err)
return newGetSeatResult(response, request.ResponseBody, request, err)
}

@ -21,22 +21,22 @@ type GetShowDateResult struct {
Err error // 错误
}
func NewGetShowDateResult(result GetShowDateResponse, body []byte, http gorequest.Response, err error) *GetShowDateResult {
func newGetShowDateResult(result GetShowDateResponse, body []byte, http gorequest.Response, err error) *GetShowDateResult {
return &GetShowDateResult{Result: result, Body: body, Http: http, Err: err}
}
// GetShowDate 包含某电影的日期 https://www.showdoc.com.cn/1154868044931571/6091788579441818
func (app *App) GetShowDate(cityId, filmId int) *GetShowDateResult {
func (c *Client) GetShowDate(cityId, filmId int) *GetShowDateResult {
// 参数
param := NewParams()
param := gorequest.NewParams()
param.Set("cityId", cityId)
param.Set("filmId", filmId)
// 转换
params := app.NewParamsWith(param)
params := gorequest.NewParamsWith(param)
// 请求
request, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-show-date", params)
request, err := c.request(apiUrl+"/movieapi/movie-info/get-show-date", params)
// 定义
var response GetShowDateResponse
err = json.Unmarshal(request.ResponseBody, &response)
return NewGetShowDateResult(response, request.ResponseBody, request, err)
return newGetShowDateResult(response, request.ResponseBody, request, err)
}

@ -43,12 +43,12 @@ type GetShowListResult struct {
Err error // 错误
}
func NewGetShowListResult(result GetShowListResponse, body []byte, http gorequest.Response, err error) *GetShowListResult {
func newGetShowListResult(result GetShowListResponse, body []byte, http gorequest.Response, err error) *GetShowListResult {
return &GetShowListResult{Result: result, Body: body, Http: http, Err: err}
}
// GetShowList 包含某电影的影院 https://www.showdoc.com.cn/1154868044931571/6067372188376779
func (app *App) GetShowList(param GetShowList) *GetShowListResult {
func (c *Client) GetShowList(param GetShowList) *GetShowListResult {
// api params
params := map[string]interface{}{}
b, _ := json.Marshal(&param)
@ -57,9 +57,9 @@ func (app *App) GetShowList(param GetShowList) *GetShowListResult {
for k, v := range m {
params[k] = v
}
request, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-show-list", params)
request, err := c.request(apiUrl+"/movieapi/movie-info/get-show-list", params)
// 定义
var response GetShowListResponse
err = json.Unmarshal(request.ResponseBody, &response)
return NewGetShowListResult(response, request.ResponseBody, request, err)
return newGetShowListResult(response, request.ResponseBody, request, err)
}

@ -37,21 +37,21 @@ type GetSoonListResult struct {
Err error // 错误
}
func NewGetSoonListResult(result GetSoonListResponse, body []byte, http gorequest.Response, err error) *GetSoonListResult {
func newGetSoonListResult(result GetSoonListResponse, body []byte, http gorequest.Response, err error) *GetSoonListResult {
return &GetSoonListResult{Result: result, Body: body, Http: http, Err: err}
}
// GetSoonList 即将上映 https://www.showdoc.com.cn/1154868044931571/5866125707634369
func (app *App) GetSoonList(cityId int) *GetSoonListResult {
func (c *Client) GetSoonList(cityId int) *GetSoonListResult {
// 参数
param := NewParams()
param := gorequest.NewParams()
param.Set("cityId", cityId)
// 转换
params := app.NewParamsWith(param)
params := gorequest.NewParamsWith(param)
// 请求
request, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-soon-list", params)
request, err := c.request(apiUrl+"/movieapi/movie-info/get-soon-list", params)
// 定义
var response GetSoonListResponse
err = json.Unmarshal(request.ResponseBody, &response)
return NewGetSoonListResult(response, request.ResponseBody, request, err)
return newGetSoonListResult(response, request.ResponseBody, request, err)
}

@ -19,15 +19,15 @@ type GetVersionResult struct {
Err error // 错误
}
func NewGetVersionResult(result GetVersionResponse, body []byte, http gorequest.Response, err error) *GetVersionResult {
func newGetVersionResult(result GetVersionResponse, body []byte, http gorequest.Response, err error) *GetVersionResult {
return &GetVersionResult{Result: result, Body: body, Http: http, Err: err}
}
// GetVersion 获取同步版本号 https://www.showdoc.com.cn/1154868044931571/6566701084841699
func (app *App) GetVersion() *GetVersionResult {
request, err := app.request("https://movieapi2.pintoto.cn/movieapi/movie-info/get-version", map[string]interface{}{})
func (c *Client) GetVersion() *GetVersionResult {
request, err := c.request(apiUrl+"/movieapi/movie-info/get-version", map[string]interface{}{})
// 定义
var response GetVersionResponse
err = json.Unmarshal(request.ResponseBody, &response)
return NewGetVersionResult(response, request.ResponseBody, request, err)
return newGetVersionResult(response, request.ResponseBody, request, err)
}

@ -1,27 +0,0 @@
package pintoto
// Params 请求参数
type Params map[string]interface{}
func NewParams() Params {
p := make(Params)
return p
}
func (app *App) NewParamsWith(params ...Params) Params {
p := make(Params)
for _, v := range params {
p.SetParams(v)
}
return p
}
func (p Params) Set(key string, value interface{}) {
p[key] = value
}
func (p Params) SetParams(params Params) {
for key, value := range params {
p[key] = value
}
}

@ -8,8 +8,8 @@ import (
)
// 记录日志
func (app *App) postgresqlLog(request gorequest.Response) {
app.log.Record(golog.ApiPostgresqlLog{
func (c *Client) postgresqlLog(request gorequest.Response) {
c.log.Record(golog.ApiPostgresqlLog{
RequestTime: golog.TimeString{Time: request.RequestTime}, //【请求】时间
RequestUri: request.RequestUri, //【请求】链接
RequestUrl: gorequest.UriParse(request.RequestUri).Url, //【请求】链接

@ -0,0 +1,42 @@
package pintoto
import (
"go.dtapp.net/library/utils/gorequest"
"time"
)
// 请求
func (c *Client) request(url string, params map[string]interface{}) (gorequest.Response, error) {
// 公共参数
params["time"] = time.Now().Unix()
params["appKey"] = c.GetAppKey()
// 签名
params["sign"] = c.getSign(c.GetAppSecret(), params)
// 创建请求
client := c.client
// 设置请求地址
client.SetUri(url)
// 设置格式
client.SetContentTypeForm()
// 设置参数
client.SetParams(params)
// 发起请求
request, err := client.Post()
if err != nil {
return gorequest.Response{}, err
}
// 日志
if c.logStatus == true {
go c.postgresqlLog(request)
}
return request, err
}

@ -9,7 +9,7 @@ import (
"strconv"
)
func (app *App) getSign(appSecret string, p map[string]interface{}) string {
func (c *Client) getSign(appSecret string, p map[string]interface{}) string {
var keys []string
for k := range p {
keys = append(keys, k)
@ -17,7 +17,7 @@ func (app *App) getSign(appSecret string, p map[string]interface{}) string {
sort.Strings(keys)
signStr := ""
for _, key := range keys {
signStr += fmt.Sprintf("%s=%s&", key, app.getString(p[key]))
signStr += fmt.Sprintf("%s=%s&", key, c.getString(p[key]))
}
signStr += fmt.Sprintf("appSecret=%s", appSecret)
// md5加密
@ -26,7 +26,7 @@ func (app *App) getSign(appSecret string, p map[string]interface{}) string {
return fmt.Sprintf("%x", has)
}
func (app *App) getString(i interface{}) string {
func (c *Client) getString(i interface{}) string {
switch v := i.(type) {
case string:
return v
@ -41,12 +41,12 @@ func (app *App) getString(i interface{}) string {
}
// 获取请求数据
func (app *App) getRequestData(params map[string]interface{}) string {
func (c *Client) getRequestData(params map[string]interface{}) string {
// 公共参数
args := url.Values{}
// 请求参数
for key, val := range params {
args.Set(key, app.getString(val))
args.Set(key, c.getString(val))
}
return args.Encode()
}

Loading…
Cancel
Save