diff --git a/package.json b/package.json index b67d38c7..5c5a779b 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "ts-jest": "^29.0.3", "ts-loader": "^9.4.1", "ts-node": "^10.9.1", + "tsconfig-paths": "^4.1.1", "tslib": "^2.4.0", "typescript": "4.8.4", "url-loader": "^4.1.1", diff --git a/script/data/user_chrome.json b/script/data/user_chrome.json deleted file mode 100644 index c3a4559f..00000000 --- a/script/data/user_chrome.json +++ /dev/null @@ -1,630 +0,0 @@ -{ - "2021-03-08": 4, - "2021-03-09": 5, - "2021-03-10": 6, - "2021-03-11": 6, - "2021-03-12": 9, - "2021-03-13": 10, - "2021-03-14": 11, - "2021-03-15": 12, - "2021-03-16": 13, - "2021-03-17": 15, - "2021-03-18": 16, - "2021-03-19": 16, - "2021-03-20": 17, - "2021-03-21": 17, - "2021-03-22": 15, - "2021-03-23": 15, - "2021-03-24": 15, - "2021-03-25": 15, - "2021-03-26": 13, - "2021-03-27": 15, - "2021-03-28": 15, - "2021-03-29": 16, - "2021-03-30": 16, - "2021-03-31": 15, - "2021-04-01": 15, - "2021-04-02": 15, - "2021-04-03": 15, - "2021-04-04": 15, - "2021-04-05": 16, - "2021-04-06": 17, - "2021-04-07": 17, - "2021-04-08": 18, - "2021-04-09": 19, - "2021-04-10": 19, - "2021-04-11": 19, - "2021-04-12": 21, - "2021-04-13": 21, - "2021-04-14": 23, - "2021-04-15": 23, - "2021-04-16": 23, - "2021-04-17": 22, - "2021-04-18": 23, - "2021-04-19": 22, - "2021-04-20": 22, - "2021-04-21": 22, - "2021-04-22": 23, - "2021-04-23": 25, - "2021-04-24": 23, - "2021-04-25": 23, - "2021-04-26": 23, - "2021-04-27": 25, - "2021-04-28": 27, - "2021-04-29": 29, - "2021-04-30": 27, - "2021-05-01": 27, - "2021-05-02": 28, - "2021-05-03": 29, - "2021-05-04": 29, - "2021-05-05": 27, - "2021-05-06": 26, - "2021-05-07": 27, - "2021-05-08": 28, - "2021-05-09": 28, - "2021-05-10": 29, - "2021-05-11": 29, - "2021-05-12": 30, - "2021-05-13": 30, - "2021-05-14": 33, - "2021-05-15": 35, - "2021-05-16": 36, - "2021-05-17": 36, - "2021-05-18": 36, - "2021-05-19": 35, - "2021-05-20": 36, - "2021-05-21": 34, - "2021-05-22": 33, - "2021-05-23": 33, - "2021-05-24": 34, - "2021-05-25": 35, - "2021-05-26": 35, - "2021-05-27": 38, - "2021-05-28": 41, - "2021-05-29": 41, - "2021-05-30": 43, - "2021-05-31": 52, - "2021-06-01": 58, - "2021-06-02": 62, - "2021-06-03": 65, - "2021-06-04": 65, - "2021-06-05": 66, - "2021-06-06": 66, - "2021-06-07": 70, - "2021-06-08": 70, - "2021-06-09": 71, - "2021-06-10": 73, - "2021-06-11": 74, - "2021-06-12": 75, - "2021-06-13": 75, - "2021-06-14": 75, - "2021-06-15": 73, - "2021-06-16": 74, - "2021-06-17": 75, - "2021-06-18": 77, - "2021-06-19": 78, - "2021-06-20": 78, - "2021-06-21": 78, - "2021-06-22": 79, - "2021-06-23": 81, - "2021-06-24": 81, - "2021-06-25": 83, - "2021-06-26": 84, - "2021-06-27": 85, - "2021-06-28": 89, - "2021-06-29": 88, - "2021-06-30": 88, - "2021-07-01": 89, - "2021-07-02": 87, - "2021-07-03": 90, - "2021-07-04": 91, - "2021-07-05": 92, - "2021-07-06": 102, - "2021-07-07": 105, - "2021-07-08": 109, - "2021-07-09": 116, - "2021-07-10": 117, - "2021-07-11": 121, - "2021-07-12": 122, - "2021-07-13": 128, - "2021-07-14": 129, - "2021-07-15": 131, - "2021-07-16": 136, - "2021-07-17": 138, - "2021-07-18": 136, - "2021-07-19": 138, - "2021-07-20": 135, - "2021-07-21": 141, - "2021-07-22": 142, - "2021-07-23": 144, - "2021-07-24": 148, - "2021-07-25": 153, - "2021-07-26": 159, - "2021-07-27": 162, - "2021-07-28": 158, - "2021-07-29": 160, - "2021-07-30": 162, - "2021-07-31": 163, - "2021-08-01": 163, - "2021-08-02": 165, - "2021-08-03": 168, - "2021-08-04": 172, - "2021-08-05": 174, - "2021-08-06": 174, - "2021-08-07": 174, - "2021-08-08": 174, - "2021-08-09": 174, - "2021-08-10": 172, - "2021-08-11": 171, - "2021-08-12": 168, - "2021-08-13": 167, - "2021-08-14": 170, - "2021-08-15": 178, - "2021-08-16": 180, - "2021-08-17": 184, - "2021-08-18": 187, - "2021-08-19": 186, - "2021-08-20": 190, - "2021-08-21": 191, - "2021-08-22": 193, - "2021-08-23": 195, - "2021-08-24": 192, - "2021-08-25": 189, - "2021-08-26": 191, - "2021-08-27": 187, - "2021-08-28": 189, - "2021-08-29": 192, - "2021-08-30": 190, - "2021-08-31": 171, - "2021-09-01": 169, - "2021-09-02": 165, - "2021-09-03": 168, - "2021-09-04": 167, - "2021-09-05": 169, - "2021-09-06": 171, - "2021-09-07": 169, - "2021-09-08": 172, - "2021-09-09": 172, - "2021-09-10": 167, - "2021-09-11": 166, - "2021-09-12": 164, - "2021-09-13": 157, - "2021-09-14": 157, - "2021-09-15": 156, - "2021-09-16": 159, - "2021-09-17": 158, - "2021-09-18": 161, - "2021-09-19": 163, - "2021-09-20": 167, - "2021-09-21": 168, - "2021-09-22": 167, - "2021-09-23": 170, - "2021-09-24": 171, - "2021-09-25": 170, - "2021-09-26": 171, - "2021-09-27": 172, - "2021-09-28": 171, - "2021-09-29": 174, - "2021-09-30": 176, - "2021-10-01": 180, - "2021-10-02": 183, - "2021-10-03": 184, - "2021-10-04": 184, - "2021-10-05": 181, - "2021-10-06": 168, - "2021-10-07": 178, - "2021-10-08": 183, - "2021-10-09": 186, - "2021-10-10": 190, - "2021-10-11": 194, - "2021-10-12": 197, - "2021-10-13": 197, - "2021-10-14": 199, - "2021-10-15": 205, - "2021-10-16": 209, - "2021-10-17": 219, - "2021-10-18": 218, - "2021-10-19": 222, - "2021-10-20": 217, - "2021-10-21": 217, - "2021-10-22": 209, - "2021-10-23": 204, - "2021-10-24": 204, - "2021-10-25": 203, - "2021-10-26": 202, - "2021-10-27": 198, - "2021-10-28": 197, - "2021-10-29": 197, - "2021-10-30": 195, - "2021-10-31": 199, - "2021-11-01": 196, - "2021-11-02": 194, - "2021-11-03": 197, - "2021-11-04": 193, - "2021-11-05": 192, - "2021-11-06": 193, - "2021-11-07": 192, - "2021-11-08": 192, - "2021-11-09": 195, - "2021-11-10": 197, - "2021-11-11": 200, - "2021-11-12": 193, - "2021-11-13": 189, - "2021-11-14": 187, - "2021-11-15": 193, - "2021-11-16": 195, - "2021-11-17": 194, - "2021-11-18": 196, - "2021-11-19": 204, - "2021-11-20": 207, - "2021-11-21": 212, - "2021-11-22": 214, - "2021-11-23": 215, - "2021-11-24": 214, - "2021-11-25": 215, - "2021-11-26": 211, - "2021-11-27": 209, - "2021-11-28": 209, - "2021-11-29": 211, - "2021-11-30": 209, - "2021-12-01": 213, - "2021-12-02": 216, - "2021-12-03": 219, - "2021-12-04": 219, - "2021-12-05": 220, - "2021-12-06": 223, - "2021-12-07": 222, - "2021-12-08": 218, - "2021-12-09": 218, - "2021-12-10": 222, - "2021-12-11": 225, - "2021-12-12": 222, - "2021-12-13": 219, - "2021-12-14": 217, - "2021-12-15": 219, - "2021-12-16": 220, - "2021-12-17": 219, - "2021-12-18": 221, - "2021-12-19": 225, - "2021-12-20": 233, - "2021-12-21": 234, - "2021-12-22": 236, - "2021-12-23": 242, - "2021-12-24": 239, - "2021-12-25": 239, - "2021-12-26": 240, - "2021-12-27": 234, - "2021-12-28": 229, - "2021-12-29": 228, - "2021-12-30": 228, - "2021-12-31": 235, - "2022-01-01": 240, - "2022-01-02": 242, - "2022-01-03": 240, - "2022-01-04": 242, - "2022-01-05": 245, - "2022-01-06": 246, - "2022-01-07": 242, - "2022-01-08": 241, - "2022-01-09": 240, - "2022-01-10": 240, - "2022-01-11": 240, - "2022-01-12": 238, - "2022-01-13": 242, - "2022-01-14": 238, - "2022-01-15": 241, - "2022-01-16": 239, - "2022-01-17": 244, - "2022-01-18": 245, - "2022-01-19": 247, - "2022-01-20": 247, - "2022-01-21": 249, - "2022-01-22": 244, - "2022-01-23": 247, - "2022-01-24": 251, - "2022-01-25": 259, - "2022-01-26": 262, - "2022-01-27": 267, - "2022-01-28": 266, - "2022-01-29": 272, - "2022-01-30": 302, - "2022-01-31": 304, - "2022-02-01": 288, - "2022-02-02": 282, - "2022-02-03": 269, - "2022-02-04": 258, - "2022-02-05": 257, - "2022-02-06": 290, - "2022-02-07": 315, - "2022-02-08": 334, - "2022-02-09": 337, - "2022-02-10": 344, - "2022-02-11": 352, - "2022-02-12": 355, - "2022-02-13": 363, - "2022-02-14": 366, - "2022-02-15": 369, - "2022-02-16": 379, - "2022-02-17": 376, - "2022-02-18": 387, - "2022-02-19": 385, - "2022-02-20": 387, - "2022-02-21": 395, - "2022-02-22": 400, - "2022-02-23": 398, - "2022-02-24": 402, - "2022-02-25": 405, - "2022-02-26": 403, - "2022-02-27": 406, - "2022-02-28": 413, - "2022-03-01": 412, - "2022-03-02": 422, - "2022-03-03": 419, - "2022-03-04": 423, - "2022-03-05": 424, - "2022-03-06": 426, - "2022-03-07": 421, - "2022-03-08": 419, - "2022-03-09": 420, - "2022-03-10": 433, - "2022-03-11": 437, - "2022-03-12": 442, - "2022-03-13": 441, - "2022-03-14": 440, - "2022-03-15": 442, - "2022-03-16": 441, - "2022-03-17": 432, - "2022-03-18": 430, - "2022-03-19": 435, - "2022-03-20": 438, - "2022-03-21": 453, - "2022-03-22": 463, - "2022-03-23": 481, - "2022-03-24": 491, - "2022-03-25": 485, - "2022-03-26": 482, - "2022-03-27": 477, - "2022-03-28": 467, - "2022-03-29": 463, - "2022-03-30": 465, - "2022-03-31": 470, - "2022-04-01": 468, - "2022-04-02": 463, - "2022-04-03": 465, - "2022-04-04": 462, - "2022-04-05": 462, - "2022-04-06": 465, - "2022-04-07": 466, - "2022-04-08": 467, - "2022-04-09": 460, - "2022-04-10": 463, - "2022-04-11": 472, - "2022-04-12": 474, - "2022-04-13": 468, - "2022-04-14": 478, - "2022-04-15": 486, - "2022-04-16": 492, - "2022-04-17": 495, - "2022-04-18": 499, - "2022-04-19": 500, - "2022-04-20": 505, - "2022-04-21": 624, - "2022-04-22": 689, - "2022-04-23": 735, - "2022-04-24": 773, - "2022-04-25": 797, - "2022-04-26": 822, - "2022-04-27": 848, - "2022-04-28": 936, - "2022-04-29": 1019, - "2022-04-30": 1058, - "2022-05-01": 1089, - "2022-05-02": 1123, - "2022-05-03": 1130, - "2022-05-04": 1132, - "2022-05-05": 1148, - "2022-05-06": 1171, - "2022-05-07": 1180, - "2022-05-08": 1206, - "2022-05-09": 1217, - "2022-05-10": 1223, - "2022-05-11": 1230, - "2022-05-12": 1238, - "2022-05-13": 1247, - "2022-05-14": 1245, - "2022-05-15": 1249, - "2022-05-16": 1248, - "2022-05-17": 1255, - "2022-05-18": 1262, - "2022-05-19": 1256, - "2022-05-20": 1258, - "2022-05-21": 1262, - "2022-05-22": 1257, - "2022-05-23": 1274, - "2022-05-24": 1285, - "2022-05-25": 1294, - "2022-05-26": 1301, - "2022-05-27": 1312, - "2022-05-28": 1310, - "2022-05-29": 1315, - "2022-05-30": 1309, - "2022-05-31": 1313, - "2022-06-01": 1313, - "2022-06-02": 1315, - "2022-06-03": 1321, - "2022-06-04": 1328, - "2022-06-05": 1330, - "2022-06-06": 1329, - "2022-06-07": 1331, - "2022-06-08": 1331, - "2022-06-09": 1326, - "2022-06-10": 1323, - "2022-06-11": 1315, - "2022-06-12": 1323, - "2022-06-13": 1337, - "2022-06-14": 1349, - "2022-06-15": 1354, - "2022-06-16": 1361, - "2022-06-17": 1369, - "2022-06-18": 1359, - "2022-06-19": 1383, - "2022-06-20": 1402, - "2022-06-21": 1399, - "2022-06-22": 1399, - "2022-06-23": 1422, - "2022-06-24": 1451, - "2022-06-25": 1474, - "2022-06-26": 1464, - "2022-06-27": 1481, - "2022-06-28": 1479, - "2022-06-29": 1465, - "2022-06-30": 1423, - "2022-07-01": 1414, - "2022-07-02": 1392, - "2022-07-03": 1440, - "2022-07-04": 1466, - "2022-07-05": 1473, - "2022-07-06": 1476, - "2022-07-07": 1484, - "2022-07-08": 1481, - "2022-07-09": 1479, - "2022-07-10": 1501, - "2022-07-11": 1514, - "2022-07-12": 1529, - "2022-07-13": 1532, - "2022-07-14": 1547, - "2022-07-15": 1567, - "2022-07-16": 1576, - "2022-07-17": 1583, - "2022-07-18": 1585, - "2022-07-19": 1607, - "2022-07-20": 1601, - "2022-07-21": 1613, - "2022-07-22": 1602, - "2022-07-23": 1602, - "2022-07-24": 1623, - "2022-07-25": 1623, - "2022-07-26": 1617, - "2022-07-27": 1624, - "2022-07-28": 1612, - "2022-07-29": 1620, - "2022-07-30": 1624, - "2022-07-31": 1612, - "2022-08-01": 1618, - "2022-08-02": 1636, - "2022-08-03": 1632, - "2022-08-04": 1628, - "2022-08-05": 1631, - "2022-08-06": 1629, - "2022-08-07": 1628, - "2022-08-08": 1645, - "2022-08-09": 1652, - "2022-08-10": 1664, - "2022-08-11": 1654, - "2022-08-12": 1643, - "2022-08-13": 1634, - "2022-08-14": 1646, - "2022-08-15": 1652, - "2022-08-16": 1646, - "2022-08-17": 1639, - "2022-08-18": 1632, - "2022-08-19": 1636, - "2022-08-20": 1634, - "2022-08-21": 1638, - "2022-08-22": 1650, - "2022-08-23": 1648, - "2022-08-24": 1662, - "2022-08-25": 1664, - "2022-08-26": 1665, - "2022-08-27": 1669, - "2022-08-28": 1679, - "2022-08-29": 1671, - "2022-08-30": 1668, - "2022-08-31": 1675, - "2022-09-01": 1663, - "2022-09-02": 1659, - "2022-09-03": 1672, - "2022-09-04": 1658, - "2022-09-05": 1679, - "2022-09-06": 1695, - "2022-09-07": 1685, - "2022-09-08": 1683, - "2022-09-09": 1696, - "2022-09-10": 1696, - "2022-09-11": 1691, - "2022-09-12": 1684, - "2022-09-13": 1702, - "2022-09-14": 1716, - "2022-09-15": 1725, - "2022-09-16": 1718, - "2022-09-17": 1716, - "2022-09-18": 1725, - "2022-09-19": 1747, - "2022-09-20": 1749, - "2022-09-21": 1739, - "2022-09-22": 1742, - "2022-09-23": 1754, - "2022-09-24": 1745, - "2022-09-25": 1752, - "2022-09-26": 1753, - "2022-09-27": 1770, - "2022-09-28": 1778, - "2022-09-29": 1794, - "2022-09-30": 1793, - "2022-10-01": 1791, - "2022-10-02": 1789, - "2022-10-03": 1778, - "2022-10-04": 1756, - "2022-10-05": 1726, - "2022-10-06": 1634, - "2022-10-07": 1705, - "2022-10-08": 1755, - "2022-10-09": 1791, - "2022-10-10": 1802, - "2022-10-11": 1822, - "2022-10-12": 1818, - "2022-10-13": 1801, - "2022-10-14": 1803, - "2022-10-15": 1828, - "2022-10-16": 1817, - "2022-10-17": 1820, - "2022-10-18": 1811, - "2022-10-19": 1803, - "2022-10-20": 1812, - "2022-10-21": 1833, - "2022-10-22": 1831, - "2022-10-23": 1838, - "2022-10-24": 1830, - "2022-10-25": 1830, - "2022-10-26": 1823, - "2022-10-27": 1832, - "2022-10-28": 1822, - "2022-10-29": 1820, - "2022-10-30": 1831, - "2022-10-31": 1824, - "2022-11-01": 1816, - "2022-11-02": 1824, - "2022-11-03": 1838, - "2022-11-04": 1841, - "2022-11-05": 1854, - "2022-11-06": 1844, - "2022-11-07": 1860, - "2022-11-08": 1855, - "2022-11-09": 1857, - "2022-11-10": 1858, - "2022-11-11": 1850, - "2022-11-12": 1854, - "2022-11-13": 1853, - "2022-11-14": 1848, - "2022-11-15": 1862, - "2022-11-16": 1867, - "2022-11-17": 1877, - "2022-11-18": 1894, - "2022-11-19": 1879, - "2022-11-20": 1874, - "2022-11-21": 1882, - "2022-11-22": 1888, - "2022-11-23": 1883, - "2022-11-24": 1887, - "2022-11-25": 1904 -} \ No newline at end of file diff --git a/script/data/user_edge.json b/script/data/user_edge.json deleted file mode 100644 index 8f5f2a2f..00000000 --- a/script/data/user_edge.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "2021-03-14": 19, - "2021-03-21": 49, - "2021-03-28": 57, - "2021-04-04": 63, - "2021-04-11": 63, - "2021-04-18": 74, - "2021-04-25": 93, - "2021-05-02": 118, - "2021-05-09": 131, - "2021-05-16": 133, - "2021-05-23": 154, - "2021-05-30": 169, - "2021-06-06": 193, - "2021-06-13": 192, - "2021-06-20": 203, - "2021-06-27": 209, - "2021-07-04": 258, - "2021-07-11": 219, - "2021-07-18": 227, - "2021-07-25": 246, - "2021-08-01": 271, - "2021-08-08": 291, - "2021-08-15": 298, - "2021-08-22": 295, - "2021-08-29": 313, - "2021-09-05": 305, - "2021-09-12": 311, - "2021-09-19": 356, - "2021-09-26": 324, - "2021-10-03": 346, - "2021-10-10": 417, - "2021-10-17": 399, - "2021-10-24": 378, - "2021-10-31": 394, - "2021-11-07": 460, - "2021-11-14": 449, - "2021-11-21": 438, - "2021-11-28": 432, - "2021-12-05": 453, - "2021-12-12": 461, - "2021-12-19": 465, - "2021-12-26": 509, - "2022-01-02": 524, - "2022-01-09": 530, - "2022-01-16": 519, - "2022-01-23": 517, - "2022-01-30": 528, - "2022-02-06": 459, - "2022-02-13": 582, - "2022-02-20": 546, - "2022-02-27": 591, - "2022-03-06": 618, - "2022-03-13": 645, - "2022-03-20": 646, - "2022-03-27": 641, - "2022-04-03": 692, - "2022-04-10": 744, - "2022-04-17": 747, - "2022-04-24": 975, - "2022-05-01": 1198, - "2022-05-08": 1294, - "2022-05-15": 1302, - "2022-05-22": 1354, - "2022-05-29": 1369, - "2022-06-05": 1354, - "2022-06-12": 1360, - "2022-06-19": 1398, - "2022-06-26": 1378, - "2022-07-03": 1379, - "2022-07-10": 1553, - "2022-07-17": 1532, - "2022-07-24": 1701, - "2022-07-31": 1728, - "2022-08-07": 1644, - "2022-08-14": 1636, - "2022-08-21": 1649, - "2022-08-28": 1641, - "2022-09-05": 1821, - "2022-09-11": 1719, - "2022-09-18": 1851, - "2022-09-25": 1805, - "2022-10-02": 1827, - "2022-10-09": 1925, - "2022-10-16": 1886, - "2022-10-23": 1906, - "2022-10-30": 1888, - "2022-11-06": 1905, - "2022-11-13": 1967, - "2022-11-20": 1956, - "2022-11-27": 1993 -} \ No newline at end of file diff --git a/script/data/user_firefox.json b/script/data/user_firefox.json deleted file mode 100644 index b52c4cff..00000000 --- a/script/data/user_firefox.json +++ /dev/null @@ -1,632 +0,0 @@ -{ - "2021-03-03": 1, - "2021-03-04": 2, - "2021-03-05": 1, - "2021-03-06": 1, - "2021-03-08": 1, - "2021-03-09": 2, - "2021-03-10": 1, - "2021-03-11": 1, - "2021-03-12": 1, - "2021-03-13": 1, - "2021-03-14": 1, - "2021-03-15": 1, - "2021-03-16": 1, - "2021-03-17": 1, - "2021-03-18": 1, - "2021-03-19": 1, - "2021-03-22": 1, - "2021-03-23": 2, - "2021-03-24": 3, - "2021-03-25": 1, - "2021-03-26": 2, - "2021-03-27": 2, - "2021-03-28": 2, - "2021-03-30": 2, - "2021-03-31": 1, - "2021-04-01": 2, - "2021-04-02": 2, - "2021-04-03": 1, - "2021-04-04": 1, - "2021-04-05": 1, - "2021-04-06": 1, - "2021-04-07": 2, - "2021-04-08": 1, - "2021-04-09": 1, - "2021-04-10": 2, - "2021-04-11": 3, - "2021-04-12": 3, - "2021-04-13": 3, - "2021-04-14": 4, - "2021-04-15": 4, - "2021-04-16": 6, - "2021-04-17": 5, - "2021-04-18": 4, - "2021-04-19": 4, - "2021-04-20": 3, - "2021-04-21": 5, - "2021-04-22": 3, - "2021-04-23": 3, - "2021-04-24": 3, - "2021-04-25": 4, - "2021-04-26": 5, - "2021-04-27": 4, - "2021-04-28": 6, - "2021-04-29": 4, - "2021-04-30": 6, - "2021-05-01": 4, - "2021-05-02": 5, - "2021-05-03": 6, - "2021-05-04": 5, - "2021-05-05": 6, - "2021-05-06": 7, - "2021-05-07": 7, - "2021-05-08": 6, - "2021-05-09": 6, - "2021-05-10": 7, - "2021-05-11": 10, - "2021-05-12": 8, - "2021-05-13": 9, - "2021-05-14": 9, - "2021-05-15": 6, - "2021-05-16": 7, - "2021-05-17": 7, - "2021-05-18": 8, - "2021-05-19": 7, - "2021-05-20": 8, - "2021-05-21": 9, - "2021-05-22": 8, - "2021-05-23": 8, - "2021-05-24": 7, - "2021-05-25": 7, - "2021-05-26": 8, - "2021-05-27": 8, - "2021-05-28": 9, - "2021-05-29": 9, - "2021-05-30": 7, - "2021-05-31": 10, - "2021-06-01": 9, - "2021-06-02": 10, - "2021-06-03": 8, - "2021-06-04": 9, - "2021-06-05": 9, - "2021-06-06": 9, - "2021-06-07": 10, - "2021-06-08": 11, - "2021-06-09": 12, - "2021-06-10": 11, - "2021-06-11": 10, - "2021-06-12": 10, - "2021-06-13": 12, - "2021-06-14": 9, - "2021-06-15": 10, - "2021-06-16": 8, - "2021-06-17": 10, - "2021-06-18": 10, - "2021-06-19": 10, - "2021-06-20": 9, - "2021-06-21": 7, - "2021-06-22": 9, - "2021-06-23": 9, - "2021-06-24": 11, - "2021-06-25": 12, - "2021-06-26": 12, - "2021-06-27": 11, - "2021-06-28": 12, - "2021-06-29": 11, - "2021-06-30": 11, - "2021-07-01": 11, - "2021-07-02": 8, - "2021-07-03": 11, - "2021-07-04": 9, - "2021-07-05": 14, - "2021-07-06": 12, - "2021-07-07": 12, - "2021-07-08": 12, - "2021-07-09": 12, - "2021-07-10": 13, - "2021-07-11": 14, - "2021-07-12": 13, - "2021-07-13": 11, - "2021-07-14": 14, - "2021-07-15": 14, - "2021-07-16": 16, - "2021-07-17": 12, - "2021-07-18": 9, - "2021-07-19": 12, - "2021-07-20": 10, - "2021-07-21": 8, - "2021-07-22": 11, - "2021-07-23": 12, - "2021-07-24": 10, - "2021-07-25": 10, - "2021-07-26": 10, - "2021-07-27": 12, - "2021-07-28": 10, - "2021-07-29": 9, - "2021-07-30": 9, - "2021-07-31": 10, - "2021-08-01": 11, - "2021-08-02": 11, - "2021-08-03": 14, - "2021-08-04": 15, - "2021-08-05": 14, - "2021-08-06": 17, - "2021-08-07": 17, - "2021-08-08": 14, - "2021-08-09": 14, - "2021-08-10": 15, - "2021-08-11": 14, - "2021-08-12": 14, - "2021-08-13": 11, - "2021-08-14": 12, - "2021-08-15": 13, - "2021-08-16": 12, - "2021-08-17": 9, - "2021-08-18": 13, - "2021-08-19": 11, - "2021-08-20": 9, - "2021-08-21": 9, - "2021-08-22": 10, - "2021-08-23": 11, - "2021-08-24": 13, - "2021-08-25": 12, - "2021-08-26": 13, - "2021-08-27": 12, - "2021-08-28": 12, - "2021-08-29": 18, - "2021-08-30": 20, - "2021-08-31": 16, - "2021-09-01": 17, - "2021-09-02": 17, - "2021-09-03": 17, - "2021-09-04": 18, - "2021-09-05": 18, - "2021-09-06": 18, - "2021-09-07": 17, - "2021-09-08": 16, - "2021-09-09": 16, - "2021-09-10": 15, - "2021-09-11": 15, - "2021-09-12": 15, - "2021-09-13": 14, - "2021-09-14": 19, - "2021-09-15": 19, - "2021-09-16": 17, - "2021-09-17": 16, - "2021-09-18": 15, - "2021-09-19": 15, - "2021-09-20": 14, - "2021-09-21": 13, - "2021-09-22": 17, - "2021-09-23": 16, - "2021-09-24": 17, - "2021-09-25": 18, - "2021-09-26": 14, - "2021-09-27": 15, - "2021-09-28": 12, - "2021-09-29": 10, - "2021-09-30": 3, - "2021-10-01": 3, - "2021-10-02": 5, - "2021-10-03": 3, - "2021-10-04": 2, - "2021-10-05": 4, - "2021-10-06": 5, - "2021-10-07": 11, - "2021-10-08": 12, - "2021-10-09": 12, - "2021-10-10": 17, - "2021-10-11": 15, - "2021-10-12": 14, - "2021-10-13": 13, - "2021-10-14": 12, - "2021-10-15": 13, - "2021-10-16": 13, - "2021-10-17": 14, - "2021-10-18": 11, - "2021-10-19": 14, - "2021-10-20": 12, - "2021-10-21": 12, - "2021-10-22": 13, - "2021-10-23": 15, - "2021-10-24": 16, - "2021-10-25": 17, - "2021-10-26": 13, - "2021-10-27": 13, - "2021-10-28": 11, - "2021-10-29": 16, - "2021-10-30": 18, - "2021-10-31": 17, - "2021-11-01": 15, - "2021-11-02": 11, - "2021-11-03": 14, - "2021-11-04": 16, - "2021-11-05": 16, - "2021-11-06": 17, - "2021-11-07": 14, - "2021-11-08": 14, - "2021-11-09": 15, - "2021-11-10": 17, - "2021-11-11": 14, - "2021-11-12": 18, - "2021-11-13": 12, - "2021-11-14": 15, - "2021-11-15": 15, - "2021-11-16": 16, - "2021-11-17": 17, - "2021-11-18": 12, - "2021-11-19": 12, - "2021-11-20": 12, - "2021-11-21": 17, - "2021-11-22": 16, - "2021-11-23": 18, - "2021-11-24": 18, - "2021-11-25": 17, - "2021-11-26": 16, - "2021-11-27": 18, - "2021-11-28": 16, - "2021-11-29": 16, - "2021-11-30": 11, - "2021-12-01": 12, - "2021-12-02": 13, - "2021-12-03": 16, - "2021-12-04": 13, - "2021-12-05": 13, - "2021-12-06": 12, - "2021-12-07": 13, - "2021-12-08": 14, - "2021-12-09": 12, - "2021-12-10": 10, - "2021-12-11": 12, - "2021-12-12": 15, - "2021-12-13": 14, - "2021-12-14": 15, - "2021-12-15": 15, - "2021-12-16": 14, - "2021-12-17": 14, - "2021-12-18": 11, - "2021-12-19": 12, - "2021-12-20": 18, - "2021-12-21": 15, - "2021-12-22": 16, - "2021-12-23": 15, - "2021-12-24": 12, - "2021-12-25": 9, - "2021-12-26": 11, - "2021-12-27": 11, - "2021-12-28": 12, - "2021-12-29": 11, - "2021-12-30": 11, - "2021-12-31": 14, - "2022-01-01": 11, - "2022-01-02": 15, - "2022-01-03": 12, - "2022-01-04": 15, - "2022-01-05": 13, - "2022-01-06": 14, - "2022-01-07": 10, - "2022-01-08": 9, - "2022-01-09": 7, - "2022-01-10": 11, - "2022-01-11": 12, - "2022-01-12": 12, - "2022-01-13": 14, - "2022-01-14": 11, - "2022-01-15": 13, - "2022-01-16": 13, - "2022-01-17": 18, - "2022-01-18": 17, - "2022-01-19": 16, - "2022-01-20": 19, - "2022-01-21": 14, - "2022-01-22": 12, - "2022-01-23": 15, - "2022-01-24": 20, - "2022-01-25": 16, - "2022-01-26": 21, - "2022-01-27": 18, - "2022-01-28": 15, - "2022-01-29": 13, - "2022-01-30": 11, - "2022-01-31": 10, - "2022-02-01": 12, - "2022-02-02": 10, - "2022-02-03": 11, - "2022-02-04": 13, - "2022-02-05": 16, - "2022-02-06": 15, - "2022-02-07": 12, - "2022-02-08": 16, - "2022-02-09": 16, - "2022-02-10": 19, - "2022-02-11": 19, - "2022-02-12": 20, - "2022-02-13": 15, - "2022-02-14": 15, - "2022-02-15": 17, - "2022-02-16": 19, - "2022-02-17": 14, - "2022-02-18": 21, - "2022-02-19": 15, - "2022-02-20": 16, - "2022-02-21": 18, - "2022-02-22": 20, - "2022-02-23": 17, - "2022-02-24": 17, - "2022-02-25": 16, - "2022-02-26": 15, - "2022-02-27": 18, - "2022-02-28": 18, - "2022-03-01": 20, - "2022-03-02": 18, - "2022-03-03": 18, - "2022-03-04": 18, - "2022-03-05": 21, - "2022-03-06": 17, - "2022-03-07": 19, - "2022-03-08": 19, - "2022-03-09": 20, - "2022-03-10": 20, - "2022-03-11": 19, - "2022-03-12": 20, - "2022-03-13": 21, - "2022-03-14": 20, - "2022-03-15": 22, - "2022-03-16": 22, - "2022-03-17": 24, - "2022-03-18": 21, - "2022-03-19": 21, - "2022-03-20": 18, - "2022-03-21": 20, - "2022-03-22": 17, - "2022-03-23": 17, - "2022-03-24": 16, - "2022-03-25": 19, - "2022-03-26": 21, - "2022-03-27": 21, - "2022-03-28": 21, - "2022-03-29": 18, - "2022-03-30": 20, - "2022-03-31": 21, - "2022-04-01": 18, - "2022-04-02": 17, - "2022-04-03": 18, - "2022-04-04": 18, - "2022-04-05": 20, - "2022-04-06": 18, - "2022-04-07": 19, - "2022-04-08": 23, - "2022-04-09": 18, - "2022-04-10": 15, - "2022-04-11": 18, - "2022-04-12": 18, - "2022-04-13": 22, - "2022-04-14": 21, - "2022-04-15": 22, - "2022-04-16": 19, - "2022-04-17": 25, - "2022-04-18": 18, - "2022-04-19": 17, - "2022-04-20": 20, - "2022-04-21": 34, - "2022-04-22": 42, - "2022-04-23": 43, - "2022-04-24": 59, - "2022-04-25": 67, - "2022-04-26": 66, - "2022-04-27": 59, - "2022-04-28": 62, - "2022-04-29": 53, - "2022-04-30": 46, - "2022-05-01": 50, - "2022-05-02": 45, - "2022-05-03": 54, - "2022-05-04": 61, - "2022-05-05": 65, - "2022-05-06": 57, - "2022-05-07": 59, - "2022-05-08": 52, - "2022-05-09": 56, - "2022-05-10": 62, - "2022-05-11": 60, - "2022-05-12": 57, - "2022-05-13": 59, - "2022-05-14": 49, - "2022-05-15": 54, - "2022-05-16": 58, - "2022-05-17": 59, - "2022-05-18": 55, - "2022-05-19": 64, - "2022-05-20": 63, - "2022-05-21": 60, - "2022-05-22": 61, - "2022-05-23": 63, - "2022-05-24": 60, - "2022-05-25": 56, - "2022-05-26": 61, - "2022-05-27": 56, - "2022-05-28": 58, - "2022-05-29": 53, - "2022-05-30": 56, - "2022-05-31": 51, - "2022-06-01": 59, - "2022-06-02": 65, - "2022-06-03": 53, - "2022-06-04": 54, - "2022-06-05": 51, - "2022-06-06": 64, - "2022-06-07": 61, - "2022-06-08": 56, - "2022-06-09": 59, - "2022-06-10": 63, - "2022-06-11": 47, - "2022-06-12": 55, - "2022-06-13": 67, - "2022-06-14": 57, - "2022-06-15": 63, - "2022-06-16": 60, - "2022-06-17": 56, - "2022-06-18": 54, - "2022-06-19": 54, - "2022-06-20": 61, - "2022-06-21": 60, - "2022-06-22": 68, - "2022-06-23": 63, - "2022-06-24": 63, - "2022-06-25": 53, - "2022-06-26": 48, - "2022-06-27": 59, - "2022-06-28": 61, - "2022-06-29": 57, - "2022-06-30": 58, - "2022-07-01": 56, - "2022-07-02": 46, - "2022-07-03": 50, - "2022-07-04": 60, - "2022-07-05": 57, - "2022-07-06": 61, - "2022-07-07": 68, - "2022-07-08": 62, - "2022-07-09": 52, - "2022-07-10": 48, - "2022-07-11": 55, - "2022-07-12": 62, - "2022-07-13": 57, - "2022-07-14": 55, - "2022-07-15": 61, - "2022-07-16": 52, - "2022-07-17": 49, - "2022-07-18": 58, - "2022-07-19": 56, - "2022-07-20": 61, - "2022-07-21": 59, - "2022-07-22": 61, - "2022-07-23": 60, - "2022-07-24": 51, - "2022-07-25": 66, - "2022-07-26": 70, - "2022-07-27": 70, - "2022-07-28": 65, - "2022-07-29": 67, - "2022-07-30": 56, - "2022-07-31": 55, - "2022-08-01": 68, - "2022-08-02": 71, - "2022-08-03": 58, - "2022-08-04": 57, - "2022-08-05": 61, - "2022-08-06": 63, - "2022-08-07": 65, - "2022-08-08": 68, - "2022-08-09": 60, - "2022-08-10": 73, - "2022-08-11": 63, - "2022-08-12": 60, - "2022-08-13": 52, - "2022-08-14": 49, - "2022-08-15": 64, - "2022-08-16": 63, - "2022-08-17": 67, - "2022-08-18": 67, - "2022-08-19": 73, - "2022-08-20": 61, - "2022-08-21": 61, - "2022-08-22": 71, - "2022-08-23": 69, - "2022-08-24": 67, - "2022-08-25": 66, - "2022-08-26": 64, - "2022-08-27": 57, - "2022-08-28": 51, - "2022-08-29": 68, - "2022-08-30": 65, - "2022-08-31": 69, - "2022-09-01": 60, - "2022-09-02": 67, - "2022-09-03": 61, - "2022-09-04": 54, - "2022-09-05": 66, - "2022-09-06": 70, - "2022-09-07": 75, - "2022-09-08": 70, - "2022-09-09": 67, - "2022-09-10": 55, - "2022-09-11": 62, - "2022-09-12": 57, - "2022-09-13": 75, - "2022-09-14": 67, - "2022-09-15": 68, - "2022-09-16": 71, - "2022-09-17": 61, - "2022-09-18": 52, - "2022-09-19": 62, - "2022-09-20": 58, - "2022-09-21": 59, - "2022-09-22": 62, - "2022-09-23": 67, - "2022-09-24": 63, - "2022-09-25": 54, - "2022-09-26": 65, - "2022-09-27": 70, - "2022-09-28": 65, - "2022-09-29": 55, - "2022-09-30": 60, - "2022-10-01": 49, - "2022-10-02": 52, - "2022-10-03": 54, - "2022-10-04": 56, - "2022-10-05": 66, - "2022-10-06": 61, - "2022-10-07": 60, - "2022-10-08": 67, - "2022-10-09": 67, - "2022-10-10": 62, - "2022-10-11": 64, - "2022-10-12": 62, - "2022-10-13": 65, - "2022-10-14": 77, - "2022-10-15": 62, - "2022-10-16": 68, - "2022-10-17": 68, - "2022-10-18": 78, - "2022-10-19": 72, - "2022-10-20": 76, - "2022-10-21": 71, - "2022-10-22": 58, - "2022-10-23": 59, - "2022-10-24": 68, - "2022-10-25": 70, - "2022-10-26": 69, - "2022-10-27": 74, - "2022-10-28": 65, - "2022-10-29": 57, - "2022-10-30": 63, - "2022-10-31": 75, - "2022-11-01": 77, - "2022-11-02": 77, - "2022-11-03": 78, - "2022-11-04": 79, - "2022-11-05": 66, - "2022-11-06": 63, - "2022-11-07": 69, - "2022-11-08": 67, - "2022-11-09": 64, - "2022-11-10": 73, - "2022-11-11": 73, - "2022-11-12": 61, - "2022-11-13": 59, - "2022-11-14": 68, - "2022-11-15": 74, - "2022-11-16": 73, - "2022-11-17": 77, - "2022-11-18": 79, - "2022-11-19": 65, - "2022-11-20": 64, - "2022-11-21": 73, - "2022-11-22": 76, - "2022-11-23": 78, - "2022-11-24": 74, - "2022-11-25": 78, - "2022-11-26": 66 -} \ No newline at end of file diff --git a/script/requirements.txt b/script/requirements.txt deleted file mode 100644 index f04644a0..00000000 --- a/script/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -pygal -cairosvg -requests \ No newline at end of file diff --git a/script/user-chart/add.ts b/script/user-chart/add.ts new file mode 100644 index 00000000..2a1d54fd --- /dev/null +++ b/script/user-chart/add.ts @@ -0,0 +1,140 @@ +import { + createGist as createGistApi, + getJsonFileContent, + Gist, + GistForm, + updateGist as updateGistApi +} from "@src/api/gist" +import { AddArgv, Argv, Browser } from "./argv" +import fs from "fs" +import { descriptionOf, exitWith, filenameOf, getExistGist } from "./common" + +export type UserCount = Record + +async function createGist(token: string, browser: Browser, data: UserCount) { + const description = descriptionOf(browser) + const filename = filenameOf(browser) + + // 1. sort by key + const sorted: UserCount = {} + Object.keys(data).sort().forEach(key => sorted[key] = data[key]) + // 2. create + const files = {} + files[filename] = { filename: filename, content: JSON.stringify(sorted, null, 2) } + const gistForm: GistForm = { + public: true, + description, + files + } + await createGistApi(token, gistForm) +} + +async function updateGist(token: string, browser: Browser, data: UserCount, gist: Gist) { + const description = descriptionOf(browser) + const filename = filenameOf(browser) + // 1. merge + const file = gist.files[filename] + const existData = (await getJsonFileContent(file)) || {} + Object.entries(data).forEach(([key, val]) => existData[key] = val) + // 2. sort by key + const sorted: UserCount = {} + Object.keys(existData).sort().forEach(key => sorted[key] = existData[key]) + const files = {} + files[filename] = { filename: filename, content: JSON.stringify(sorted, null, 2) } + const gistForm: GistForm = { + public: true, + description, + files + } + updateGistApi(token, gist.id, gistForm) +} + +function parseChrome(content: string): UserCount { + const lines = content.split('\n') + const result = {} + if (!(lines?.length > 2)) { + return result + } + lines.slice(2).forEach(line => { + const [dateStr, numberStr] = line.split(',') + if (!dateStr || !numberStr) { + return + } + // Replace '/' to '-', then rjust month and date + const date = dateStr.split('/').map(str => rjust(str, 2, '0')).join('-') + const number = parseInt(numberStr) + date && number && (result[date] = number) + }) + return result +} + +function parseEdge(content: string): UserCount { + const lines = content.split('\n') + const result = {} + if (!(lines?.length > 1)) { + return result + } + lines.slice(1).forEach(line => { + const splits = line.split(',') + const dateStr = splits[5] + const numberStr = splits[6] + if (!dateStr || !numberStr) { + return + } + // Replace '/' to '-', then rjust month and date + const date = dateStr.split('/').map(str => rjust(str, 2, '0')).join('-') + const number = parseInt(numberStr) + date && number && (result[date] = number) + }) + return result +} + +function parseFirefox(content: string): UserCount { + const lines = content.split('\n') + const result = {} + if (!(lines?.length > 4)) { + return result + } + lines.slice(4).forEach(line => { + const splits = line.split(',') + const date = splits[0] + const numberStr = splits[1] + if (!date || !numberStr) { + return + } + const number = parseInt(numberStr) + date && number && (result[date] = number) + }) + return result +} + +function rjust(str: string, num: number, padding: string): string { + str = str || '' + if (str.length >= num) { + return str + } + return Array.from(new Array(num - str.length).keys()).map(_ => padding).join('') + str +} + +export async function add(argv: Argv) { + const token = argv.gistToken + const browser = (argv as AddArgv).browser + const fileName = (argv as AddArgv).fileName + const content = fs.readFileSync(fileName, { encoding: 'utf-8' }) + let newData: UserCount = {} + if (browser === 'chrome') { + newData = parseChrome(content) + } else if (browser === 'edge') { + newData = parseEdge(content) + } else if (browser === 'firefox') { + newData = parseFirefox(content) + } else { + exitWith("Un-supported browser: " + browser) + } + const gist = await getExistGist(token, browser) + if (!gist) { + await createGist(token, browser, newData) + } else { + await updateGist(token, browser, newData, gist) + } +} \ No newline at end of file diff --git a/script/user-chart/argv.ts b/script/user-chart/argv.ts new file mode 100644 index 00000000..122c3033 --- /dev/null +++ b/script/user-chart/argv.ts @@ -0,0 +1,70 @@ +import { exitWith } from "./common" + +type Cmd = + | 'add' + | 'render' + +type ArgvBase = { + cmd: Cmd + gistToken: string +} + +export type RenderArgv = ArgvBase & { + cmd: 'render' +} + +export type Browser = + | 'chrome' + | 'firefox' + | 'edge' + +export type AddArgv = ArgvBase & { + cmd: 'add' + browser: Browser + fileName: string +} + +export type Argv = + | RenderArgv + | AddArgv + +export function parseArgv(): Argv { + const argv = process.argv.slice(2) + const cmd: Cmd = argv[0] as Cmd + + const token = process.env.TIMER_USER_COUNT_GIST_TOKEN + if (!token) { + exitWith("Can't find token from env variable [TIMER_USER_COUNT_GIST_TOKEN]") + } + if (cmd === 'add') { + return parseAddArgv(argv, token) + } else if (cmd === 'render') { + return { gistToken: token, cmd: 'render' } as RenderArgv + } else { + console.error("Supported command: render, add") + process.exit() + } +} + +function parseAddArgv(argv: string[], token: string): AddArgv { + const browserArgv = argv[1] + const fileName = argv[2] + if (!browserArgv || !fileName) { + exitWith("add [c/e/f] [file_name]") + } + const browserArgvMap: Record = { + c: 'chrome', + e: 'edge', + f: 'firefox', + } + const browser: Browser = browserArgvMap[browserArgv] + if (!browser) { + exitWith("add [c/e/f] [file_name]") + } + return { + cmd: 'add', + gistToken: token, + browser, + fileName + } +} \ No newline at end of file diff --git a/script/user-chart/common.ts b/script/user-chart/common.ts new file mode 100644 index 00000000..a81e272b --- /dev/null +++ b/script/user-chart/common.ts @@ -0,0 +1,25 @@ +import { findTarget, Gist } from "@api/gist" +import { Browser } from "./argv" + +export function exitWith(msg: string) { + console.error(msg) + process.exit() +} + +/** + * Calculate the gist description of target browser + */ +export function descriptionOf(browser: Browser): string { + return `Timer_UserCount_4_${browser}` +} + +/** + * Calculate the gist filename of target browser + */ +export function filenameOf(browser: Browser): string { + return descriptionOf(browser) + '.json' +} + +export async function getExistGist(token: string, browser: Browser): Promise { + return await findTarget(token, gist => gist.description === descriptionOf(browser)) +} \ No newline at end of file diff --git a/script/user-chart/index.ts b/script/user-chart/index.ts new file mode 100644 index 00000000..8b2ae1b9 --- /dev/null +++ b/script/user-chart/index.ts @@ -0,0 +1,20 @@ +import { add } from "./add" +import { parseArgv } from "./argv" +import { exitWith } from "./common" +import { render } from "./render" + +function main() { + const argv = parseArgv() + switch (argv.cmd) { + case 'add': + add(argv) + break + case 'render': + render(argv) + break + default: + exitWith('Unsupported cmd: ' + JSON.stringify(argv)) + } +} + +main() \ No newline at end of file diff --git a/script/user-chart/render.ts b/script/user-chart/render.ts new file mode 100644 index 00000000..c1d4e02a --- /dev/null +++ b/script/user-chart/render.ts @@ -0,0 +1,212 @@ +import { + createGist, + FileForm, + findTarget, + getJsonFileContent, + Gist, + GistForm, + updateGist +} from "@api/gist" +import { UserCount } from "./add" +import { Argv, Browser } from "./argv" +import { filenameOf, getExistGist } from "./common" +import { EChartsType, init } from "echarts" + +const ALL_BROWSERS: Browser[] = ['firefox', 'edge', 'chrome'] + +type OriginData = { + [browser in Browser]: UserCount +} + +type ChartData = { + xAixs: string[] + yAixses: { + [browser in Browser]: number[] + } +} + +export async function render(argv: Argv): Promise { + const token = argv.gistToken + // 1. get all data + const originData: OriginData = await getOriginData(token) + // 2. pre-process data + const chartData = preProcess(originData) + // 3. render csv + const svg = render2Svg(chartData) + // 4. upload + await upload2Gist(token, svg) + process.exit() +} + +function preProcess(originData: OriginData): ChartData { + // 1. sort datess + const dateSet = new Set() + Object.values(originData).forEach(ud => Object.keys(ud).forEach(date => dateSet.add(date))) + let allDates = Array.from(dateSet).sort() + + // 2. smooth the count + const ctx: { [browser in Browser]: SmoothContext } = { + chrome: new SmoothContext(), + firefox: new SmoothContext(), + edge: new SmoothContext(), + } + + allDates.forEach( + date => ALL_BROWSERS.forEach(b => ctx[b].process(originData[b][date])) + ) + const result = { + xAixs: allDates, + yAixses: { + chrome: ctx.chrome.end(), + firefox: ctx.firefox.end(), + edge: ctx.edge.end(), + } + } + + // 3. zoom + const reduction = Math.floor(Object.keys(allDates).length / 150) + result.xAixs = zoom(result.xAixs, reduction) + ALL_BROWSERS.forEach(b => result.yAixses[b] = zoom(result.yAixses[b], reduction)) + return result +} + +class SmoothContext { + lastVal: number + step: number + data: number[] + + constructor() { + this.lastVal = 0 + this.step = 0 + this.data = [] + } + + /** + * Process value + */ + process(newVal: number | undefined) { + if (newVal) { + this.smooth(newVal) + } else { + this.increaseStep() + } + } + + smooth(currentValue: number): void { + if (this.step < 0) { + return + } + const unitVal = (currentValue - this.lastVal) / (this.step + 1) + Object.keys(Array.from(new Array(this.step))) + .map(key => parseInt(key)) + .map(i => Math.floor(unitVal * (i + 1) + this.lastVal)) + .forEach(smoothedVal => this.data.push(smoothedVal)) + this.data.push(currentValue) + // Reset + this.lastVal = currentValue + this.step = 0 + } + + increaseStep(): void { + this.step += 1 + } + + end(): number[] { + Object.keys(new Array(this.step)) + .forEach(() => this.data.push(this.lastVal)) + return this.data + } +} + +function zoom(data: T[], reduction: number): T[] { + let i = 0 + const newData = [] + while (i < data.length) { + newData.push(data[i]) + i += reduction + } + return newData +} + +function render2Svg(chartData: ChartData): string { + const { xAixs, yAixses } = chartData + const chart: EChartsType = init(null, null, { + renderer: 'svg', + ssr: true, + width: 960, + height: 640 + }) + chart.setOption({ + title: { + text: 'Total Active User Count', + subtext: `${xAixs[0]} to ${xAixs[xAixs.length - 1]}` + }, + legend: { data: ALL_BROWSERS }, + grid: { + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true + }, + xAxis: [{ + type: 'category', + boundaryGap: false, + data: xAixs + }], + yAxis: [ + { type: 'value' } + ], + series: ALL_BROWSERS.map(b => ({ + name: b, + type: 'line', + stack: 'Total', + // Fill the area + areaStyle: {}, + data: yAixses[b] + })) + }) + return chart.renderToSVGString() +} + +const USER_COUNT_GIST_DESC = "User count of timer, auto-generated" +const USER_COUNT_SVG_FILE_NAME = "user_count.svg" + +async function getOriginData(token: string): Promise { + const [firefox, edge, chrome]: UserCount[] = await Promise.all( + ALL_BROWSERS.map(b => getDataFromGist(token, b)) + ) + return { chrome, firefox, edge } +} + +/** + * Get the data from gist + */ +async function getDataFromGist(token: string, browser: Browser): Promise { + const gist: Gist = await getExistGist(token, browser) + const file = gist?.files[filenameOf(browser)] + return file ? getJsonFileContent(file) : {} +} + +/** + * Upload svg string to gist + */ +async function upload2Gist(token: string, svg: string) { + const files: Record = {} + files[USER_COUNT_SVG_FILE_NAME] = { + filename: USER_COUNT_SVG_FILE_NAME, + content: svg + } + const form: GistForm = { + public: true, + description: USER_COUNT_GIST_DESC, + files + } + const gist = await findTarget(token, gist => gist.description === USER_COUNT_GIST_DESC) + if (gist) { + await updateGist(token, gist.id, form) + console.log('Updated gist') + } else { + await createGist(token, form) + console.log('Created new gist') + } +} \ No newline at end of file diff --git a/script/user_count.py b/script/user_count.py deleted file mode 100644 index 19c42998..00000000 --- a/script/user_count.py +++ /dev/null @@ -1,316 +0,0 @@ -import pygal -from collections import OrderedDict -import sys -import json -import os -import cairosvg -import requests -import math - -svg_file_path = os.path.join('output', 'user_count.svg') -output_dir_path = 'output' - -def smooth_count(last_value, step_num, current_value, data): - unit_val = (current_value-last_value) / (step_num+1) - for i in range(step_num): - data.append(unit_val*(i+1)+last_value) - data.append(current_value) - - -def quit_with(msg: str): - print(msg) - quit() - - -def zoom(data, reduction): - i = 0 - new_data = [] - while i < len(data): - new_data.append(data[i]) - i += reduction - return new_data - - -def render(): - edge_user = read_json('user_edge') - chrome_user = read_json('user_chrome') - firefox_user = read_json('user_firefox') - dates = set() - for date in edge_user: - dates.add(date) - for date in chrome_user: - dates.add(date) - for date in firefox_user: - dates.add(date) - sorted_date = sorted(dates) - last_edge, last_chrome, last_firefox = 0, 0, 0 - edge_step, chrome_step, firefox_step = 0, 0, 0 - - edge_data = [] - chrome_data = [] - firefox_data = [] - for date in sorted_date: - if date in chrome_user: - val = chrome_user[date] - smooth_count(last_chrome, chrome_step, val, chrome_data) - last_chrome = val - chrome_step = 0 - else: - chrome_step += 1 - if date in edge_user: - val = edge_user[date] - smooth_count(last_edge, edge_step, val, edge_data) - last_edge = val - edge_step = 0 - else: - edge_step += 1 - if date in firefox_user: - val = firefox_user[date] - smooth_count(last_firefox, firefox_step, val, firefox_data) - last_firefox = val - firefox_step = 0 - else: - firefox_step += 1 - smooth_count(last_chrome, chrome_step, last_chrome, chrome_data) - smooth_count(last_edge, edge_step, last_edge, edge_data) - smooth_count(last_firefox, firefox_step, last_firefox, firefox_data) - - data_size = len(chrome_data) - reduction = math.floor(data_size/150) - chrome_data = zoom(chrome_data, reduction) - edge_data = zoom(edge_data, reduction) - firefox_data = zoom(firefox_data, reduction) - sorted_date = zoom(sorted_date, reduction) - - chart = pygal.StackedLine( - fill=True, style=pygal.style.styles['default'](label_font_size=8)) - chart.title = 'Active User Count / {} to {}'.format( - sorted_date[0], sorted_date[-1]) - - chart.add('Firefox', firefox_data) - chart.add('Chrome', chrome_data) - chart.add('Edge', edge_data) - svg = chart.render() - if not os.path.exists(output_dir_path): - os.makedirs(output_dir_path) - with open(svg_file_path, 'wb') as svg_file: - svg_file.write(svg) - cairosvg.svg2svg(file_obj=open(svg_file_path, 'r'), write_to=svg_file_path) - - -def read_json(name): - dir_path = 'data' - if not os.path.exists(dir_path): - os.mkdir(dir_path) - return None - file_path = os.path.join(dir_path, '{}.json'.format(name)) - if not os.path.exists(file_path): - return None - with open(file_path, 'r', encoding='utf8') as json_file: - content = '\n'.join(json_file.readlines()) - return json.loads(content) - - -def write_json(name, json_obj): - dir_path = 'data' - if not os.path.exists(dir_path): - os.mkdir(dir_path) - file_path = os.path.join(dir_path, '{}.json'.format(name)) - with open(file_path, 'w', encoding='utf8') as json_file: - json_file.write(json.dumps(json_obj, indent=4)) - - -def add_chrome(file_path): - json_file = 'user_chrome' - if not os.path.exists(file_path): - quit_with("File not found: {}".format(file_path)) - # 1. parse input data - input_data = {} - with open(file_path, encoding='utf8', mode='r') as csv_file: - lines = csv_file.readlines()[2:] - for line in lines: - if not line: - continue - splits = line.split(',') - origin_date = splits[0] - value = int(splits[1]) - date = '-'.join(map(lambda a: a.rjust(2, '0'), - origin_date.split('/'))) - input_data[date] = value - # 2. read exist data - exist_data = read_json(json_file) - if not exist_data: - exist_data = {} - # 3. migrate - for key, val in input_data.items(): - if key not in exist_data and val: - exist_data[key] = val - # 4. write with sorted by key - write_json(json_file, OrderedDict(sorted(exist_data.items()))) - pass - - -def add_edge(file_path): - json_file = 'user_edge' - if not os.path.exists(file_path): - quit_with("File not found: {}".format(file_path)) - # 1. parse input data - input_data = {} - with open(file_path, encoding='utf8', mode='r') as csv_file: - lines = csv_file.readlines()[1:] - for line in lines: - if not line: - continue - splits = line.split(',') - date = splits[5] - value = int(splits[6]) - input_data[date] = value - if not value and len(input_data): - # The last line maybe zero caused by edge's bug - continue - # 2. read exist data - exist_data = read_json(json_file) - if not exist_data: - exist_data = {} - # 3. migrate - for key in input_data: - if key not in exist_data: - exist_data[key] = input_data[key] - # 4. write with sorted by key - write_json(json_file, OrderedDict(sorted(exist_data.items()))) - pass - - -def add_firefox(file_path): - json_file = 'user_firefox' - if not os.path.exists(file_path): - quit_with("File not found: {}".format(file_path)) - # 1. parse input data - input_data = {} - with open(file_path, encoding='utf8', mode='r') as csv_file: - lines = csv_file.readlines()[4:] - for line in lines: - if not line: - continue - splits = line.split(',') - date = splits[0] - value = int(splits[1]) - input_data[date] = value - # 2. read exist data - exist_data = read_json(json_file) - if not exist_data: - exist_data = {} - # 3. migrate - for key in input_data: - if key not in exist_data: - exist_data[key] = input_data[key] - # 4. write with sorted by key - write_json(json_file, OrderedDict(sorted(exist_data.items()))) - pass - - -def add(): - argv = sys.argv - if len(argv) < 4 or argv[2] not in ['c', 'e', 'f']: - quit_with("add [c/e/f] [file_name]") - browser = argv[2] - file_path = argv[3] - if browser == 'c': - add_chrome(file_path) - elif browser == 'e': - add_edge(file_path) - elif browser == 'f': - add_firefox(file_path) - else: - pass - - -GIST_TOKEN_ENV = 'TIMER_USER_COUNT_GIST_TOKEN' -DESC = "User count of timer, auto-generated" - - -def upload2gist(): - argv = sys.argv - # 1. find token and svg file - token = argv[2] if len(argv) > 2 else os.environ.get(GIST_TOKEN_ENV) - if not token: - quit_with( - "Token is None, please input with command or set with environment TIMER_USER_COUNT_GIST_TOKEN" - ) - if not os.path.exists(svg_file_path): - quit_with('Svg file not found') - # 2. find exist gist file - token_header = 'Bearer {}'.format(token) - headers = { - "Accept": "application/vnd.github+json", - "Authorization": token_header - } - response = requests.get('https://api.github.com/gists', headers=headers) - status_code = response.status_code - if status_code != 200: - quit_with("Failed to list exist gists: statusCode={}".format(status_code)) - gist_list = json.loads(response.content) - exist_gist = next( - (gist for gist in gist_list if 'description' in gist and gist['description'] == DESC), - None - ) - svg_content = '' - with open(svg_file_path, 'r') as file: - svg_content = '\r\n'.join(file.readlines()) - if not svg_content: - quit_with("Failed to read svg file") - data = json.dumps({ - "description": DESC, - "public": True, - "files": { - "user_count.svg": { - "content": svg_content - } - } - }) - # 3. create new one or update - if not exist_gist: - print("Gist not found, so try to create one") - response = requests.post('https://api.github.com/gists', - data=data, headers=headers) - status_code = response.status_code - if status_code != 200 and status_code != 201: - quit_with( - 'Failed to create new gist: statusCode={}'.format(status_code) - ) - else: - print('Success to create new gist') - else: - gist_id = exist_gist['id'] - response = requests.post('https://api.github.com/gists/{}'.format(gist_id), - data=data, headers=headers) - status_code = response.status_code - if status_code != 200 and status_code != 201: - quit_with("Failed to update gist: id={}, statusCode={}".format( - gist_id, - status_code - )) - else: - print("Success to update gist") - - -def main(): - argv = sys.argv - if len(argv) == 1 or argv[1] not in ['render', 'add', 'upload']: - print("Supported command: render, add, upload") - quit() - - cmd = argv[1] - if cmd == 'render': - render() - elif cmd == 'add': - add() - elif cmd == 'upload': - render() - upload2gist() - else: - pass - - -if __name__ == '__main__': - main() diff --git a/tsconfig.json b/tsconfig.json index 27777ea1..af9f1dbc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -51,5 +51,11 @@ "node_modules", "dist" ], - "strict": true + "strict": true, + "ts-node": { + "files": true, + "require": [ + "tsconfig-paths/register" + ] + } } \ No newline at end of file