2016-03-07 14:46:23 +00:00
|
|
|
package agent
|
|
|
|
|
|
|
|
import (
|
2016-07-25 12:09:49 +00:00
|
|
|
"bytes"
|
2016-03-07 14:46:23 +00:00
|
|
|
"fmt"
|
2016-07-25 12:09:49 +00:00
|
|
|
"log"
|
|
|
|
"os"
|
2016-03-07 14:46:23 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2016-12-23 15:18:27 +00:00
|
|
|
"github.com/influxdata/telegraf/plugins"
|
2016-11-22 12:51:57 +00:00
|
|
|
"github.com/influxdata/telegraf/metric"
|
2016-03-07 14:46:23 +00:00
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
2016-07-25 12:09:49 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2016-03-07 14:46:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestAdd(t *testing.T) {
|
|
|
|
now := time.Now()
|
2016-12-23 15:18:27 +00:00
|
|
|
metrics := make(chan plugins.Metric, 10)
|
2016-09-08 14:22:10 +00:00
|
|
|
defer close(metrics)
|
|
|
|
a := NewAccumulator(&TestMetricMaker{}, metrics)
|
2016-03-07 14:46:23 +00:00
|
|
|
|
2016-08-31 11:15:14 +00:00
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{})
|
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"})
|
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"}, now)
|
2016-03-07 14:46:23 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
testm := <-metrics
|
2016-03-07 14:46:23 +00:00
|
|
|
actual := testm.String()
|
|
|
|
assert.Contains(t, actual, "acctest value=101")
|
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
testm = <-metrics
|
2016-03-07 14:46:23 +00:00
|
|
|
actual = testm.String()
|
|
|
|
assert.Contains(t, actual, "acctest,acc=test value=101")
|
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
testm = <-metrics
|
2016-03-07 14:46:23 +00:00
|
|
|
actual = testm.String()
|
|
|
|
assert.Equal(t,
|
2016-11-28 18:19:35 +00:00
|
|
|
fmt.Sprintf("acctest,acc=test value=101 %d\n", now.UnixNano()),
|
2016-03-07 14:46:23 +00:00
|
|
|
actual)
|
|
|
|
}
|
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
func TestAddFields(t *testing.T) {
|
2016-08-31 16:27:37 +00:00
|
|
|
now := time.Now()
|
2016-12-23 15:18:27 +00:00
|
|
|
metrics := make(chan plugins.Metric, 10)
|
2016-09-08 14:22:10 +00:00
|
|
|
defer close(metrics)
|
|
|
|
a := NewAccumulator(&TestMetricMaker{}, metrics)
|
2016-08-31 16:27:37 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
fields := map[string]interface{}{
|
|
|
|
"usage": float64(99),
|
|
|
|
}
|
|
|
|
a.AddFields("acctest", fields, map[string]string{})
|
|
|
|
a.AddGauge("acctest", fields, map[string]string{"acc": "test"})
|
|
|
|
a.AddCounter("acctest", fields, map[string]string{"acc": "test"}, now)
|
2016-08-31 16:27:37 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
testm := <-metrics
|
2016-08-31 16:27:37 +00:00
|
|
|
actual := testm.String()
|
2016-09-08 14:22:10 +00:00
|
|
|
assert.Contains(t, actual, "acctest usage=99")
|
2016-08-31 16:27:37 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
testm = <-metrics
|
2016-08-31 16:27:37 +00:00
|
|
|
actual = testm.String()
|
2016-09-08 14:22:10 +00:00
|
|
|
assert.Contains(t, actual, "acctest,acc=test usage=99")
|
2016-08-31 16:27:37 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
testm = <-metrics
|
2016-08-31 16:27:37 +00:00
|
|
|
actual = testm.String()
|
|
|
|
assert.Equal(t,
|
2016-11-28 18:19:35 +00:00
|
|
|
fmt.Sprintf("acctest,acc=test usage=99 %d\n", now.UnixNano()),
|
2016-08-31 16:27:37 +00:00
|
|
|
actual)
|
|
|
|
}
|
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
func TestAccAddError(t *testing.T) {
|
|
|
|
errBuf := bytes.NewBuffer(nil)
|
|
|
|
log.SetOutput(errBuf)
|
|
|
|
defer log.SetOutput(os.Stderr)
|
2016-08-31 16:27:37 +00:00
|
|
|
|
2016-12-23 15:18:27 +00:00
|
|
|
metrics := make(chan plugins.Metric, 10)
|
2016-09-08 14:22:10 +00:00
|
|
|
defer close(metrics)
|
|
|
|
a := NewAccumulator(&TestMetricMaker{}, metrics)
|
2016-08-31 16:27:37 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
a.AddError(fmt.Errorf("foo"))
|
|
|
|
a.AddError(fmt.Errorf("bar"))
|
|
|
|
a.AddError(fmt.Errorf("baz"))
|
2016-08-31 16:27:37 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
errs := bytes.Split(errBuf.Bytes(), []byte{'\n'})
|
2016-11-07 08:34:46 +00:00
|
|
|
assert.EqualValues(t, int64(3), NErrors.Get())
|
2016-09-08 14:22:10 +00:00
|
|
|
require.Len(t, errs, 4) // 4 because of trailing newline
|
|
|
|
assert.Contains(t, string(errs[0]), "TestPlugin")
|
|
|
|
assert.Contains(t, string(errs[0]), "foo")
|
|
|
|
assert.Contains(t, string(errs[1]), "TestPlugin")
|
|
|
|
assert.Contains(t, string(errs[1]), "bar")
|
|
|
|
assert.Contains(t, string(errs[2]), "TestPlugin")
|
|
|
|
assert.Contains(t, string(errs[2]), "baz")
|
2016-08-31 16:27:37 +00:00
|
|
|
}
|
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
func TestAddNoIntervalWithPrecision(t *testing.T) {
|
2016-06-13 14:21:11 +00:00
|
|
|
now := time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC)
|
2016-12-23 15:18:27 +00:00
|
|
|
metrics := make(chan plugins.Metric, 10)
|
2016-09-08 14:22:10 +00:00
|
|
|
defer close(metrics)
|
|
|
|
a := NewAccumulator(&TestMetricMaker{}, metrics)
|
2016-06-13 14:21:11 +00:00
|
|
|
a.SetPrecision(0, time.Second)
|
2016-09-08 14:22:10 +00:00
|
|
|
|
2016-08-31 11:15:14 +00:00
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{})
|
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"})
|
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"}, now)
|
2016-06-13 14:21:11 +00:00
|
|
|
|
|
|
|
testm := <-a.metrics
|
|
|
|
actual := testm.String()
|
|
|
|
assert.Contains(t, actual, "acctest value=101")
|
|
|
|
|
|
|
|
testm = <-a.metrics
|
|
|
|
actual = testm.String()
|
|
|
|
assert.Contains(t, actual, "acctest,acc=test value=101")
|
|
|
|
|
|
|
|
testm = <-a.metrics
|
|
|
|
actual = testm.String()
|
|
|
|
assert.Equal(t,
|
2016-11-28 18:19:35 +00:00
|
|
|
fmt.Sprintf("acctest,acc=test value=101 %d\n", int64(1139572800000000000)),
|
2016-06-13 14:21:11 +00:00
|
|
|
actual)
|
|
|
|
}
|
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
func TestAddDisablePrecision(t *testing.T) {
|
2016-06-13 14:21:11 +00:00
|
|
|
now := time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC)
|
2016-12-23 15:18:27 +00:00
|
|
|
metrics := make(chan plugins.Metric, 10)
|
2016-09-08 14:22:10 +00:00
|
|
|
defer close(metrics)
|
|
|
|
a := NewAccumulator(&TestMetricMaker{}, metrics)
|
2016-06-13 14:21:11 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
a.SetPrecision(time.Nanosecond, 0)
|
2016-08-31 11:15:14 +00:00
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{})
|
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"})
|
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"}, now)
|
2016-06-13 14:21:11 +00:00
|
|
|
|
|
|
|
testm := <-a.metrics
|
|
|
|
actual := testm.String()
|
|
|
|
assert.Contains(t, actual, "acctest value=101")
|
|
|
|
|
|
|
|
testm = <-a.metrics
|
|
|
|
actual = testm.String()
|
|
|
|
assert.Contains(t, actual, "acctest,acc=test value=101")
|
|
|
|
|
|
|
|
testm = <-a.metrics
|
|
|
|
actual = testm.String()
|
|
|
|
assert.Equal(t,
|
2016-11-28 18:19:35 +00:00
|
|
|
fmt.Sprintf("acctest,acc=test value=101 %d\n", int64(1139572800082912748)),
|
2016-06-13 14:21:11 +00:00
|
|
|
actual)
|
|
|
|
}
|
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
func TestAddNoPrecisionWithInterval(t *testing.T) {
|
2016-06-13 14:21:11 +00:00
|
|
|
now := time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC)
|
2016-12-23 15:18:27 +00:00
|
|
|
metrics := make(chan plugins.Metric, 10)
|
2016-09-08 14:22:10 +00:00
|
|
|
defer close(metrics)
|
|
|
|
a := NewAccumulator(&TestMetricMaker{}, metrics)
|
2016-06-13 14:21:11 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
a.SetPrecision(0, time.Second)
|
2016-08-31 11:15:14 +00:00
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{})
|
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"})
|
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"}, now)
|
2016-06-13 14:21:11 +00:00
|
|
|
|
|
|
|
testm := <-a.metrics
|
|
|
|
actual := testm.String()
|
|
|
|
assert.Contains(t, actual, "acctest value=101")
|
|
|
|
|
|
|
|
testm = <-a.metrics
|
|
|
|
actual = testm.String()
|
|
|
|
assert.Contains(t, actual, "acctest,acc=test value=101")
|
|
|
|
|
|
|
|
testm = <-a.metrics
|
|
|
|
actual = testm.String()
|
|
|
|
assert.Equal(t,
|
2016-11-28 18:19:35 +00:00
|
|
|
fmt.Sprintf("acctest,acc=test value=101 %d\n", int64(1139572800000000000)),
|
2016-06-13 14:21:11 +00:00
|
|
|
actual)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDifferentPrecisions(t *testing.T) {
|
|
|
|
now := time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC)
|
2016-12-23 15:18:27 +00:00
|
|
|
metrics := make(chan plugins.Metric, 10)
|
2016-09-08 14:22:10 +00:00
|
|
|
defer close(metrics)
|
|
|
|
a := NewAccumulator(&TestMetricMaker{}, metrics)
|
2016-06-13 14:21:11 +00:00
|
|
|
|
|
|
|
a.SetPrecision(0, time.Second)
|
2016-08-31 11:15:14 +00:00
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"}, now)
|
2016-06-13 14:21:11 +00:00
|
|
|
testm := <-a.metrics
|
|
|
|
actual := testm.String()
|
|
|
|
assert.Equal(t,
|
2016-11-28 18:19:35 +00:00
|
|
|
fmt.Sprintf("acctest,acc=test value=101 %d\n", int64(1139572800000000000)),
|
2016-06-13 14:21:11 +00:00
|
|
|
actual)
|
|
|
|
|
|
|
|
a.SetPrecision(0, time.Millisecond)
|
2016-08-31 11:15:14 +00:00
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"}, now)
|
2016-06-13 14:21:11 +00:00
|
|
|
testm = <-a.metrics
|
|
|
|
actual = testm.String()
|
|
|
|
assert.Equal(t,
|
2016-11-28 18:19:35 +00:00
|
|
|
fmt.Sprintf("acctest,acc=test value=101 %d\n", int64(1139572800083000000)),
|
2016-06-13 14:21:11 +00:00
|
|
|
actual)
|
|
|
|
|
|
|
|
a.SetPrecision(0, time.Microsecond)
|
2016-08-31 11:15:14 +00:00
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"}, now)
|
2016-06-13 14:21:11 +00:00
|
|
|
testm = <-a.metrics
|
|
|
|
actual = testm.String()
|
|
|
|
assert.Equal(t,
|
2016-11-28 18:19:35 +00:00
|
|
|
fmt.Sprintf("acctest,acc=test value=101 %d\n", int64(1139572800082913000)),
|
2016-06-13 14:21:11 +00:00
|
|
|
actual)
|
|
|
|
|
|
|
|
a.SetPrecision(0, time.Nanosecond)
|
2016-08-31 11:15:14 +00:00
|
|
|
a.AddFields("acctest",
|
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"}, now)
|
2016-06-13 14:21:11 +00:00
|
|
|
testm = <-a.metrics
|
|
|
|
actual = testm.String()
|
|
|
|
assert.Equal(t,
|
2016-11-28 18:19:35 +00:00
|
|
|
fmt.Sprintf("acctest,acc=test value=101 %d\n", int64(1139572800082912748)),
|
2016-06-13 14:21:11 +00:00
|
|
|
actual)
|
|
|
|
}
|
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
func TestAddGauge(t *testing.T) {
|
2016-03-07 14:46:23 +00:00
|
|
|
now := time.Now()
|
2016-12-23 15:18:27 +00:00
|
|
|
metrics := make(chan plugins.Metric, 10)
|
2016-09-08 14:22:10 +00:00
|
|
|
defer close(metrics)
|
|
|
|
a := NewAccumulator(&TestMetricMaker{}, metrics)
|
2016-03-07 14:46:23 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
a.AddGauge("acctest",
|
2016-08-31 11:15:14 +00:00
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{})
|
2016-09-08 14:22:10 +00:00
|
|
|
a.AddGauge("acctest",
|
2016-08-31 11:15:14 +00:00
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"})
|
2016-09-08 14:22:10 +00:00
|
|
|
a.AddGauge("acctest",
|
2016-08-31 11:15:14 +00:00
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"}, now)
|
2016-03-07 14:46:23 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
testm := <-metrics
|
2016-03-07 14:46:23 +00:00
|
|
|
actual := testm.String()
|
2016-09-08 14:22:10 +00:00
|
|
|
assert.Contains(t, actual, "acctest value=101")
|
2016-12-23 15:18:27 +00:00
|
|
|
assert.Equal(t, testm.Type(), plugins.Gauge)
|
2016-03-07 14:46:23 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
testm = <-metrics
|
2016-03-07 14:46:23 +00:00
|
|
|
actual = testm.String()
|
2016-09-08 14:22:10 +00:00
|
|
|
assert.Contains(t, actual, "acctest,acc=test value=101")
|
2016-12-23 15:18:27 +00:00
|
|
|
assert.Equal(t, testm.Type(), plugins.Gauge)
|
2016-03-07 14:46:23 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
testm = <-metrics
|
2016-03-07 14:46:23 +00:00
|
|
|
actual = testm.String()
|
|
|
|
assert.Equal(t,
|
2016-11-28 18:19:35 +00:00
|
|
|
fmt.Sprintf("acctest,acc=test value=101 %d\n", now.UnixNano()),
|
2016-03-07 14:46:23 +00:00
|
|
|
actual)
|
2016-12-23 15:18:27 +00:00
|
|
|
assert.Equal(t, testm.Type(), plugins.Gauge)
|
2016-03-07 14:46:23 +00:00
|
|
|
}
|
2016-04-12 23:06:27 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
func TestAddCounter(t *testing.T) {
|
2016-04-12 23:06:27 +00:00
|
|
|
now := time.Now()
|
2016-12-23 15:18:27 +00:00
|
|
|
metrics := make(chan plugins.Metric, 10)
|
2016-09-08 14:22:10 +00:00
|
|
|
defer close(metrics)
|
|
|
|
a := NewAccumulator(&TestMetricMaker{}, metrics)
|
2016-04-12 23:06:27 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
a.AddCounter("acctest",
|
2016-08-31 11:15:14 +00:00
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{})
|
2016-09-08 14:22:10 +00:00
|
|
|
a.AddCounter("acctest",
|
2016-08-31 11:15:14 +00:00
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"})
|
2016-09-08 14:22:10 +00:00
|
|
|
a.AddCounter("acctest",
|
2016-08-31 11:15:14 +00:00
|
|
|
map[string]interface{}{"value": float64(101)},
|
|
|
|
map[string]string{"acc": "test"}, now)
|
2016-04-12 23:06:27 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
testm := <-metrics
|
2016-04-12 23:06:27 +00:00
|
|
|
actual := testm.String()
|
|
|
|
assert.Contains(t, actual, "acctest value=101")
|
2016-12-23 15:18:27 +00:00
|
|
|
assert.Equal(t, testm.Type(), plugins.Counter)
|
2016-04-12 23:06:27 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
testm = <-metrics
|
2016-04-12 23:06:27 +00:00
|
|
|
actual = testm.String()
|
2016-09-08 14:22:10 +00:00
|
|
|
assert.Contains(t, actual, "acctest,acc=test value=101")
|
2016-12-23 15:18:27 +00:00
|
|
|
assert.Equal(t, testm.Type(), plugins.Counter)
|
2016-04-12 23:06:27 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
testm = <-metrics
|
2016-04-12 23:06:27 +00:00
|
|
|
actual = testm.String()
|
|
|
|
assert.Equal(t,
|
2016-11-28 18:19:35 +00:00
|
|
|
fmt.Sprintf("acctest,acc=test value=101 %d\n", now.UnixNano()),
|
2016-04-12 23:06:27 +00:00
|
|
|
actual)
|
2016-12-23 15:18:27 +00:00
|
|
|
assert.Equal(t, testm.Type(), plugins.Counter)
|
2016-04-12 23:06:27 +00:00
|
|
|
}
|
2016-07-25 12:09:49 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
type TestMetricMaker struct {
|
|
|
|
}
|
2016-07-25 12:09:49 +00:00
|
|
|
|
2016-09-08 14:22:10 +00:00
|
|
|
func (tm *TestMetricMaker) Name() string {
|
|
|
|
return "TestPlugin"
|
|
|
|
}
|
|
|
|
func (tm *TestMetricMaker) MakeMetric(
|
|
|
|
measurement string,
|
|
|
|
fields map[string]interface{},
|
|
|
|
tags map[string]string,
|
2016-12-23 15:18:27 +00:00
|
|
|
mType plugins.ValueType,
|
2016-09-08 14:22:10 +00:00
|
|
|
t time.Time,
|
2016-12-23 15:18:27 +00:00
|
|
|
) plugins.Metric {
|
2016-09-08 14:22:10 +00:00
|
|
|
switch mType {
|
2016-12-23 15:18:27 +00:00
|
|
|
case plugins.Untyped:
|
2016-11-22 12:51:57 +00:00
|
|
|
if m, err := metric.New(measurement, tags, fields, t); err == nil {
|
2016-09-08 14:22:10 +00:00
|
|
|
return m
|
|
|
|
}
|
2016-12-23 15:18:27 +00:00
|
|
|
case plugins.Counter:
|
|
|
|
if m, err := metric.New(measurement, tags, fields, t, plugins.Counter); err == nil {
|
2016-09-08 14:22:10 +00:00
|
|
|
return m
|
|
|
|
}
|
2016-12-23 15:18:27 +00:00
|
|
|
case plugins.Gauge:
|
|
|
|
if m, err := metric.New(measurement, tags, fields, t, plugins.Gauge); err == nil {
|
2016-09-08 14:22:10 +00:00
|
|
|
return m
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
2016-07-25 12:09:49 +00:00
|
|
|
}
|