v1.3.1 docs

This commit is contained in:
MickMake 2022-02-28 19:51:21 +11:00
parent 287a1a334f
commit 5ea7e3a592
31 changed files with 172 additions and 154 deletions

106
.idea/workspace.xml generated
View File

@ -5,9 +5,18 @@
</component>
<component name="ChangeListManager">
<list default="true" id="76adadc9-ae71-42a6-82a1-66dbc8ecb14c" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/examples.txt" beforeDir="false" afterPath="$PROJECT_DIR$/examples.txt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/foo.png" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/foo.png" beforeDir="false" afterPath="$PROJECT_DIR$/foo.png" afterDir="false" />
<change beforePath="$PROJECT_DIR$/iSolarCloud/AppService/getPowerDevicePointNames/data.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/AppService/getPowerDevicePointNames/data.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/iSolarCloud/AppService/getPsList/data.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/AppService/getPsList/data.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/iSolarCloud/AppService/getTemplateList/data.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/AppService/getTemplateList/data.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/iSolarCloud/AppService/login/auth.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/AppService/login/auth.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/iSolarCloud/AppService/queryDeviceList/data.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/AppService/queryDeviceList/data.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/iSolarCloud/AppService/queryMutiPointDataList/data.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/AppService/queryMutiPointDataList/data.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/iSolarCloud/api/nullEndPoint/data.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/api/nullEndPoint/data.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/iSolarCloud/api/output/struct_graph.go" beforeDir="false" afterPath="$PROJECT_DIR$/iSolarCloud/api/output/struct_graph.go" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -73,7 +82,7 @@
<configuration name="GoSungrow" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="GoSungrow" />
<working_directory value="$PROJECT_DIR$" />
<parameters value="data graph template 8041 20220228 '{&quot;search_string&quot;:&quot;p13007&quot;,&quot;min_left_axis&quot;:40,&quot;max_left_axis&quot;:60}'" />
<parameters value="data graph template 8042 20220228" />
<kind value="PACKAGE" />
<package value="$PROJECT_DIR$" />
<directory value="$PROJECT_DIR$" />
@ -140,41 +149,6 @@
<line>95</line>
<option name="timeStamp" value="115" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/struct_template.go</url>
<line>98</line>
<option name="timeStamp" value="120" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/api/output/struct_graph.go</url>
<line>618</line>
<option name="timeStamp" value="154" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/funcs.go</url>
<line>478</line>
<option name="timeStamp" value="158" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/api/output/struct_graph.go</url>
<line>628</line>
<option name="timeStamp" value="160" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/struct_template.go</url>
<line>68</line>
<option name="timeStamp" value="164" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/api/output/struct_graph.go</url>
<line>533</line>
<option name="timeStamp" value="166" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/api/output/struct_graph.go</url>
<line>255</line>
<option name="timeStamp" value="174" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/struct_template.go</url>
<line>119</line>
@ -210,11 +184,6 @@
<line>278</line>
<option name="timeStamp" value="206" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/struct_template.go</url>
<line>49</line>
<option name="timeStamp" value="207" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/funcs.go</url>
<line>330</line>
@ -235,11 +204,6 @@
<line>302</line>
<option name="timeStamp" value="256" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/AppService/queryMutiPointDataList/data.go</url>
<line>170</line>
<option name="timeStamp" value="257" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/funcs.go</url>
<line>399</line>
@ -256,34 +220,44 @@
<option name="timeStamp" value="266" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/struct_template.go</url>
<line>80</line>
<option name="timeStamp" value="267" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/AppService/queryMutiPointDataList/data.go</url>
<line>225</line>
<option name="timeStamp" value="268" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/funcs.go</url>
<line>474</line>
<option name="timeStamp" value="269" />
<url>file://$PROJECT_DIR$/iSolarCloud/api/output/struct_graph.go</url>
<line>270</line>
<option name="timeStamp" value="291" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/api/output/struct_graph.go</url>
<line>605</line>
<option name="timeStamp" value="270" />
<line>257</line>
<option name="timeStamp" value="311" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/api/output/struct_graph.go</url>
<line>407</line>
<option name="timeStamp" value="274" />
<line>634</line>
<option name="timeStamp" value="312" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/api/output/struct_graph.go</url>
<line>147</line>
<option name="timeStamp" value="276" />
<line>76</line>
<option name="timeStamp" value="313" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/api/struct_response.go</url>
<line>23</line>
<option name="timeStamp" value="324" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/api/datetime.go</url>
<line>63</line>
<option name="timeStamp" value="326" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/api/output/struct_graph.go</url>
<line>204</line>
<option name="timeStamp" value="331" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/iSolarCloud/api/output/struct_graph.go</url>
<line>181</line>
<option name="timeStamp" value="332" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@ -172,6 +172,16 @@ $ ./bin/GoSungrow data graph template 8042 20220224 '{"search_string":"p13019"}'
```
![alt text](https://github.com/MickMake/GoSungrow/blob/master/docs/AppService_queryMutiPointDataList-20220224-8042.png?raw=true)
Produce graphs of all points from template 8040 for date 2022/02/24 with a different width and height.
```
$ ./bin/GoSungrow data graph template 8042 20220228 '{"width":2400,"height":500}'
```
![alt text](https://github.com/MickMake/GoSungrow/blob/master/docs/AppService_queryMutiPointDataList-20220228-8042-PurchasedPower.png?raw=true)
![alt text](https://github.com/MickMake/GoSungrow/blob/master/docs/AppService_queryMutiPointDataList-20220228-8042-LoadPower.png?raw=true)
![alt text](https://github.com/MickMake/GoSungrow/blob/master/docs/AppService_queryMutiPointDataList-20220228-8042-BatteryTemperature.png?raw=true)
![alt text](https://github.com/MickMake/GoSungrow/blob/master/docs/AppService_queryMutiPointDataList-20220228-8042-InternalAirTemperature.png?raw=true)
![alt text](https://github.com/MickMake/GoSungrow/blob/master/docs/AppService_queryMutiPointDataList-20220228-8042-BatteryChargingPower.png?raw=true)
![alt text](https://github.com/MickMake/GoSungrow/blob/master/docs/AppService_queryMutiPointDataList-20220228-8042-BatteryDischargingPower.png?raw=true)
Produce daily report for point_id p83106 for date 2022/02/24.
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
foo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -131,9 +131,10 @@ func (e *EndPoint) GetDataTable() output.Table {
// table.InitGraph(output.GraphRequest {
// Title: "",
// TimeColumn: output.SetInteger(1),
// SearchColumn: output.SetInteger(2),
// NameColumn: output.SetInteger(3),
// ValueColumn: output.SetInteger(4),
// UnitsColumn: output.SetInteger(5),
// SearchColumn: output.SetInteger(2),
// SearchString: output.SetString(""),
// MinLeftAxis: output.SetFloat(0),
// MaxLeftAxis: output.SetFloat(0),

View File

@ -283,9 +283,10 @@ func (e *EndPoint) GetDataTable() output.Table {
table.InitGraph(output.GraphRequest {
Title: "",
TimeColumn: output.SetInteger(1),
ValueColumn: output.SetInteger(3),
UnitsColumn: output.SetInteger(4),
SearchColumn: output.SetInteger(2),
NameColumn: output.SetInteger(3),
ValueColumn: output.SetInteger(4),
UnitsColumn: output.SetInteger(5),
SearchString: output.SetString(""),
MinLeftAxis: output.SetFloat(0),
MaxLeftAxis: output.SetFloat(0),

View File

@ -95,9 +95,10 @@ func (e *EndPoint) GetDataTable() output.Table {
// table.InitGraph(output.GraphRequest {
// Title: "",
// TimeColumn: output.SetInteger(1),
// SearchColumn: output.SetInteger(2),
// NameColumn: output.SetInteger(3),
// ValueColumn: output.SetInteger(4),
// UnitsColumn: output.SetInteger(5),
// SearchColumn: output.SetInteger(2),
// SearchString: output.SetString(""),
// MinLeftAxis: output.SetFloat(0),
// MaxLeftAxis: output.SetFloat(0),

View File

@ -83,6 +83,10 @@ func (e *EndPoint) Login(auth *SunGrowAuth) error {
if auth.Force {
e.Auth.Token = ""
e.Response.ResultData.Token = ""
// e.Error = os.Remove(filepath.Join(e.ApiRoot.GetCacheDir(), e.CacheFilename()))
// if e.Error != nil {
// break
// }
}
if e.IsTokenValid() {

View File

@ -242,9 +242,10 @@ func (e *EndPoint) GetDataTable() output.Table {
table.InitGraph(output.GraphRequest {
Title: "",
TimeColumn: output.SetInteger(1),
SearchColumn: output.SetInteger(2),
NameColumn: output.SetInteger(4),
ValueColumn: output.SetInteger(5),
UnitsColumn: output.SetInteger(6),
SearchColumn: output.SetInteger(2),
SearchString: output.SetString(""),
MinLeftAxis: output.SetFloat(0),
MaxLeftAxis: output.SetFloat(0),

View File

@ -213,9 +213,10 @@ func (e *EndPoint) GetDataTable(points api.TemplatePoints) output.Table {
table.InitGraph(output.GraphRequest {
Title: "",
TimeColumn: output.SetInteger(1),
SearchColumn: output.SetInteger(2),
NameColumn: output.SetInteger(3),
ValueColumn: output.SetInteger(4),
UnitsColumn: output.SetInteger(5),
SearchColumn: output.SetInteger(2),
SearchString: output.SetString(""),
MinLeftAxis: output.SetFloat(0),
MaxLeftAxis: output.SetFloat(0),

View File

@ -96,9 +96,10 @@ func (e *EndPoint) GetDataTable() output.Table {
// table.InitGraph(output.GraphRequest {
// Title: "",
// TimeColumn: output.SetInteger(1),
// SearchColumn: output.SetInteger(2),
// NameColumn: output.SetInteger(3),
// ValueColumn: output.SetInteger(4),
// UnitsColumn: output.SetInteger(5),
// SearchColumn: output.SetInteger(2),
// SearchString: output.SetString(""),
// MinLeftAxis: output.SetFloat(0),
// MaxLeftAxis: output.SetFloat(0),

View File

@ -4,6 +4,7 @@ import (
"GoSungrow/Only"
"encoding/json"
"errors"
"fmt"
"github.com/wcharczuk/go-chart/v2"
"github.com/wcharczuk/go-chart/v2/drawing"
"go.pennock.tech/tabular"
@ -20,12 +21,16 @@ type GraphRequest struct {
TimeColumn *int `json:"time_column"`
ValueColumn *int `json:"value_column"`
UnitsColumn *int `json:"units_column"`
NameColumn *int `json:"name_column"`
SearchColumn *int `json:"search_column"`
SearchString *string `json:"search_string"`
MinLeftAxis *float64 `json:"min_left_axis"`
MaxLeftAxis *float64 `json:"max_left_axis"`
Width *int `json:"width"`
Height *int `json:"height"`
Error error `json:"-"`
}
@ -39,71 +44,13 @@ func SetFloat(v float64) *float64 {
return &v
}
// type Integer int
// func (c *Integer) Set(f int) (*Integer, bool) {
// var changed bool
// for range Only.Once {
// ff := Integer(f)
// if c == nil {
// c = &ff
// break
// }
//
// if*c == ff {
// break
// }
//
// changed = true
// }
// return c, changed
// }
//
// type Float float64
// func (c *Float) Set(f float64) (*Float, bool) {
// var changed bool
// for range Only.Once {
// ff := Float(f)
// if c == nil {
// c = &ff
// break
// }
//
// if*c == ff {
// break
// }
//
// changed = true
// }
// return c, changed
// }
//
// type String string
// func (c *String) Set(s string) (*String, bool) {
// var changed bool
// for range Only.Once {
// ss := String(s)
// if c == nil {
// c = &ss
// break
// }
//
// if*c == ss {
// break
// }
//
// if ss == "" {
// break
// }
//
// changed = true
// }
// return c, changed
// }
func JsonToGraphRequest(j Json) GraphRequest {
var ret GraphRequest
for range Only.Once {
if j == "" {
break
}
ret.Error = json.Unmarshal([]byte(j), &ret)
if ret.Error != nil {
break
@ -127,7 +74,12 @@ func (t *Table) SetGraph(req GraphRequest) error {
t.graph = New(req.Title)
}
t.Error = t.graph.SetFilename(t.filePrefix + ".png")
t.graph.SetWidth(req.Width)
if t.Error != nil {
break
}
t.graph.SetHeight(req.Height)
if t.Error != nil {
break
}
@ -180,6 +132,7 @@ func (t *Table) ProcessGraphData() error {
for range Only.Once {
req := t.graph.req
t.graph.searchName = ""
var units string
var times []time.Time
var values []float64
@ -198,7 +151,17 @@ func (t *Table) ProcessGraphData() error {
_ = t.SetTitle(cell.String())
}
//
if t.graph.searchName == "" {
if *req.NameColumn > 0 {
cell, t.Error = t.table.CellAt(tabular.CellLocation{Row: row, Column: *req.NameColumn})
if t.Error != nil {
continue
}
t.graph.searchName = cell.String()
}
}
// Get units
if units == "" {
if *req.UnitsColumn > 0 {
cell, t.Error = t.table.CellAt(tabular.CellLocation{Row: row, Column: *req.UnitsColumn})
@ -215,7 +178,7 @@ func (t *Table) ProcessGraphData() error {
continue
}
var tim time.Time
tim, t.Error = time.Parse(DateTimeSearchLayout, cell.String())
tim, t.Error = time.ParseInLocation(DateTimeSearchLayout, cell.String(), time.Local) // @TODO - May have to revisit this!
if t.Error != nil {
continue
}
@ -234,6 +197,11 @@ func (t *Table) ProcessGraphData() error {
values = append(values, val)
}
t.Error = t.graph.SetFilename(fmt.Sprintf("%s-%s.png", t.filePrefix, strings.ReplaceAll(t.graph.searchName, " ", "")))
if t.Error != nil {
break
}
t.Error = t.graph.SetX("Date", times...)
if t.Error != nil {
break
@ -276,17 +244,42 @@ func (t *Table) SearchStrings() SearchStrings {
}
func (t *Table) CreateGraph() error {
return t.graph.Generate()
for range Only.Once {
if *t.graph.req.SearchString != "" {
t.Error = t.graph.Generate()
break
}
t.Error = t.FindSearchStrings()
if t.Error != nil {
break
}
for s := range t.graph.otherSearch {
t.graph.req.SearchString = &s
t.Error = t.ProcessGraphData()
if t.Error != nil {
continue
}
t.Error = t.graph.Generate()
if t.Error != nil {
continue
}
}
}
return t.Error
}
func (t *Table) CreateGraphAll() error {
return t.graph.Generate()
}
// func (t *Table) CreateGraphAll() error {
// return t.graph.Generate()
// }
type Chart struct {
Error error `json:"-"`
searchName string
otherSearch SearchStrings
req GraphRequest
filename string
@ -374,6 +367,34 @@ func New(title string) *Chart {
}
func (c *Chart) SetWidth(v *int) {
for range Only.Once {
if v == nil {
c.graph.Width = 3840
break
}
if *v == 0 {
c.graph.Width = 3840
break
}
c.graph.Width = *v
}
}
func (c *Chart) SetHeight(v *int) {
for range Only.Once {
if v == nil {
c.graph.Height = 1080
break
}
if *v == 0 {
c.graph.Height = 1080
break
}
c.graph.Height = *v
}
}
func (c *Chart) SetFilename(fn string) error {
for range Only.Once {
@ -462,7 +483,7 @@ func (c *Chart) SetX(name string, values ...time.Time) error {
Name: name,
NameStyle: chart.Style{},
Style: chart.Style{},
ValueFormatter: nil,
ValueFormatter: chart.TimeValueFormatterWithFormat(DateTimeLayout),
Range: &chart.ContinuousRange {
Min: 0,
Max: 0,
@ -496,7 +517,8 @@ func (c *Chart) SetX(name string, values ...time.Time) error {
// Descending: false,
// }
c.timeSeries1.XValues = append(c.timeSeries1.XValues, values...)
c.timeSeries1.XValues = values
// c.timeSeries1.XValues = append(c.timeSeries1.XValues, values...)
// c.timeSeries2.XValues = append(c.timeSeries2.XValues, values...)
}
return c.Error
@ -533,7 +555,9 @@ func (c *Chart) SetY(name string, values ...float64) error {
c.graph.YAxis.Name = name
c.timeSeries1.YValues = append(c.timeSeries1.YValues, values...)
c.timeSeries1.YValues = values
// c.timeSeries1.YValues = append(c.timeSeries1.YValues, values...)
// c.graph.Series = []chart.Series{ c.timeSeries }
// c.graph.YAxis.Range = &chart.ContinuousRange {
// Min: 0,
@ -596,13 +620,6 @@ func (c *Chart) Generate() error {
break
}
// c.graph.YAxis.Range = &chart.ContinuousRange {
// Min: *c.req.MinLeftAxis,
// Max: *c.req.MaxLeftAxis,
// Domain: 0,
// Descending: false,
// }
c.timeSeries1.Style = chart.Style {
StrokeColor: drawing.ColorBlue,
FillColor: drawing.ColorBlue.WithAlpha(64),
@ -613,8 +630,17 @@ func (c *Chart) Generate() error {
// c.timeSeries2,
}
c.graph.Title = c.req.Title
c.graph.DPI = 150
for range Only.Once {
if c.req.Title != "" {
c.graph.Title = c.req.Title
break
}
c.graph.Title = c.searchName
}
fmt.Printf("Creating graph file '%s'\n", c.filename)
var f *os.File
f, c.Error = os.Create(c.filename)
if c.Error != nil {
@ -624,8 +650,6 @@ func (c *Chart) Generate() error {
//goland:noinspection GoUnhandledErrorResult,GoDeferInLoop
defer f.Close()
c.graph.Width = 1024
c.graph.Height = 768
c.Error = c.graph.Render(chart.PNG, f)
}
return c.Error