Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions src/hdr_time.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

#include <math.h>
#include <limits.h>

#include <hdr/hdr_time.h>

Expand Down Expand Up @@ -89,9 +90,25 @@ double hdr_timespec_as_double(const hdr_timespec* t)

void hdr_timespec_from_double(hdr_timespec* t, double value)
{
int seconds = (int) value;
int milliseconds = (int) round((value - seconds) * 1000);
/* Bound by the destination: time_t on POSIX, long on Windows/Cygwin. */
const double limit = ldexp(1.0, (int) (sizeof(t->tv_sec) * CHAR_BIT) - 1);
double seconds = trunc(value);
int milliseconds;

t->tv_sec = seconds;
/* converting a non-finite or out-of-range double to an integer is UB */
if (!isfinite(value) || seconds >= limit || seconds < -limit)
{
t->tv_sec = 0;
t->tv_nsec = 0;
Comment on lines +101 to +102

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're "silently" mapping invalid or out of range input values to zero (tbh, I'm not totally aware of the impact)
Maybe we could return an error instead and propagate it above (?)
The down-side is that the function returns void, so we'd need an API change, or a separate checked conversion function

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question — I dug into this rather than hand-wave it. Recommendation: merge #154 as-is; keep the silent clamp, and add a checked variant only later as a separate, additive follow-up if a caller actually needs it.

Reasoning:

  1. Signature/ABI. hdr_timespec_from_double is a published void symbol in hdr/hdr_time.h. Changing it to return int is a source + ABI break that would force a SOVERSION bump — disproportionate for a UBSan fix and against the one-PR-one-purpose norm here.
  2. No caller can consume an error. The only in-tree caller is scan_start_time (src/hdr_histogram_log.c), which is itself void, and its parent header-scan chain propagates no per-field error. An absent StartTime already degrades to 0 via hdr_log_reader_init. So invalid input mapping to 0/0 lands exactly on the pre-existing "unknown start time" sentinel — consistent behavior, not a new silent failure mode. Even if the function returned an error today, every caller would discard it.
  3. The PR's job is to remove UB. 0/0 is defined behavior; the out-of-range double→int cast was UB. Replacing UB with a defined sentinel is the fix. Bolting on error-return machinery is a separate design change (same reason the tv_nsec == 1e9 carry and negative-fraction normalization were split into fix: hdr_timespec_from_double could emit a malformed hdr_timespec (tv_nsec == 1e9, or negative) #156).

If a checked path is wanted later, the minimal non-breaking shape is additive and belongs in its own PR, not here:

/* returns 0 on success, -EINVAL on non-finite, -ERANGE on out-of-tv_sec-range input */
int hdr_timespec_from_double_checked(hdr_timespec* t, double value);

with the existing void function kept as a thin wrapper that calls it and zeroes on failure — so no caller and no ABI break, and encode/decode callers that care could then propagate the error.

(Adversarial re-review of the current head was 7/7 green through all correctness lenses; this was the only open thread.)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sound good!!
Approving

return;
}

milliseconds = (int) round((value - seconds) * 1000);

#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
t->tv_sec = (long) seconds;
#else
t->tv_sec = (time_t) seconds;
#endif
t->tv_nsec = milliseconds * 1000000;
}
2 changes: 2 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ foreach(V 2.0.1.logV0 2.0.6.logV1 2.0.7S.logV2 2.0.7S.logV3)
configure_file(jHiccup-${V}.hlog jHiccup-${V}.hlog COPYONLY)
endforeach()

configure_file(regression-log-start-time-overflow.hlog regression-log-start-time-overflow.hlog COPYONLY)

foreach(V test_tagged_invalid_histogram.txt test_tagged_invalid_tag_key.txt test_tagged_invalid_timestamp.txt test_tagged_missing_histogram.txt test_overflow_timestamp_seconds.txt test_overflow_timestamp_nanos.txt test_timestamp_seconds_2pow31.txt)
configure_file(${V} ${V} COPYONLY)
endforeach()
25 changes: 25 additions & 0 deletions test/hdr_histogram_log_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,30 @@ static int parse_line_from_file(const char* filename)
return result;
}

