2020-01-25 11:05:38 +00:00
|
|
|
#include "common.h"
|
|
|
|
|
2020-01-28 04:59:04 +00:00
|
|
|
#include <algorithm>
|
2020-01-25 11:05:38 +00:00
|
|
|
#include <vector>
|
2020-02-16 19:17:06 +00:00
|
|
|
#include <iterator>
|
2020-01-25 11:05:38 +00:00
|
|
|
|
2020-01-28 05:13:11 +00:00
|
|
|
void htmlencode(std::string& data) {
|
2020-02-17 20:27:51 +00:00
|
|
|
std::string tmp;
|
|
|
|
tmp.reserve(data.size() + 20);
|
2020-01-28 05:13:11 +00:00
|
|
|
|
2020-02-17 20:27:51 +00:00
|
|
|
for (size_t i = 0; i != data.size(); i++) {
|
|
|
|
switch (data[i]) {
|
|
|
|
case '&':
|
2020-01-28 05:13:11 +00:00
|
|
|
tmp += "&";
|
|
|
|
break;
|
2020-02-17 20:27:51 +00:00
|
|
|
case '\"':
|
2020-01-28 05:13:11 +00:00
|
|
|
tmp += """;
|
|
|
|
break;
|
2020-02-17 20:27:51 +00:00
|
|
|
case '\'':
|
2020-01-28 05:13:11 +00:00
|
|
|
tmp += "'";
|
|
|
|
break;
|
2020-02-17 20:27:51 +00:00
|
|
|
case '<':
|
2020-01-28 05:13:11 +00:00
|
|
|
tmp += "<";
|
|
|
|
break;
|
2020-02-17 20:27:51 +00:00
|
|
|
case '>':
|
2020-01-28 05:13:11 +00:00
|
|
|
tmp += ">";
|
|
|
|
break;
|
2020-02-17 20:27:51 +00:00
|
|
|
default:
|
2020-01-28 05:13:11 +00:00
|
|
|
tmp += data[i];
|
|
|
|
break;
|
2020-02-17 20:27:51 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-28 05:13:11 +00:00
|
|
|
|
2020-02-17 20:27:51 +00:00
|
|
|
data.swap(tmp);
|
2020-01-28 05:13:11 +00:00
|
|
|
}
|
|
|
|
|
2020-05-02 22:19:59 +00:00
|
|
|
static std::string string_mangle(const std::string& str) {
|
|
|
|
std::string tmp;
|
|
|
|
tmp.reserve(str.size());
|
|
|
|
|
|
|
|
for (size_t i = 0; i != str.size(); i++) {
|
|
|
|
if (str[i] == ' ') continue;
|
|
|
|
if (std::isupper(str[i])) tmp.push_back(std::tolower(str[i]));
|
|
|
|
else tmp.push_back(str[i]);
|
|
|
|
}
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
2020-02-11 16:34:23 +00:00
|
|
|
void show_histogram(const Caches& cc, std::string Cache::*ptr, const std::string& caption, bool html, bool sort_by_val) {
|
2020-03-20 02:28:20 +00:00
|
|
|
int HIST_MAX = 20;
|
|
|
|
|
2020-01-25 11:05:38 +00:00
|
|
|
std::map<std::string, int> histogram;
|
|
|
|
std::vector<std::pair<std::string, int>> pairs;
|
|
|
|
|
2020-03-20 02:28:20 +00:00
|
|
|
if (!sort_by_val) HIST_MAX = 1000;
|
|
|
|
|
2020-01-25 11:20:41 +00:00
|
|
|
for (auto el : cc)
|
2020-01-25 11:05:38 +00:00
|
|
|
histogram[el.*ptr]++;
|
2020-02-16 19:17:06 +00:00
|
|
|
std::copy(histogram.begin(), histogram.end(), std::back_inserter(pairs));
|
|
|
|
|
2020-01-25 11:05:38 +00:00
|
|
|
if (sort_by_val)
|
|
|
|
sort(pairs.begin(), pairs.end(), [&](std::pair<std::string, int>& a, std::pair<std::string, int>& b) { return a.second > b.second; });
|
|
|
|
else
|
|
|
|
sort(pairs.begin(), pairs.end(), [&](std::pair<std::string, int>& a, std::pair<std::string, int>& b) { return a.first < b.first; });
|
|
|
|
|
|
|
|
if (html) {
|
|
|
|
int max;
|
|
|
|
if (sort_by_val)
|
|
|
|
max = pairs[0].second;
|
|
|
|
else
|
|
|
|
max = std::max_element(pairs.begin(), pairs.end(), [&](std::pair<std::string, int>& a, std::pair<std::string, int>& b) { return a.second < b.second; })->second;
|
|
|
|
int i = 0;
|
|
|
|
std::cout << "<h2>" << caption << "</h2>\n";
|
2020-05-02 22:19:59 +00:00
|
|
|
std::cout << "<div class=\"histogram " << string_mangle(caption) << "\">\n";
|
2020-01-25 11:05:38 +00:00
|
|
|
for (auto own : pairs) {
|
2020-01-28 05:13:11 +00:00
|
|
|
htmlencode(own.first);
|
2020-01-25 11:05:38 +00:00
|
|
|
if (own.first.empty()) own.first = "[unknown]";
|
|
|
|
|
|
|
|
if (i < HIST_MAX)
|
2020-02-29 12:38:46 +00:00
|
|
|
std::cout << "<div class=\"bar\" style=\"--percent: " << 100 * own.second / max << "%;\"><span class=\"text\">" << own.first << ": " << own.second << "</span></div>\n";
|
2020-01-25 11:05:38 +00:00
|
|
|
else if (i == HIST_MAX) {
|
2020-02-29 12:38:46 +00:00
|
|
|
std::cout << "</div>\n";
|
2020-05-02 22:19:59 +00:00
|
|
|
std::cout << "<details class=\"histogram_others " << string_mangle(caption) << "\">\n<summary>See more</summary>\n<p>\n";
|
2020-01-28 04:59:53 +00:00
|
|
|
std::cout << own.first << " (" << own.second << ")";
|
2020-01-25 11:05:38 +00:00
|
|
|
}
|
|
|
|
if (i > HIST_MAX)
|
2020-01-25 12:24:43 +00:00
|
|
|
std::cout << ", " << own.first << " (" << own.second << ")";
|
2020-01-25 11:05:38 +00:00
|
|
|
i++;
|
|
|
|
}
|
2020-03-19 16:40:43 +00:00
|
|
|
if (i <= HIST_MAX)
|
2020-02-29 12:38:46 +00:00
|
|
|
std::cout << "</div>\n";
|
2020-01-25 11:05:38 +00:00
|
|
|
else
|
2020-03-09 12:20:49 +00:00
|
|
|
std::cout << "</p></details>\n";
|
2020-01-25 11:05:38 +00:00
|
|
|
} else {
|
|
|
|
std::cout << caption << '\n';
|
|
|
|
for (auto own : pairs)
|
|
|
|
std::cout << own.first << ": " << own.second << '\n';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-25 11:39:55 +00:00
|
|
|
static bool same_day(const std::tm& a, const std::tm& b) {
|
2020-01-25 11:05:38 +00:00
|
|
|
return (a.tm_year == b.tm_year && a.tm_mon == b.tm_mon && a.tm_mday == b.tm_mday);
|
|
|
|
}
|
|
|
|
|
2020-01-25 11:39:55 +00:00
|
|
|
static void next_day(std::tm& a) {
|
2020-01-25 11:05:38 +00:00
|
|
|
a.tm_mday++;
|
|
|
|
mktime(&a);
|
|
|
|
}
|
|
|
|
|
|
|
|
int find_streak(const std::multimap<std::time_t, const Cache*>& cc, std::tm& start) {
|
|
|
|
int max_str = 0;
|
|
|
|
int cur_str = 0;
|
|
|
|
|
|
|
|
std::tm cur_tm;
|
|
|
|
cur_tm.tm_year = 0;
|
|
|
|
std::tm cur_start_tm = cur_tm;
|
|
|
|
start = cur_tm;
|
|
|
|
|
|
|
|
for (auto i : cc) {
|
|
|
|
if (same_day(cur_tm, *std::localtime(&i.first)))
|
|
|
|
continue;
|
|
|
|
next_day(cur_tm);
|
|
|
|
if (same_day(cur_tm, *std::localtime(&i.first))) {
|
|
|
|
cur_str++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (max_str < cur_str) {
|
|
|
|
max_str = cur_str;
|
|
|
|
start = cur_start_tm;
|
|
|
|
}
|
|
|
|
cur_str = 1;
|
2020-01-25 11:51:11 +00:00
|
|
|
cur_tm = cur_start_tm = *std::localtime(&i.first);
|
|
|
|
if (max_str == 0) {
|
|
|
|
max_str = 1;
|
|
|
|
start = cur_tm;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (max_str < cur_str) {
|
|
|
|
max_str = cur_str;
|
|
|
|
start = cur_start_tm;
|
2020-01-25 11:05:38 +00:00
|
|
|
}
|
2020-01-25 11:51:11 +00:00
|
|
|
|
2020-01-25 11:05:38 +00:00
|
|
|
return max_str;
|
|
|
|
}
|
2020-02-23 00:41:15 +00:00
|
|
|
|
|
|
|
long int get_num(char c, char* opt) {
|
|
|
|
try {
|
|
|
|
if (std::stoi(opt) > 0) {
|
|
|
|
return std::stoi(opt);
|
|
|
|
} else {
|
|
|
|
std::cout << "Option \"-" << c << "\" requires a valid number as an argument\n";
|
|
|
|
std::exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
std::cout << "Option \"-" << c << "\" requires a valid number as an argument\n";
|
|
|
|
std::exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|