2022-12-15 01:01:33 +01:00
// Code generated by qtc from "expand-with-exprs.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
//line app/vmselect/prometheus/expand-with-exprs.qtpl:1
package prometheus
//line app/vmselect/prometheus/expand-with-exprs.qtpl:1
import (
2023-04-25 10:40:01 +02:00
"fmt"
2022-12-15 01:01:33 +01:00
"github.com/VictoriaMetrics/metricsql"
)
// ExpandWithExprsResponse returns a webpage, which expands with templates in q MetricsQL.
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:9
2022-12-15 01:01:33 +01:00
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:9
2022-12-15 01:01:33 +01:00
var (
_ = qtio422016 . Copy
_ = qt422016 . AcquireByteBuffer
)
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:9
2022-12-15 01:01:33 +01:00
func StreamExpandWithExprsResponse ( qw422016 * qt422016 . Writer , q string ) {
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:9
2022-12-15 01:01:33 +01:00
qw422016 . N ( ) . S ( ` <html><head><title>Expand WITH expressions</title><style>p { font-weight: bold }textarea { margin: 1em }</style></head><body><div><form method="get"><div><p><a href="https://docs.victoriametrics.com/MetricsQL.html">MetricsQL</a> query with optional WITH expressions:</p><textarea name="query" style="height: 15em; width: 90%"> ` )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:26
2022-12-15 01:01:33 +01:00
qw422016 . E ( ) . S ( q )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:26
2022-12-15 01:01:33 +01:00
qw422016 . N ( ) . S ( ` </textarea><br/><input type="submit" value="Expand" /><p><a href="https://docs.victoriametrics.com/MetricsQL.html">MetricsQL</a> query after expanding WITH expressions and applying other optimizations:</p><textarea style="height: 5em; width: 90%" readonly="readonly"> ` )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:32
2022-12-15 01:01:33 +01:00
streamexpandWithExprs ( qw422016 , q )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:32
2022-12-15 01:01:33 +01:00
qw422016 . N ( ) . S ( ` </textarea></div></form></div><div> ` )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:37
2022-12-15 01:01:33 +01:00
streamwithExprsTutorial ( qw422016 )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:37
2022-12-15 01:01:33 +01:00
qw422016 . N ( ) . S ( ` </div></body></html> ` )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
2022-12-15 01:01:33 +01:00
}
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
2022-12-15 01:01:33 +01:00
func WriteExpandWithExprsResponse ( qq422016 qtio422016 . Writer , q string ) {
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
2022-12-15 01:01:33 +01:00
qw422016 := qt422016 . AcquireWriter ( qq422016 )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
2022-12-15 01:01:33 +01:00
StreamExpandWithExprsResponse ( qw422016 , q )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
2022-12-15 01:01:33 +01:00
qt422016 . ReleaseWriter ( qw422016 )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
2022-12-15 01:01:33 +01:00
}
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
2022-12-15 01:01:33 +01:00
func ExpandWithExprsResponse ( q string ) string {
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
2022-12-15 01:01:33 +01:00
qb422016 := qt422016 . AcquireByteBuffer ( )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
2022-12-15 01:01:33 +01:00
WriteExpandWithExprsResponse ( qb422016 , q )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
2022-12-15 01:01:33 +01:00
qs422016 := string ( qb422016 . B )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
2022-12-15 01:01:33 +01:00
qt422016 . ReleaseByteBuffer ( qb422016 )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
2022-12-15 01:01:33 +01:00
return qs422016
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
2022-12-15 01:01:33 +01:00
}
//line app/vmselect/prometheus/expand-with-exprs.qtpl:43
2023-04-25 10:40:01 +02:00
func streamexpandWithExprs ( qw422016 * qt422016 . Writer , q string ) {
2022-12-15 01:01:33 +01:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:44
2023-04-25 10:40:01 +02:00
if len ( q ) == 0 {
2022-12-15 01:01:33 +01:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:45
2023-04-25 10:40:01 +02:00
return
//line app/vmselect/prometheus/expand-with-exprs.qtpl:46
2022-12-15 01:01:33 +01:00
}
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:48
2022-12-15 01:01:33 +01:00
expr , err := metricsql . Parse ( q )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:49
2022-12-15 01:01:33 +01:00
if err != nil {
//line app/vmselect/prometheus/expand-with-exprs.qtpl:49
2023-04-25 10:40:01 +02:00
qw422016 . N ( ) . S ( ` Cannot parse query: ` )
2022-12-15 01:01:33 +01:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:50
2023-04-25 10:40:01 +02:00
qw422016 . E ( ) . V ( err )
2022-12-15 01:01:33 +01:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:51
2023-04-25 10:40:01 +02:00
} else {
//line app/vmselect/prometheus/expand-with-exprs.qtpl:52
2022-12-15 01:01:33 +01:00
expr = metricsql . Optimize ( expr )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:53
2023-04-25 10:40:01 +02:00
qw422016 . E ( ) . Z ( expr . AppendString ( nil ) )
2022-12-15 01:01:33 +01:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:54
2023-04-25 10:40:01 +02:00
}
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
2022-12-15 01:01:33 +01:00
}
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
2022-12-15 01:01:33 +01:00
func writeexpandWithExprs ( qq422016 qtio422016 . Writer , q string ) {
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
2022-12-15 01:01:33 +01:00
qw422016 := qt422016 . AcquireWriter ( qq422016 )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
2022-12-15 01:01:33 +01:00
streamexpandWithExprs ( qw422016 , q )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
2022-12-15 01:01:33 +01:00
qt422016 . ReleaseWriter ( qw422016 )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
2022-12-15 01:01:33 +01:00
}
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
2022-12-15 01:01:33 +01:00
func expandWithExprs ( q string ) string {
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
2022-12-15 01:01:33 +01:00
qb422016 := qt422016 . AcquireByteBuffer ( )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
2022-12-15 01:01:33 +01:00
writeexpandWithExprs ( qb422016 , q )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
2022-12-15 01:01:33 +01:00
qs422016 := string ( qb422016 . B )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
2022-12-15 01:01:33 +01:00
qt422016 . ReleaseByteBuffer ( qb422016 )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
2022-12-15 01:01:33 +01:00
return qs422016
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
2022-12-15 01:01:33 +01:00
}
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:59
2022-12-15 01:01:33 +01:00
func streamwithExprsTutorial ( qw422016 * qt422016 . Writer ) {
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:59
2022-12-15 01:01:33 +01:00
qw422016 . N ( ) . S ( `
< h3 > Tutorial for WITH expressions in < a href = "https://docs.victoriametrics.com/MetricsQL.html" > MetricsQL < / a > < / h3 >
< p >
2022-12-25 17:36:20 +01:00
Let ' s look at the following real query from < a href = "https://grafana.com/grafana/dashboards/1860-node-exporter-full/" > Node Exporter Full < / a > dashboard :
2022-12-15 01:01:33 +01:00
< / p >
< pre >
(
(
node_memory_MemTotal_bytes { instance = ~ "$node:$port" , job = ~ "$job" }
-
node_memory_MemFree_bytes { instance = ~ "$node:$port" , job = ~ "$job" }
)
/
node_memory_MemTotal_bytes { instance = ~ "$node:$port" , job = ~ "$job" }
)
*
100
< / pre >
< p >
It is clear the query calculates the percentage of used memory
for the given $ node , $ port and $ job . Isn ' t it ? : )
< / p >
< p >
What ' s wrong with this query ? Copy - pasted label filters for distinct timeseries
which makes it easy to mistype these filters during modification .
Let ' s simplify the query with WITH expressions :
< / p >
< pre >
WITH (
commonFilters = { instance = ~ "$node:$port" , job = ~ "$job" }
)
(
node_memory_MemTotal_bytes { commonFilters }
-
node_memory_MemFree_bytes { commonFilters }
)
/
node_memory_MemTotal_bytes { commonFilters } * 100
< / pre >
< p >
Now label filters are located in a single place instead of three distinct places .
The query mentions node_memory_MemTotal_bytes metric twice and { commonFilters }
three times . WITH expressions may improve this :
< / p >
< pre >
WITH (
my_resource_utilization ( free , limit , filters ) = ( limit { filters } - free { filters } ) / limit { filters } * 100
)
my_resource_utilization (
node_memory_MemFree_bytes ,
node_memory_MemTotal_bytes ,
{ instance = ~ "$node:$port" , job = ~ "$job" } ,
)
< / pre >
< p >
Now the template function my_resource_utilization ( ) may be used for monitoring arbitrary
resources - memory , CPU , network , storage , you name it .
< / p >
< p >
2022-12-25 17:36:20 +01:00
Let ' s take another nice query from < a href = "https://grafana.com/grafana/dashboards/1860-node-exporter-full/" > Node Exporter Full < / a > dashboard :
2022-12-15 01:01:33 +01:00
< / p >
< pre >
(
(
(
count (
count ( node_cpu_seconds_total { instance = ~ "$node:$port" , job = ~ "$job" } ) by ( cpu )
)
)
-
avg (
sum by ( mode ) ( rate ( node_cpu_seconds_total { mode = ' idle ' , instance = ~ "$node:$port" , job = ~ "$job" } [ 5 m ] ) )
)
)
*
100
)
/
count (
count ( node_cpu_seconds_total { instance = ~ "$node:$port" , job = ~ "$job" } ) by ( cpu )
)
< / pre >
< p >
Do you understand what does this mess do ? Is it manageable ? : ) WITH expressions are happy to help in a few iterations .
< br / >
< br / >
1. Extract common filters used in multiple places into a commonFilters variable :
< / p >
< pre >
WITH (
commonFilters = { instance = ~ "$node:$port" , job = ~ "$job" }
)
(
(
(
count (
count ( node_cpu_seconds_total { commonFilters } ) by ( cpu )
)
)
-
avg (
sum by ( mode ) ( rate ( node_cpu_seconds_total { mode = ' idle ' , commonFilters } [ 5 m ] ) )
)
)
*
100
)
/
count (
count ( node_cpu_seconds_total { commonFilters } ) by ( cpu )
)
< / pre >
< p >
2. Extract "count(count(...) by (cpu))" into cpuCount variable :
< / p >
< pre >
WITH (
commonFilters = { instance = ~ "$node:$port" , job = ~ "$job" } ,
cpuCount = count ( count ( node_cpu_seconds_total { commonFilters } ) by ( cpu ) )
)
(
(
cpuCount
-
avg (
sum by ( mode ) ( rate ( node_cpu_seconds_total { mode = ' idle ' , commonFilters } [ 5 m ] ) )
)
)
*
100
) / cpuCount
< / pre >
< p >
3. Extract rate ( ... ) part into cpuIdle variable , since it is clear now that this part calculates the number of idle CPUs :
< / p >
< pre >
WITH (
commonFilters = { instance = ~ "$node:$port" , job = ~ "$job" } ,
cpuCount = count ( count ( node_cpu_seconds_total { commonFilters } ) by ( cpu ) ) ,
cpuIdle = sum ( rate ( node_cpu_seconds_total { mode = ' idle ' , commonFilters } [ 5 m ] ) )
)
( ( cpuCount - cpuIdle ) * 100 ) / cpuCount
< / pre >
< p >
4. Put node_cpu_seconds_total { commonFilters } into its own varialbe with the name cpuSeconds :
< / p >
< pre >
WITH (
cpuSeconds = node_cpu_seconds_total { instance = ~ "$node:$port" , job = ~ "$job" } ,
cpuCount = count ( count ( cpuSeconds ) by ( cpu ) ) ,
cpuIdle = sum ( rate ( cpuSeconds { mode = ' idle ' } [ 5 m ] ) )
)
( ( cpuCount - cpuIdle ) * 100 ) / cpuCount
< / pre >
< p >
Now the query became more clear comparing to the initial query .
< / p >
< p >
WITH expressions may be nested and may be put anywhere . Try expanding the following query :
< / p >
< pre >
WITH (
f ( a , b ) = WITH (
f1 ( x ) = b - x ,
f2 ( x ) = x + x
) f1 ( a ) * f2 ( b )
) f ( foo , with ( x = bar ) x )
< / pre >
` )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
2022-12-15 01:01:33 +01:00
}
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
2022-12-15 01:01:33 +01:00
func writewithExprsTutorial ( qq422016 qtio422016 . Writer ) {
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
2022-12-15 01:01:33 +01:00
qw422016 := qt422016 . AcquireWriter ( qq422016 )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
2022-12-15 01:01:33 +01:00
streamwithExprsTutorial ( qw422016 )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
2022-12-15 01:01:33 +01:00
qt422016 . ReleaseWriter ( qw422016 )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
2022-12-15 01:01:33 +01:00
}
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
2022-12-15 01:01:33 +01:00
func withExprsTutorial ( ) string {
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
2022-12-15 01:01:33 +01:00
qb422016 := qt422016 . AcquireByteBuffer ( )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
2022-12-15 01:01:33 +01:00
writewithExprsTutorial ( qb422016 )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
qs422016 := string ( qb422016 . B )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
qt422016 . ReleaseByteBuffer ( qb422016 )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
return qs422016
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
}
//line app/vmselect/prometheus/expand-with-exprs.qtpl:249
func StreamExpandWithExprsJSONResponse ( qw422016 * qt422016 . Writer , q string ) {
//line app/vmselect/prometheus/expand-with-exprs.qtpl:250
streamexpandWithExprsJSON ( qw422016 , q )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
}
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
func WriteExpandWithExprsJSONResponse ( qq422016 qtio422016 . Writer , q string ) {
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
qw422016 := qt422016 . AcquireWriter ( qq422016 )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
StreamExpandWithExprsJSONResponse ( qw422016 , q )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
qt422016 . ReleaseWriter ( qw422016 )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
}
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
func ExpandWithExprsJSONResponse ( q string ) string {
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
qb422016 := qt422016 . AcquireByteBuffer ( )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
WriteExpandWithExprsJSONResponse ( qb422016 , q )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
qs422016 := string ( qb422016 . B )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
qt422016 . ReleaseByteBuffer ( qb422016 )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
return qs422016
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
}
//line app/vmselect/prometheus/expand-with-exprs.qtpl:253
func streamexpandWithExprsJSON ( qw422016 * qt422016 . Writer , q string ) {
//line app/vmselect/prometheus/expand-with-exprs.qtpl:254
if len ( q ) == 0 {
//line app/vmselect/prometheus/expand-with-exprs.qtpl:254
qw422016 . N ( ) . S ( ` { "status": "error","error": "query string cannot be empty"} ` )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:259
return
//line app/vmselect/prometheus/expand-with-exprs.qtpl:260
}
//line app/vmselect/prometheus/expand-with-exprs.qtpl:260
qw422016 . N ( ) . S ( ` { ` )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:263
expr , err := metricsql . Parse ( q )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:264
if err != nil {
//line app/vmselect/prometheus/expand-with-exprs.qtpl:264
qw422016 . N ( ) . S ( ` "status": "error","error": ` )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:266
qw422016 . N ( ) . Q ( fmt . Sprintf ( "Cannot parse query: %s" , err ) )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:267
} else {
//line app/vmselect/prometheus/expand-with-exprs.qtpl:268
expr = metricsql . Optimize ( expr )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:268
qw422016 . N ( ) . S ( ` "status": "success","expr": ` )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:270
qw422016 . N ( ) . Q ( string ( expr . AppendString ( nil ) ) )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:271
}
//line app/vmselect/prometheus/expand-with-exprs.qtpl:271
qw422016 . N ( ) . S ( ` } ` )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
}
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
func writeexpandWithExprsJSON ( qq422016 qtio422016 . Writer , q string ) {
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
qw422016 := qt422016 . AcquireWriter ( qq422016 )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
streamexpandWithExprsJSON ( qw422016 , q )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
qt422016 . ReleaseWriter ( qw422016 )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
}
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
func expandWithExprsJSON ( q string ) string {
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
qb422016 := qt422016 . AcquireByteBuffer ( )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
writeexpandWithExprsJSON ( qb422016 , q )
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
2022-12-15 01:01:33 +01:00
qs422016 := string ( qb422016 . B )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
2022-12-15 01:01:33 +01:00
qt422016 . ReleaseByteBuffer ( qb422016 )
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
2022-12-15 01:01:33 +01:00
return qs422016
2023-04-25 10:40:01 +02:00
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
2022-12-15 01:01:33 +01:00
}