/* A StartTime beyond int range must not be an out-of-range cast (UBSan). */
static char* handle_wide_start_time(void)
{
struct hdr_log_reader reader;
int rc;

FILE* f = fopen("regression-log-start-time-overflow.hlog", "r");
mu_assert("Can not open wide start time log", f != NULL);

hdr_log_reader_init(&reader);
rc = hdr_log_read_header(&reader, f);
fclose(f);

mu_assert("Failed to read header", compare_int(0, rc));
if (sizeof(reader.start_timestamp.tv_sec) >= 8)
{
mu_assert(
"Start time wrong",
compare_int64(INT64_C(1403476110183), (int64_t) reader.start_timestamp.tv_sec));
}

return 0;
}

static char* handle_invalid_log_lines(void)
{
mu_assert("Should have invalid histogram", -EINVAL == parse_line_from_file("test_tagged_invalid_histogram.txt"));
Expand Down Expand Up @@ -1159,6 +1183,7 @@ static struct mu_result all_tests(void)
mu_run_test(decode_v1_log);
mu_run_test(decode_v0_log);
mu_run_test(handle_invalid_log_lines);
mu_run_test(handle_wide_start_time);
mu_run_test(handle_sub_nanosecond_timestamp);
mu_run_test(handle_timestamp_at_long_boundary);

Expand Down
48 changes: 48 additions & 0 deletions test/hdr_histogram_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
#include <math.h>

#include <stdio.h>
#include <math.h>
#include <hdr/hdr_histogram.h>
#include <hdr/hdr_interval_recorder.h>
#include <hdr/hdr_time.h>

#include "minunit.h"
#include "hdr_test_util.h"
Expand Down Expand Up @@ -159,6 +161,51 @@ static char* test_invalid_init(void)
return 0;
}

static char* test_timespec_from_double(void)
{
hdr_timespec t;

hdr_timespec_from_double(&t, 1403476110.183);
mu_assert("seconds wrong", compare_int64(INT64_C(1403476110), (int64_t) t.tv_sec));
mu_assert("nanoseconds wrong", compare_int64(INT64_C(183000000), (int64_t) t.tv_nsec));

hdr_timespec_from_double(&t, -2.0);
mu_assert("negative seconds wrong", compare_int64(INT64_C(-2), (int64_t) t.tv_sec));
mu_assert("negative nanoseconds wrong", compare_int64(INT64_C(0), (int64_t) t.tv_nsec));

/* Exceeds int but fits a 64-bit destination; reachable from a log header. */
hdr_timespec_from_double(&t, 1403476110183.0);
if (sizeof(t.tv_sec) >= 8)
{
mu_assert("wide seconds wrong", compare_int64(INT64_C(1403476110183), (int64_t) t.tv_sec));
}
else
{
mu_assert("unrepresentable seconds should be zeroed", compare_int64(INT64_C(0), (int64_t) t.tv_sec));
}
mu_assert("wide nanoseconds wrong", compare_int64(INT64_C(0), (int64_t) t.tv_nsec));

/* Values tv_sec cannot hold, and non-finite values, must not be converted. */
hdr_timespec_from_double(&t, 1e300);
mu_assert("huge seconds should be zeroed", compare_int64(INT64_C(0), (int64_t) t.tv_sec));
mu_assert("huge nanoseconds should be zeroed", compare_int64(INT64_C(0), (int64_t) t.tv_nsec));

hdr_timespec_from_double(&t, -1e300);
mu_assert("huge negative seconds should be zeroed", compare_int64(INT64_C(0), (int64_t) t.tv_sec));

hdr_timespec_from_double(&t, INFINITY);
mu_assert("inf seconds should be zeroed", compare_int64(INT64_C(0), (int64_t) t.tv_sec));

hdr_timespec_from_double(&t, -INFINITY);
mu_assert("-inf seconds should be zeroed", compare_int64(INT64_C(0), (int64_t) t.tv_sec));

hdr_timespec_from_double(&t, NAN);
mu_assert("nan seconds should be zeroed", compare_int64(INT64_C(0), (int64_t) t.tv_sec));
mu_assert("nan nanoseconds should be zeroed", compare_int64(INT64_C(0), (int64_t) t.tv_nsec));

return 0;
}

static char* test_bucket_config_shift_overflow(void)
{
struct hdr_histogram* h = NULL;
Expand Down Expand Up @@ -767,6 +814,7 @@ static struct mu_result all_tests(void)
{
mu_run_test(test_create);
mu_run_test(test_invalid_init);
mu_run_test(test_timespec_from_double);
mu_run_test(test_bucket_config_shift_overflow);
mu_run_test(test_bucket_config_reject_defines_cfg);
mu_run_test(test_create_with_large_values);
Expand Down
66 changes: 66 additions & 0 deletions test/regression-log-start-time-overflow.hlog
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#[Logged with jHiccup version 2.0.7-SNAPSHOT]
#[Histogram log format version 1.2]
#[StartTime: 1403476110183.0 (seconds since epoch), Mon Jun 23 10:28:30 NZST 2014]
"StartTimestamp","Interval_Length","Interval_Max","Interval_Compressed_Histogram"
0.127,1.007,2.769,HISTFAAAAEV42pNpmSzMwMCgyAABTBDKT4GBgdnNYMcCBvsPEBEJISEuATEZMQ4uASkhIR4nrxg9v2lMaxhvMekILGZkKmcCAEf2CsI=
1.134,0.999,0.442,HISTFAAAAEJ42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPEBEWLj45FTExAT4pBSEBKa6UkAgBi1uM7xjfMMlwMDABAC0CCjM=
2.133,1.001,0.426,HISTFAAAAD942pNpmSzMwMAgwwABTBDKT4GBgdnNYMcCBvsPEBE+Ph4OLgk5OSkeIS4+LgEeswIDo1+MbmdYNASYAA51CSo=
3.134,1.001,0.426,HISTFAAAAD942pNpmSzMwMAgwwABTBDKT4GBgdnNYMcCBvsPEBExPiEpITEFGTkRKSEeOR6FkCg1hTeMXvNYlHhYABQ5CTo=
4.135,0.997,0.426,HISTFAAAAD942pNpmSzMwMAgwwABTBDKT4GBgdnNYMcCBvsPEBE2PiERBREpBREhER4+Hj4uvQAdrTlMBldYDDhYAAugCKk=
5.132,1.002,0.426,HISTFAAAAEF42pNpmSzMwMAgywABTBDKT4GBgdnNYMcCBvsPEBEWPhElOR4pARUpKTkpGQkxq2mMegZnGI0+MZuIcAEAHo8Jvw==
6.134,0.999,0.442,HISTFAAAAEF42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPEBEWIS4FITEhDiEJERE+GT6ZkhZGLbl7jEqrWHREmFgAIbAJMw==
7.133,0.999,0.459,HISTFAAAAEJ42pNpmSzMwMCgwAABTBDKD8hndjPYsYDB/gNEhEtMQEBBTk5MQERCRkBEQEWlh9FJbg9jE+MS5ig1LhYmADkkCcE=
8.132,1.000,0.459,HISTFAAAAEB42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPEBEWIREgEOIQEuGT4xHg41Oo0pIqu8LYwVImwMfGBAAfkgkw
9.132,1.751,1551.892,HISTFAAAAJZ42pNpmSzMwMB0nQECmCCUnwIDA7ObwY4FDPYfYDJMXFxsbGwMbBwszDwsDDxsHFw6RWJMLJMZmcqBMJrJmskSiA2ZZJmkgRBCgmheIORGI1H5rEzMQAyDzFhY2EWRWUwMWCBxQtQQhAIWJiyAaEHyFbKwsLHAADYWAWmiFeKS5gACLsIEzdQICAgBIQShEfhFABXDF+M=
10.883,0.250,0.426,HISTFAAAAD142pNpmSzMwMAgxQABTBDKT4GBgdnNYMcCBvsPEBEeFi4mPg4WLhY2BjY2FhYOBSkpASEtoRA+NgDkCQZR
11.133,1.003,0.524,HISTFAAAAER42pNpmSzMwMCgyAABTBDKT4GBgdnNYMcCBvsPUBk2HgkZKREpEQUeGSEBAQ6xSYxhCnp7GJ02sWgJsbCwMgEAO0AJSQ==
12.136,0.997,0.459,HISTFAAAAEB42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPUBk2AT4eCQURHgkuEREOHjERlSQhhWuMSV9Y7ERYWAAa4gko
13.133,0.998,0.459,HISTFAAAAD942pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPMBkRIR4RMRk5KQE+PgEhMRmzEjWZJ4whW1hMBNiYAB42CTA=
14.131,1.000,0.492,HISTFAAAAEN42pNpmSzMwMCgyAABTBDKT4GBgdnNYMcCBvsPUBkWFhE5GT4FKQkRCR4ZCREpqwmMBhpHGG16WHx42JgYmAA6swk+
15.131,1.001,0.442,HISTFAAAAD542pNpmSzMwMAgywABTBDKT4GBgdnNYMcCBvsPMBkuMTEFHgklFRkRATkJERGdKgudfYwRTSwGalwAF2IJOw==
16.132,1.001,0.524,HISTFAAAAEZ42pNpmSzMwMCgxAABTBDKT4GBgdnNYMcCBvsPEBE2IQEFCQkpGREpHj4hKS6NU4z7GDMkuBoYDSYw2wiwMLEyAQBQ3wne
17.133,0.998,0.459,HISTFAAAAEB42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPUBk2DjElIR4RHiExKQE5IT61iCodtXWMdn0sKVJMTAAekAk0
18.131,1.000,0.459,HISTFAAAAEF42pNpmSzMwMAgzwABTBDKT4GBgdnNYMcCBvsPUBkWISERJSUJESklHhEJEREhqwZGLakPjDZdLBYCHCwAKOkJPg==
19.131,1.000,0.475,HISTFAAAAEF42pNpmSzMwMAgzwABTBDKT4GBgdnNYMcCBvsPUAk2HjkJBSk+Pi4BMT4xIQE9pxIluTOMPhtYbITY2JgAKLoJOQ==
20.131,1.004,0.475,HISTFAAAAEF42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPEBFmPhEJOSEhDi4+ETEeASEhswIVi1+MFjtYvCRYGJgAIP8JNw==
21.135,0.999,0.492,HISTFAAAAEB42pNpmSzMwMCgwAABTBDKD8hndjPYsYDB/gNMhk1AjINDRECAj4+Hi49LKS5CS2EGo1kXa4ANExMDEwAmOQil
22.134,0.997,0.459,HISTFAAAAEB42pNpmSzMwMAgywABTBDKT4GBgdnNYMcCBvsPEBFmHhE+MRExCTEZAS4RMQERvRI1hSuMTidY3KQ4mAAXhgks
23.131,1.004,0.508,HISTFAAAAEB42pNpmSzMwMCgwAABTBDKD8hndjPYsYDB/gNMhotHSEBASEyMg09MQUSIT6tKS2YKY8gfFj8tJmYmJgAsowkz
24.135,0.998,0.492,HISTFAAAAEJ42pNpmSzMwMAgzwABTBDKT4GBgdnNYMcCBvsPEBEBLjkhETEpET4BISEhCR6FsqAQFY1jjBoTWPQEOJiZAC2aCUY=
25.133,1.002,0.459,HISTFAAAAEB42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPUBkuHh4BITEpMSEpLiE5AS6FoAgdpQuMJk9YzMRYmAAdngk2
26.135,0.998,0.508,HISTFAAAAER42pNpmSzMwMCgyAABTBDKT4GBgdnNYMcCBvsPUAkOKSEJKTUJOT4+IQkeIT69LYwVCnIbGI0eMZtJsTAxMwEAQvkJyg==
27.133,0.998,0.442,HISTFAAAAEN42pNpmSzMwMAgzwABTBDKT4GBgdnNYMcCBvsPEBE2CQUZFTkZOSURKQkRMT6NKYwhbYxaOocY/a4xSUmwAQA4pQpb
28.131,1.002,0.426,HISTFAAAAD942pNpmSzMwMAgwwABTBDKT4GBgdnNYMcCBvsPEBGtFDcHIy0jDQUdPjENFZUzjNNYHCT4uBQkzJiYADIGCcY=
29.133,1.460,968.884,HISTFAAAAJZ42pNpmSzMwMDUwgABTBDKT4GBgdnNYMcCBvsPEBE5AwMDJSUFISk2ETYuAS6PQ0xSXCzsTEw7GZnKgdCTyZLJGog1maSZZIFYGkpLMnEz8QIhOolgcTKxAiEzmGRFYxMShbEYUCAalzRBsjSjARYmTIBNjDKFSIIsIMDGAgPYWJRJE1DIxQEEaAQHF2GCNDVsAE2dFJE=
30.593,0.541,0.459,HISTFAAAAEB42pNpmSzMwMAgywABTBDKT4GBgdnNYMcCBvsPEBEFCxUNBRkFMTE+Pj4ZHgGHFYwGIkJcMiIpbEwMTAAdQQhJ
31.134,0.997,0.737,HISTFAAAAER42pNpmSzMwMCgyAABTBDKT4GBgdnNYMcCBvsPEJGAHsYexqKaIAcPPRMVKTEhoR6mJUxqfBx8LFwCTOxM0kwAfR8KqA==
32.131,1.002,0.508,HISTFAAAAEJ42pNpmSzMwMCgwAABTBDKD8hndjPYsYDB/gNEJKCDMcHJw8jOTUfNSEZGQuUb4x9GHxkJDg2hMA4WViYmAHWrC2k=
33.133,1.000,0.426,HISTFAAAAD942pNpmSzMwMAgwwABTBDKT4GBgdnNYMcCBvsPEBGXGK8QHS09PRM9BRMxBa55jBOY03REhByE3DhYADicCkc=
34.133,0.998,0.442,HISTFAAAAEB42pNpmSzMwMAgywABTBDKT4GBgdnNYMcCBvsPEBE1NzsfJwMVEw0pFS0hOZm4FqYKPy2FAoUJjFIsTAA/mQql
35.131,1.000,0.459,HISTFAAAAEN42pNpmSzMwMAgzwABTBDKT4GBgdnNYMcCBvsPEBERMy0jPTk5LRUFJQk1GamYdUzHGO0UxIrUljBKsbEwAQBKXgqU
36.131,1.001,0.557,HISTFAAAAEd42pNpmSzMwMCgygABTBDKT4GBgdnNYMcCBvsPEBExJzcNMyU5PRUpLSkJKYWwHqYWRjslkTKNC4wKHGwMTExArUwAi/IKnA==
37.132,1.002,0.442,HISTFAAAAEJ42pNpmSzMwMAgzwABTBDKT4GBgdnNYMcCBvsPEBEFLRsVPQkTKTkhPT4ZBTm3V4yTGD20pFoYtZqYxESYAEjICok=
38.134,1.000,0.803,HISTFAAAAEJ42pNpmSzMwMCgwAABTBDKD8hndjPYsYDB/gNERM7Hwk3LRslMSkZMQExDLGQL0yTGIC2pKJ1VjCwcTJpMAFufCso=
39.134,0.997,0.492,HISTFAAAAEN42pNpmSzMwMCgyAABTBDKT4GBgdnNYMcCBvsPEBE5Oz8DPRsFORM5FQkNKaGCA8wtjCoSfBYSTYxCLEBtTABiWgor
40.131,1.000,0.442,HISTFAAAAEF42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPEBExJQUNFTElFRUZBRUZDTGfJqYKHzmhHka5ZUwSQmwANK0J+g==
41.131,1.002,0.475,HISTFAAAAEV42pNpmSzMwMCgyAABTBDKT4GBgdnNYMcCBvsPEBE2Hj45PiEFGSU5EQkpKREJuVmMLYwaWk8YQyYwa3CxMTABAEOgCdQ=
42.133,1.000,0.459,HISTFAAAAD942pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPMBk+Lg4+ER4hMT4hIT4lLh69OAOZZ4wOr1hCpFiYABjUCSY=
43.133,1.002,0.442,HISTFAAAAD942pNpmSzMwMAgwwABTBDKT4GBgdnNYMcCBvsPEBFmLgEJMTERHjEuCRERBSERoww5rRuMendYPFRYAA3tCTM=
44.135,0.998,0.590,HISTFAAAAEJ42pNpmSzMwMAgzwABTBDKT4GBgdnNYMcCBvsPUBk+FT0lJTktJSUjOTE1OQGpmnOMdnorGF3WMemxCTIBAEAhCnU=
45.133,0.998,0.442,HISTFAAAAEJ42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPEBEWMS0DIyMFOSsNPTEFMSGNA4x+LxidfOp0VjBKcLAAAECLCv4=
46.131,1.004,0.442,HISTFAAAAEF42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPEBEuMS0VEyMlLSkzGQUJOSkJj6RnjE56WxjNWpik2JgAO34KfQ==
47.135,0.996,0.475,HISTFAAAAEF42pNpmSzMwMCgwAABTBDKD8hndjPYsYDB/gNUgk2GR0ZOQkSAR4aLS0KKTyNtDqOWxjVGu2fMGlJMTEwANsIJvA==
48.131,1.950,1803.551,HISTFAAAAKF42pNpmSzMwMD0mQECmCCUnwIDA7ObwY4FDPYfICKsTExMLCysLCxsbEwMTAIsDHIsWTwsbNsZmcqZKpncmayZLIFYnUmWSRoMIbQkEy8TNxQjkwgWJxMrGDJDaews/KIMKBCNSytBZCYqYGHCBNjEiBckoJAFBNhYYADBwipIhkIC0lwcQIBGcHARJqigBkwKCQgICSAIFA75IlwAeB8ZpQ==
50.081,0.050,0.393,HISTFAAAADl42pNpmSzMwMAgxgABTBDKT4GBgdnNYMcCBvsPEBE2BiYWNiYWZiYGJiZmJg4OLiYuFiYWAMWGBSM=
50.131,1.001,0.442,HISTFAAAAEF42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPEBE2Lj4VAQkuJT45KTkOKSExI68eRgeDvB2MfcxxckwAJD8JyA==
51.132,0.999,0.459,HISTFAAAAEB42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPUBk2NgUFGSkNAQEeJSkuKSmxhAojhZADjKuYiyS4WAAlWgm/
52.131,1.002,0.557,HISTFAAAAER42pNpmSzMwMCgxAABTBDKT4GBgdnNYMcCBvsPUBkWPjEFGSMZKQMJJSEhPgkJiyodjZIHjB+YSvh4mBiYWJkAVc8KVw==
53.133,0.998,0.442,HISTFAAAAEJ42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPEBE2HjklJR0VPSUDHTUxJSkJs02MuxhtrLxKHjH6cbEAADjeCuw=
54.131,1.003,0.442,HISTFAAAAEB42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPMBkNPzMLIw0NLQ0pFTERCTGLT4wpQSVbGFcwynExAQA/uwsC
55.134,0.997,0.426,HISTFAAAAD942pNpmSzMwMAgywABTBDKT4GBgdnNYMcCBvsPUBkWFTUjCy01BQ0VFRUJGSkJjRamiqA5jHmXGIV4ACoyCmo=
56.131,1.000,0.459,HISTFAAAAEF42pNpmSzMwMCgwAABTBDKD8hndjPYsYDB/gNUhk1FzsrAQElFQ0xCQkJOTEDnE6ObxwrGDsYuJjUODiYASN8KbA==
57.131,1.000,0.459,HISTFAAAAEF42pNpmSzMwMAgzwABTBDKT4GBgdnNYMcCBvsPMBk5FT0JAzUNKTklKQ0FMaGUJ4wJFjcYk+4wqnAwMAEAQooK6Q==
58.131,1.002,0.442,HISTFAAAAEB42pNpmSzMwMAgywABTBDKT4GBgdnNYMcCBvsPEBEuCRMNJwMlIzUtLR0ZMREZv6IHjFYGdUXLGE14WAA4OwsG
59.133,0.998,0.442,HISTFAAAAEB42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPMBklExUdIwcdFRUlOTMZPhWXB4wBTssYsy4xKnGwAQA8bAry
60.131,1.000,0.524,HISTFAAAAEJ42pNpmSzMwMAgxwABTBDKT4GBgdnNYMcCBvsPEBFmIRcjPR0bFR0lDSk5KQkZpXlMXkF5qxh3MMqIcDIBADy8CoE=
61.131,1.000,26.083,HISTFAAAAF542pNpmSzMwMAQyAABTBDKT4GBgdnNYMcCBvsPMBkFHSMrCzEZLSUFCSkJOTmTf4xRQW2MYT8Y5diYdjIylTNVMrkzWTJZA7EmkzQYykJpSSZeJm4ghpAQFgATDg85
Loading