From 4c74a7c51dba31f43742cb3c1dd9b139ffbbbed6 Mon Sep 17 00:00:00 2001 From: jkre Date: Wed, 13 Dec 2023 22:51:40 +0100 Subject: Add current_now and voltage_now to battery struct and fix naming of current_now --- src/linux/btop_collect.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/linux/btop_collect.cpp b/src/linux/btop_collect.cpp index 33a0be8..68b8c58 100644 --- a/src/linux/btop_collect.cpp +++ b/src/linux/btop_collect.cpp @@ -661,9 +661,10 @@ namespace Cpu { } struct battery { - fs::path base_dir, energy_now, energy_full, power_now, status, online; + fs::path base_dir, energy_now, energy_full, power_now, current_now, voltage_now, status, online; string device_type; bool use_energy = true; + bool use_power = true; }; auto get_battery() -> tuple { @@ -710,8 +711,16 @@ namespace Cpu { continue; } - if (fs::exists(bat_dir / "power_now")) new_bat.power_now = bat_dir / "power_now"; - else if (fs::exists(bat_dir / "current_now")) new_bat.power_now = bat_dir / "current_now"; + if (fs::exists(bat_dir / "power_now")) { + new_bat.power_now = bat_dir / "power_now"; + } + else if ((fs::exists(bat_dir / "current_now")) and (fs::exists(bat_dir / "current_now"))) { + new_bat.current_now = bat_dir / "current_now"; + new_bat.voltage_now = bat_dir / "voltage_now"; + } + else { + new_bat.use_power = false; + } if (fs::exists(bat_dir / "AC0/online")) new_bat.online = bat_dir / "AC0/online"; else if (fs::exists(bat_dir / "AC/online")) new_bat.online = bat_dir / "AC/online"; -- cgit v1.2.3 From b99008f6267ebbcd700052d5349f4c4bac8b08c3 Mon Sep 17 00:00:00 2001 From: jkre Date: Wed, 13 Dec 2023 23:17:07 +0100 Subject: Introduce charge in addition to energy for laptops that use charge instead of energy, this is done so that the units make more sense in this case --- src/linux/btop_collect.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/linux/btop_collect.cpp b/src/linux/btop_collect.cpp index 68b8c58..1da9c4a 100644 --- a/src/linux/btop_collect.cpp +++ b/src/linux/btop_collect.cpp @@ -661,9 +661,9 @@ namespace Cpu { } struct battery { - fs::path base_dir, energy_now, energy_full, power_now, current_now, voltage_now, status, online; + fs::path base_dir, energy_now, charge_now, energy_full, charge_full, power_now, current_now, voltage_now, status, online; string device_type; - bool use_energy = true; + bool use_energy_or_charge = true; bool use_power = true; }; @@ -700,14 +700,14 @@ namespace Cpu { } if (fs::exists(bat_dir / "energy_now")) new_bat.energy_now = bat_dir / "energy_now"; - else if (fs::exists(bat_dir / "charge_now")) new_bat.energy_now = bat_dir / "charge_now"; - else new_bat.use_energy = false; + else if (fs::exists(bat_dir / "charge_now")) new_bat.charge_now = bat_dir / "charge_now"; + else new_bat.use_energy_or_charge = false; if (fs::exists(bat_dir / "energy_full")) new_bat.energy_full = bat_dir / "energy_full"; - else if (fs::exists(bat_dir / "charge_full")) new_bat.energy_full = bat_dir / "charge_full"; - else new_bat.use_energy = false; + else if (fs::exists(bat_dir / "charge_full")) new_bat.charge_full = bat_dir / "charge_full"; + else new_bat.use_energy_or_charge = false; - if (not new_bat.use_energy and not fs::exists(bat_dir / "capacity")) { + if (not new_bat.use_energy_or_charge and not fs::exists(bat_dir / "capacity")) { continue; } @@ -757,7 +757,7 @@ namespace Cpu { long seconds = -1; //? Try to get battery percentage - if (b.use_energy) { + if (b.use_energy_or_charge) { try { percent = round(100.0 * stoll(readfile(b.energy_now, "-1")) / stoll(readfile(b.energy_full, "1"))); } @@ -787,7 +787,7 @@ namespace Cpu { //? Get seconds to empty if (not is_in(status, "charging", "full")) { - if (b.use_energy and not b.power_now.empty()) { + if (b.use_energy_or_charge and not b.power_now.empty()) { try { seconds = round((double)stoll(readfile(b.energy_now, "0")) / stoll(readfile(b.power_now, "1")) * 3600); } -- cgit v1.2.3 From ee61700a4437afffd019264c50ad2a18cab75062 Mon Sep 17 00:00:00 2001 From: jkre Date: Wed, 13 Dec 2023 23:39:45 +0100 Subject: add case of calculating the remaining battery time for current/charge --- src/linux/btop_collect.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/linux/btop_collect.cpp b/src/linux/btop_collect.cpp index 1da9c4a..ae11f61 100644 --- a/src/linux/btop_collect.cpp +++ b/src/linux/btop_collect.cpp @@ -787,13 +787,23 @@ namespace Cpu { //? Get seconds to empty if (not is_in(status, "charging", "full")) { - if (b.use_energy_or_charge and not b.power_now.empty()) { - try { - seconds = round((double)stoll(readfile(b.energy_now, "0")) / stoll(readfile(b.power_now, "1")) * 3600); + if (b.use_energy_or_charge ) { + if (not b.power_now.empty()) { + try { + seconds = round((double)stoll(readfile(b.energy_now, "0")) / stoll(readfile(b.power_now, "1")) * 3600); + } + catch (const std::invalid_argument&) { } + catch (const std::out_of_range&) { } + } + else if (not b.current_now.empty()) { + try { + seconds = round((double)stoll(readfile(b.charge_now, "0")) / (double)stoll(readfile(b.current_now, "1")) * 3600); + } + catch (const std::invalid_argument&) { } + catch (const std::out_of_range&) { } } - catch (const std::invalid_argument&) { } - catch (const std::out_of_range&) { } } + if (seconds < 0 and fs::exists(b.base_dir / "time_to_empty")) { try { seconds = stoll(readfile(b.base_dir / "time_to_empty", "0")) * 60; -- cgit v1.2.3 From ab294bfc104d20e1178cb4c6bc4de2fd879cb892 Mon Sep 17 00:00:00 2001 From: jkre Date: Wed, 13 Dec 2023 23:51:18 +0100 Subject: add battery percentage calculation in charge case --- src/linux/btop_collect.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/linux/btop_collect.cpp b/src/linux/btop_collect.cpp index ae11f61..0d58596 100644 --- a/src/linux/btop_collect.cpp +++ b/src/linux/btop_collect.cpp @@ -764,6 +764,13 @@ namespace Cpu { catch (const std::invalid_argument&) { } catch (const std::out_of_range&) { } } + if (b.use_energy_or_charge == true and percent < 0) { + try { + percent = round(100.0 * stoll(readfile(b.charge_now, "-1")) / stoll(readfile(b.charge_full, "1"))); + } + catch (const std::invalid_argument&) { } + catch (const std::out_of_range&) { } + } if (percent < 0) { try { percent = stoll(readfile(b.base_dir / "capacity", "-1")); -- cgit v1.2.3 From f6d8c4a0447a7bb56f8717a6f21920bc6d7ba310 Mon Sep 17 00:00:00 2001 From: jkre Date: Wed, 13 Dec 2023 23:58:40 +0100 Subject: use capacity as default for battery percentage, less complicated and matches desktop percent exactly --- src/linux/btop_collect.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/linux/btop_collect.cpp b/src/linux/btop_collect.cpp index 0d58596..3961d91 100644 --- a/src/linux/btop_collect.cpp +++ b/src/linux/btop_collect.cpp @@ -757,23 +757,23 @@ namespace Cpu { long seconds = -1; //? Try to get battery percentage - if (b.use_energy_or_charge) { + if (percent < 0) { try { - percent = round(100.0 * stoll(readfile(b.energy_now, "-1")) / stoll(readfile(b.energy_full, "1"))); + percent = stoll(readfile(b.base_dir / "capacity", "-1")); } catch (const std::invalid_argument&) { } catch (const std::out_of_range&) { } } - if (b.use_energy_or_charge == true and percent < 0) { + if (b.use_energy_or_charge and percent < 0) { try { - percent = round(100.0 * stoll(readfile(b.charge_now, "-1")) / stoll(readfile(b.charge_full, "1"))); + percent = round(100.0 * stoll(readfile(b.energy_now, "-1")) / stoll(readfile(b.energy_full, "1"))); } catch (const std::invalid_argument&) { } catch (const std::out_of_range&) { } } - if (percent < 0) { + if (b.use_energy_or_charge == true and percent < 0) { try { - percent = stoll(readfile(b.base_dir / "capacity", "-1")); + percent = round(100.0 * stoll(readfile(b.charge_now, "-1")) / stoll(readfile(b.charge_full, "1"))); } catch (const std::invalid_argument&) { } catch (const std::out_of_range&) { } -- cgit v1.2.3 From b09f352c09c14788985e23cd01f2975b2443b810 Mon Sep 17 00:00:00 2001 From: jkre Date: Thu, 14 Dec 2023 00:16:15 +0100 Subject: clean up if statement for battery percent calculation --- src/linux/btop_collect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linux/btop_collect.cpp b/src/linux/btop_collect.cpp index 3961d91..212a165 100644 --- a/src/linux/btop_collect.cpp +++ b/src/linux/btop_collect.cpp @@ -771,7 +771,7 @@ namespace Cpu { catch (const std::invalid_argument&) { } catch (const std::out_of_range&) { } } - if (b.use_energy_or_charge == true and percent < 0) { + if (b.use_energy_or_charge and percent < 0) { try { percent = round(100.0 * stoll(readfile(b.charge_now, "-1")) / stoll(readfile(b.charge_full, "1"))); } -- cgit v1.2.3 From 419a7d4ca3889d97afc006f7301017a224e16396 Mon Sep 17 00:00:00 2001 From: jkre Date: Thu, 14 Dec 2023 00:32:06 +0100 Subject: add power draw calculation for battery --- src/linux/btop_collect.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/linux/btop_collect.cpp b/src/linux/btop_collect.cpp index 212a165..c00c563 100644 --- a/src/linux/btop_collect.cpp +++ b/src/linux/btop_collect.cpp @@ -755,6 +755,7 @@ namespace Cpu { int percent = -1; long seconds = -1; + float watts = -1; //? Try to get battery percentage if (percent < 0) { @@ -820,6 +821,25 @@ namespace Cpu { } } + //? Get power draw + if (b.use_power) { + if (not b.power_now.empty()) { + try { + watts = (float)stoll(readfile(b.energy_now, "-1")) / 1000000.0; + } + catch (const std::invalid_argument&) { } + catch (const std::out_of_range&) { } + } + else if (not b.voltage_now.empty() and not b.current_now.empty()) { + try { + watts = (float)stoll(readfile(b.current_now, "-1")) / 1000000.0 * stoll(readfile(b.voltage_now, "1")) / 1000000.0; + } + catch (const std::invalid_argument&) { } + catch (const std::out_of_range&) { } + } + + } + return {percent, seconds, status}; } -- cgit v1.2.3 From 6e575116fe45b0a48f873820bc9fe4486b827eed Mon Sep 17 00:00:00 2001 From: jkre Date: Thu, 14 Dec 2023 00:53:01 +0100 Subject: add power to get_battery function output --- src/btop_shared.hpp | 4 ++-- src/linux/btop_collect.cpp | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/btop_shared.hpp b/src/btop_shared.hpp index 017c7f8..eb5514c 100644 --- a/src/btop_shared.hpp +++ b/src/btop_shared.hpp @@ -178,7 +178,7 @@ namespace Cpu { extern string cpuName, cpuHz; extern vector available_fields; extern vector available_sensors; - extern tuple current_bat; + extern tuple current_bat; struct cpu_info { unordered_flat_map> cpu_percent = { @@ -213,7 +213,7 @@ namespace Cpu { auto get_cpuHz() -> string; //* Get battery info from /sys - auto get_battery() -> tuple; + auto get_battery() -> tuple; } namespace Mem { diff --git a/src/linux/btop_collect.cpp b/src/linux/btop_collect.cpp index c00c563..d88454a 100644 --- a/src/linux/btop_collect.cpp +++ b/src/linux/btop_collect.cpp @@ -291,7 +291,7 @@ namespace Cpu { string cpuName; string cpuHz; bool has_battery = true; - tuple current_bat; + tuple current_bat; const array time_names { "user"s, "nice"s, "system"s, "idle"s, "iowait"s, @@ -667,8 +667,8 @@ namespace Cpu { bool use_power = true; }; - auto get_battery() -> tuple { - if (not has_battery) return {0, 0, ""}; + auto get_battery() -> tuple { + if (not has_battery) return {0, 0, 0, ""}; static string auto_sel; static unordered_flat_map batteries; @@ -735,7 +735,7 @@ namespace Cpu { } if (batteries.empty()) { has_battery = false; - return {0, 0, ""}; + return {0, 0, 0, ""}; } } @@ -781,7 +781,7 @@ namespace Cpu { } if (percent < 0) { has_battery = false; - return {0, 0, ""}; + return {0, 0, 0, ""}; } //? Get charging/discharging status @@ -840,7 +840,7 @@ namespace Cpu { } - return {percent, seconds, status}; + return {percent, watts, seconds, status}; } auto collect(bool no_update) -> cpu_info& { -- cgit v1.2.3 From ddd4bec1c3eed40241fe22254770bc52e931bb88 Mon Sep 17 00:00:00 2001 From: jkre Date: Thu, 14 Dec 2023 00:54:29 +0100 Subject: Show wattage next to battery remaining time when wattage could be calculated --- src/btop_draw.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/btop_draw.cpp b/src/btop_draw.cpp index 5ae357e..dde135d 100644 --- a/src/btop_draw.cpp +++ b/src/btop_draw.cpp @@ -705,6 +705,7 @@ namespace Cpu { if (Config::getB("show_battery") and has_battery) { static int old_percent{}; // defaults to = 0 static long old_seconds{}; // defaults to = 0 + static float old_watts{}; // defaults to = 0 static string old_status; static Draw::Meter bat_meter {10, "cpu", true}; static const unordered_flat_map bat_symbols = { @@ -714,16 +715,18 @@ namespace Cpu { {"unknown", "○"} }; - const auto& [percent, seconds, status] = current_bat; + const auto& [percent, watts, seconds, status] = current_bat; - if (redraw or percent != old_percent or seconds != old_seconds or status != old_status) { + if (redraw or percent != old_percent or watts != old_watts or seconds != old_seconds or status != old_status) { old_percent = percent; + old_watts = watts; old_seconds = seconds; old_status = status; const string str_time = (seconds > 0 ? sec_to_dhms(seconds, true, true) : ""); const string str_percent = to_string(percent) + '%'; + const string str_watts = (watts != -1 ? to_string(watts) + 'W' : ""); const auto& bat_symbol = bat_symbols.at((bat_symbols.contains(status) ? status : "unknown")); - const int current_len = (Term::width >= 100 ? 11 : 0) + str_time.size() + str_percent.size() + to_string(Config::getI("update_ms")).size(); + const int current_len = (Term::width >= 100 ? 11 : 0) + str_time.size() + str_percent.size() + str_watts.size() + to_string(Config::getI("update_ms")).size(); const int current_pos = Term::width - current_len - 17; if ((bat_pos != current_pos or bat_len != current_len) and bat_pos > 0 and not redraw) @@ -733,7 +736,7 @@ namespace Cpu { out += Mv::to(y, bat_pos) + title_left + Theme::c("title") + Fx::b + "BAT" + bat_symbol + ' ' + str_percent + (Term::width >= 100 ? Fx::ub + ' ' + bat_meter(percent) + Fx::b : "") - + (not str_time.empty() ? ' ' + Theme::c("title") + str_time : " ") + Fx::ub + title_right; + + (not str_time.empty() ? ' ' + Theme::c("title") + str_time : " ") + (not str_watts.empty() ? ' ' + Theme::c("title") + Fx::b + str_watts : " ") + Fx::ub + title_right; } } else if (bat_pos > 0) { -- cgit v1.2.3 From 1ad1418771bd69c70674388d64a4965f9f7d0582 Mon Sep 17 00:00:00 2001 From: jkre Date: Thu, 14 Dec 2023 00:58:17 +0100 Subject: remove redundant space --- src/btop_draw.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/btop_draw.cpp b/src/btop_draw.cpp index dde135d..b5e75ec 100644 --- a/src/btop_draw.cpp +++ b/src/btop_draw.cpp @@ -736,7 +736,7 @@ namespace Cpu { out += Mv::to(y, bat_pos) + title_left + Theme::c("title") + Fx::b + "BAT" + bat_symbol + ' ' + str_percent + (Term::width >= 100 ? Fx::ub + ' ' + bat_meter(percent) + Fx::b : "") - + (not str_time.empty() ? ' ' + Theme::c("title") + str_time : " ") + (not str_watts.empty() ? ' ' + Theme::c("title") + Fx::b + str_watts : " ") + Fx::ub + title_right; + + (not str_time.empty() ? ' ' + Theme::c("title") + str_time : "") + (not str_watts.empty() ? ' ' + Theme::c("title") + Fx::b + str_watts : " ") + Fx::ub + title_right; } } else if (bat_pos > 0) { @@ -2239,3 +2239,4 @@ namespace Draw { } } } + -- cgit v1.2.3 From 7a188bfaaf19266b2d74336ca85ccb46fa0f111a Mon Sep 17 00:00:00 2001 From: jkre Date: Thu, 14 Dec 2023 01:39:00 +0100 Subject: round wattage to second decimal --- src/btop_draw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/btop_draw.cpp b/src/btop_draw.cpp index b5e75ec..9e49d1f 100644 --- a/src/btop_draw.cpp +++ b/src/btop_draw.cpp @@ -724,7 +724,7 @@ namespace Cpu { old_status = status; const string str_time = (seconds > 0 ? sec_to_dhms(seconds, true, true) : ""); const string str_percent = to_string(percent) + '%'; - const string str_watts = (watts != -1 ? to_string(watts) + 'W' : ""); + const string str_watts = (watts != -1 ? fmt::format("{:.2f}", watts) + 'W' : ""); const auto& bat_symbol = bat_symbols.at((bat_symbols.contains(status) ? status : "unknown")); const int current_len = (Term::width >= 100 ? 11 : 0) + str_time.size() + str_percent.size() + str_watts.size() + to_string(Config::getI("update_ms")).size(); const int current_pos = Term::width - current_len - 17; -- cgit v1.2.3 From 578b01e06b6e9bc94d6b20ec361a518ab466ec96 Mon Sep 17 00:00:00 2001 From: jkre Date: Thu, 14 Dec 2023 22:19:22 +0100 Subject: add show_battery_power option to menu --- src/btop_config.cpp | 3 +++ src/btop_menu.cpp | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/btop_config.cpp b/src/btop_config.cpp index 0f723b7..454429b 100644 --- a/src/btop_config.cpp +++ b/src/btop_config.cpp @@ -197,6 +197,8 @@ namespace Config { {"selected_battery", "#* Which battery to use if multiple are present. \"Auto\" for auto detection."}, + {"show_battery_watt" "#* Show power stats of battery next to charge indicator"}, + {"log_level", "#* Set loglevel for \"~/.config/btop/btop.log\" levels are: \"ERROR\" \"WARNING\" \"INFO\" \"DEBUG\".\n" "#* The level set includes all lower levels, i.e. \"DEBUG\" will show all logging info."}, #ifdef GPU_SUPPORT @@ -291,6 +293,7 @@ namespace Config { {"net_auto", true}, {"net_sync", true}, {"show_battery", true}, + {"show_battery_watts", true}, {"vim_keys", false}, {"tty_mode", false}, {"disk_free_priv", false}, diff --git a/src/btop_menu.cpp b/src/btop_menu.cpp index 206052f..5bbd524 100644 --- a/src/btop_menu.cpp +++ b/src/btop_menu.cpp @@ -354,6 +354,13 @@ namespace Menu { "Can be both batteries and UPS.", "", "\"Auto\" for auto detection."}, + {"show_battery_watts", + "Show battery power.", + "" + "Shows power consumed by device when not connected to power", + "Shows power charging power otherwise" + "", + "True or False."}, {"log_level", "Set loglevel for error.log", "", -- cgit v1.2.3 From 2934138a660ad0b80bde31e5c81f495d7b76dc13 Mon Sep 17 00:00:00 2001 From: jkre Date: Thu, 14 Dec 2023 22:56:31 +0100 Subject: Only redraw battery indicator on power change if power change option is set to true --- src/btop_draw.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/btop_draw.cpp b/src/btop_draw.cpp index 9e49d1f..ae9ba69 100644 --- a/src/btop_draw.cpp +++ b/src/btop_draw.cpp @@ -717,14 +717,14 @@ namespace Cpu { const auto& [percent, watts, seconds, status] = current_bat; - if (redraw or percent != old_percent or watts != old_watts or seconds != old_seconds or status != old_status) { + if (redraw or percent != old_percent or (watts != old_watts and Config::getB("show_battery_watts")) or seconds != old_seconds or status != old_status) { old_percent = percent; old_watts = watts; old_seconds = seconds; old_status = status; const string str_time = (seconds > 0 ? sec_to_dhms(seconds, true, true) : ""); const string str_percent = to_string(percent) + '%'; - const string str_watts = (watts != -1 ? fmt::format("{:.2f}", watts) + 'W' : ""); + const string str_watts = (watts != -1 and Config::getB("show_battery_watts") ? fmt::format("{:.2f}", watts) + 'W' : ""); const auto& bat_symbol = bat_symbols.at((bat_symbols.contains(status) ? status : "unknown")); const int current_len = (Term::width >= 100 ? 11 : 0) + str_time.size() + str_percent.size() + str_watts.size() + to_string(Config::getI("update_ms")).size(); const int current_pos = Term::width - current_len - 17; @@ -736,7 +736,7 @@ namespace Cpu { out += Mv::to(y, bat_pos) + title_left + Theme::c("title") + Fx::b + "BAT" + bat_symbol + ' ' + str_percent + (Term::width >= 100 ? Fx::ub + ' ' + bat_meter(percent) + Fx::b : "") - + (not str_time.empty() ? ' ' + Theme::c("title") + str_time : "") + (not str_watts.empty() ? ' ' + Theme::c("title") + Fx::b + str_watts : " ") + Fx::ub + title_right; + + (not str_time.empty() ? ' ' + Theme::c("title") + str_time : "") + (not str_watts.empty() ? " " + Theme::c("title") + Fx::b + str_watts : "") + Fx::ub + title_right; } } else if (bat_pos > 0) { -- cgit v1.2.3 From cd6c1b7294cfdabe234da13c45ba6613ed552eb5 Mon Sep 17 00:00:00 2001 From: jkre Date: Thu, 14 Dec 2023 23:27:19 +0100 Subject: make discribtion in menu and settings clearer --- src/btop_config.cpp | 2 +- src/btop_menu.cpp | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/btop_config.cpp b/src/btop_config.cpp index 454429b..5fed33f 100644 --- a/src/btop_config.cpp +++ b/src/btop_config.cpp @@ -197,7 +197,7 @@ namespace Config { {"selected_battery", "#* Which battery to use if multiple are present. \"Auto\" for auto detection."}, - {"show_battery_watt" "#* Show power stats of battery next to charge indicator"}, + {"show_battery_watts", "#* Show power stats of battery next to charge indicator."}, {"log_level", "#* Set loglevel for \"~/.config/btop/btop.log\" levels are: \"ERROR\" \"WARNING\" \"INFO\" \"DEBUG\".\n" "#* The level set includes all lower levels, i.e. \"DEBUG\" will show all logging info."}, diff --git a/src/btop_menu.cpp b/src/btop_menu.cpp index 5bbd524..5d1421f 100644 --- a/src/btop_menu.cpp +++ b/src/btop_menu.cpp @@ -356,11 +356,9 @@ namespace Menu { "\"Auto\" for auto detection."}, {"show_battery_watts", "Show battery power.", - "" - "Shows power consumed by device when not connected to power", - "Shows power charging power otherwise" "", - "True or False."}, + "Show discharge power when discharging.", + "Show charging power when charging."}, {"log_level", "Set loglevel for error.log", "", -- cgit v1.2.3 From a81b514d6df6eaff0293aa4ce869a429a1cde4b2 Mon Sep 17 00:00:00 2001 From: jkre Date: Fri, 15 Dec 2023 01:14:47 +0100 Subject: add freebsd support for battery power --- src/freebsd/btop_collect.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/freebsd/btop_collect.cpp b/src/freebsd/btop_collect.cpp index 7f93322..d678038 100644 --- a/src/freebsd/btop_collect.cpp +++ b/src/freebsd/btop_collect.cpp @@ -200,7 +200,7 @@ namespace Cpu { string cpuName; string cpuHz; bool has_battery = true; - tuple current_bat; + tuple current_bat; const array time_names = {"user", "nice", "system", "idle"}; @@ -366,10 +366,11 @@ namespace Cpu { return core_map; } - auto get_battery() -> tuple { - if (not has_battery) return {0, 0, ""}; + auto get_battery() -> tuple { + if (not has_battery) return {0, 0, 0, ""}; long seconds = -1; + float watts = -1; uint32_t percent = -1; size_t size = sizeof(percent); string status = "discharging"; @@ -381,6 +382,10 @@ namespace Cpu { if (sysctlbyname("hw.acpi.battery.time", &seconds, &size, nullptr, 0) < 0) { seconds = 0; } + size = sizeof(watts); + if (sysctlbyname("hw.acpi.battery.rate", &watts, &size, nullptr, 0) < 0) { + watts = -1; + } int state; size = sizeof(state); if (sysctlbyname("hw.acpi.battery.state", &state, &size, nullptr, 0) < 0) { @@ -395,7 +400,7 @@ namespace Cpu { } } - return {percent, seconds, status}; + return {percent, watts, seconds, status}; } auto collect(bool no_update) -> cpu_info & { -- cgit v1.2.3 From 0c706cd20a262531788469ca432ab0a09d75c852 Mon Sep 17 00:00:00 2001 From: jkre Date: Fri, 15 Dec 2023 01:28:57 +0100 Subject: make os compatible --- src/osx/btop_collect.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/osx/btop_collect.cpp b/src/osx/btop_collect.cpp index e410c74..118af83 100644 --- a/src/osx/btop_collect.cpp +++ b/src/osx/btop_collect.cpp @@ -187,7 +187,7 @@ namespace Cpu { string cpuHz; bool has_battery = true; bool macM1 = false; - tuple current_bat; + tuple current_bat; const array time_names = {"user", "nice", "system", "idle"}; @@ -398,8 +398,8 @@ namespace Cpu { ~IOPSList_Wrap() { CFRelease(data); } }; - auto get_battery() -> tuple { - if (not has_battery) return {0, 0, ""}; + auto get_battery() -> tuple { + if (not has_battery) return {0, 0, 0, ""}; uint32_t percent = -1; long seconds = -1; @@ -438,7 +438,7 @@ namespace Cpu { has_battery = false; } } - return {percent, seconds, status}; + return {percent, -1, seconds, status}; } auto collect(bool no_update) -> cpu_info & { -- cgit v1.2.3 From 6a6f514f8097ba65186f30c5ecd7a7a3bbcc8f2e Mon Sep 17 00:00:00 2001 From: "Helmut K. C. Tessarek" Date: Fri, 12 Jan 2024 11:28:42 -0500 Subject: fix: increase interface name length to 15 --- src/btop_draw.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/btop_draw.cpp b/src/btop_draw.cpp index acab14c..5e3cc5b 100644 --- a/src/btop_draw.cpp +++ b/src/btop_draw.cpp @@ -1361,6 +1361,7 @@ namespace Net { int x = 1, y, width = 20, height; int b_x, b_y, b_width, b_height, d_graph_height, u_graph_height; bool shown = true, redraw = true; + const int MAX_IFNAMSIZ = 15; string old_ip; std::unordered_map graphs; string box; @@ -1381,7 +1382,7 @@ namespace Net { out.reserve(width * height); const string title_left = Theme::c("net_box") + Fx::ub + Symbols::title_left; const string title_right = Theme::c("net_box") + Fx::ub + Symbols::title_right; - const int i_size = min((int)selected_iface.size(), 10); + const int i_size = min((int)selected_iface.size(), MAX_IFNAMSIZ); const long long down_max = (net_auto ? safeVal(graph_max, "download"s) : ((long long)(Config::getI("net_download")) << 20) / 8); const long long up_max = (net_auto ? safeVal(graph_max, "upload"s) : ((long long)(Config::getI("net_upload")) << 20) / 8); @@ -1403,7 +1404,7 @@ namespace Net { //? Interface selector and buttons out += Mv::to(y, x+width - i_size - 9) + title_left + Fx::b + Theme::c("hi_fg") + "" + title_right + + uresize(selected_iface, MAX_IFNAMSIZ) + Theme::c("hi_fg") + " n>" + title_right + Mv::to(y, x+width - i_size - 15) + title_left + Theme::c("hi_fg") + (safeVal(net.stat, "download"s).offset + safeVal(net.stat, "upload"s).offset > 0 ? Fx::b : "") + 'z' + Theme::c("title") + "ero" + title_right; Input::mouse_mappings["b"] = {y, x+width - i_size - 8, 1, 3}; -- cgit v1.2.3 From 05da55c54995147beb70bd590fd1e7bf29b329e7 Mon Sep 17 00:00:00 2001 From: Steffen Winter Date: Mon, 15 Jan 2024 15:55:04 +0100 Subject: Fix abort in locale detection on OpenBSD For whatever reason catch doesn't work for exceptions thrown in a dynamically linked library and the program aborts. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ed80899..30ce82d 100644 --- a/Makefile +++ b/Makefile @@ -143,7 +143,7 @@ else ifeq ($(PLATFORM_LC),macos) else ifeq ($(PLATFORM_LC),openbsd) PLATFORM_DIR := openbsd THREADS := $(shell sysctl -n hw.ncpu || echo 1) - override ADDFLAGS += -lkvm + override ADDFLAGS += -lkvm -static-libstdc++ export MAKE = gmake SU_GROUP := wheel else -- cgit v1.2.3 From cec251bf0569bdbf92ff2abfc85661ad030148f3 Mon Sep 17 00:00:00 2001 From: Steffen Winter Date: Mon, 15 Jan 2024 16:00:34 +0100 Subject: Allow the Findkvm module on all BSDs --- cmake/Modules/Findkvm.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/Findkvm.cmake b/cmake/Modules/Findkvm.cmake index a0847de..9e4d82b 100644 --- a/cmake/Modules/Findkvm.cmake +++ b/cmake/Modules/Findkvm.cmake @@ -3,7 +3,7 @@ # Find libkvm, the Kernel Data Access Library # -if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") +if(BSD) find_path(kvm_INCLUDE_DIR NAMES kvm.h) find_library(kvm_LIBRARY NAMES kvm) -- cgit v1.2.3 From 57752df6fc9691e359f549c6eb85673095da292c Mon Sep 17 00:00:00 2001 From: Steffen Winter Date: Mon, 15 Jan 2024 16:00:54 +0100 Subject: CMake: Enable OpenBSD --- CMakeLists.txt | 8 +++++++ README.md | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd39946..aec6782 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,8 @@ if(APPLE) target_sources(btop PRIVATE src/osx/btop_collect.cpp src/osx/sensors.cpp src/osx/smc.cpp) elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") target_sources(btop PRIVATE src/freebsd/btop_collect.cpp) +elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + target_sources(btop PRIVATE src/openbsd/btop_collect.cpp src/openbsd/sysctlbyname.cpp) elseif(LINUX) target_sources(btop PRIVATE src/linux/btop_collect.cpp) else() @@ -185,6 +187,12 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") find_package(kvm REQUIRED) target_link_libraries(btop elf::elf kvm::kvm) endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(btop PRIVATE -static-libstdc++) + endif() + find_package(kvm REQUIRED) + target_link_libraries(btop kvm::kvm) endif() install(TARGETS btop RUNTIME) diff --git a/README.md b/README.md index 9191071..e555784 100644 --- a/README.md +++ b/README.md @@ -995,6 +995,74 @@ If you have an AMD GPU `rocm_smi_lib` is required, which may or may not be packa gmake help ``` + +
+ + +### With CMake (Community maintained) + + +1. **Install build dependencies** + + Requires GCC, CMake, Ninja and Git + + _**Note:** LLVM's libc++ shipped with OpenBSD 7.4 is too old and cannot compile btop._ + + ```bash + pkg_add cmake g++%11 git ninja + ``` + +2. **Clone the repository** + + ```bash + git clone https://github.com/aristocratos/btop.git && cd btop + ``` + +3. **Compile** + + ```bash + # Configure + CXX=eg++ cmake -B build -G Ninja + # Build + cmake --build build + ``` + + This will automatically build a release version of btop. + + Some useful options to pass to the configure step: + + | Configure flag | Description | + |---------------------------------|-------------------------------------------------------------------------| + | `-DBTOP_LTO=` | Enables link time optimization (ON by default) | + | `-DBTOP_USE_MOLD=` | Use mold to link btop (OFF by default) | + | `-DBTOP_PEDANTIC=` | Compile with additional warnings (OFF by default) | + | `-DBTOP_WERROR=` | Compile with warnings as errors (OFF by default) | + | `-DBTOP_FORTIFY=` | Detect buffer overflows with `_FORTIFY_SOURCE=3` (ON by default) | + | `-DCMAKE_INSTALL_PREFIX=` | The installation prefix ('/usr/local' by default) | + + To force any other compiler, run `CXX= cmake -B build -G Ninja` + +4. **Install** + + ```bash + cmake --install build + ``` + + May require root privileges + +5. **Uninstall** + + CMake doesn't generate an uninstall target by default. To remove installed files, run + ``` + cat build/install_manifest.txt | xargs rm -irv + ``` + +6. **Cleanup build directory** + + ```bash + cmake --build build -t clean + ``` +
## Installing the snap -- cgit v1.2.3 From a44ce1c3a1036c376d105ee7aba81ba7e60c87ae Mon Sep 17 00:00:00 2001 From: Steffen Winter Date: Mon, 15 Jan 2024 19:23:47 +0100 Subject: Make BTOP_DEBUG also work for CMake --- src/btop_tools.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/btop_tools.hpp b/src/btop_tools.hpp index 705a5eb..766cc95 100644 --- a/src/btop_tools.hpp +++ b/src/btop_tools.hpp @@ -18,6 +18,10 @@ tab-size = 4 #pragma once +#if !defined(NDEBUG) +# define BTOP_DEBUG +#endif + #include // for std::ranges::count_if #include #include -- cgit v1.2.3 From 3174c83b43739995d119aa372d6a5f6d45b27b9e Mon Sep 17 00:00:00 2001 From: Steffen Winter Date: Mon, 15 Jan 2024 19:17:05 +0100 Subject: -DFMT_HEADER_ONLY as a compiler flag This just defines FMT_HEADER_ONLY everywhere instead of just in all files that include `btop_tools.hpp`, in case the statement gets removed there. --- CMakeLists.txt | 1 + Makefile | 2 +- src/btop.cpp | 1 + src/btop_tools.hpp | 4 +--- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd39946..df8d347 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,6 +110,7 @@ if(HAS_FCF_PROTECTION) endif() target_compile_definitions(btop PRIVATE + FMT_HEADER_ONLY _FILE_OFFSET_BITS=64 $<$:_GLIBCXX_ASSERTIONS _LIBCPP_ENABLE_ASSERTIONS=1> # Only has an effect with optimizations enabled diff --git a/Makefile b/Makefile index ed80899..3aae5d6 100644 --- a/Makefile +++ b/Makefile @@ -179,7 +179,7 @@ override GOODFLAGS := $(foreach flag,$(TESTFLAGS),$(strip $(shell echo "int main override REQFLAGS := -std=c++20 WARNFLAGS := -Wall -Wextra -pedantic OPTFLAGS := -O2 -ftree-vectorize -flto=$(LTO) -LDCXXFLAGS := -pthread -D_GLIBCXX_ASSERTIONS -D_FILE_OFFSET_BITS=64 $(GOODFLAGS) $(ADDFLAGS) +LDCXXFLAGS := -pthread -DFMT_HEADER_ONLY -D_GLIBCXX_ASSERTIONS -D_FILE_OFFSET_BITS=64 $(GOODFLAGS) $(ADDFLAGS) override CXXFLAGS += $(REQFLAGS) $(LDCXXFLAGS) $(OPTFLAGS) $(WARNFLAGS) override LDFLAGS += $(LDCXXFLAGS) $(OPTFLAGS) $(WARNFLAGS) INC := $(foreach incdir,$(INCDIRS),-isystem $(incdir)) -I$(SRCDIR) diff --git a/src/btop.cpp b/src/btop.cpp index 736854f..aac8e9c 100644 --- a/src/btop.cpp +++ b/src/btop.cpp @@ -53,6 +53,7 @@ tab-size = 4 #include "btop_draw.hpp" #include "btop_menu.hpp" #include "fmt/core.h" +#include "fmt/ostream.h" using std::atomic; using std::cout; diff --git a/src/btop_tools.hpp b/src/btop_tools.hpp index 705a5eb..708fddf 100644 --- a/src/btop_tools.hpp +++ b/src/btop_tools.hpp @@ -42,11 +42,9 @@ tab-size = 4 #define HOST_NAME_MAX 64 #endif #endif -#define FMT_HEADER_ONLY + #include "fmt/core.h" #include "fmt/format.h" -#include "fmt/ostream.h" -#include "fmt/ranges.h" using std::array; using std::atomic; -- cgit v1.2.3 From 61105e46b77f81dfcfbc968f8f6eb9b89d4a541e Mon Sep 17 00:00:00 2001 From: jkre Date: Mon, 22 Jan 2024 22:20:33 +0100 Subject: Add battery power draw to battery inforamtion tuple for openbsd and set it to a constant --- src/openbsd/btop_collect.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/openbsd/btop_collect.cpp b/src/openbsd/btop_collect.cpp index df35662..c0f7b9f 100644 --- a/src/openbsd/btop_collect.cpp +++ b/src/openbsd/btop_collect.cpp @@ -385,8 +385,8 @@ namespace Cpu { return core_map; } - auto get_battery() -> tuple { - if (not has_battery) return {0, 0, ""}; + auto get_battery() -> tuple { + if (not has_battery) return {0, 0, 0, ""}; long seconds = -1; uint32_t percent = -1; @@ -417,7 +417,7 @@ namespace Cpu { } } - return {percent, seconds, status}; + return {percent, -1, seconds, status}; } auto collect(bool no_update) -> cpu_info & { -- cgit v1.2.3 From c750543950304d8828e21ab5c6e2976c0c54235d Mon Sep 17 00:00:00 2001 From: jkre Date: Mon, 22 Jan 2024 22:32:16 +0100 Subject: Fix missing value in battery status tuple for openbsd --- src/openbsd/btop_collect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openbsd/btop_collect.cpp b/src/openbsd/btop_collect.cpp index c0f7b9f..3784ea9 100644 --- a/src/openbsd/btop_collect.cpp +++ b/src/openbsd/btop_collect.cpp @@ -202,7 +202,7 @@ namespace Cpu { string cpuName; string cpuHz; bool has_battery = true; - tuple current_bat; + tuple current_bat; const array time_names = {"user", "nice", "system", "idle"}; -- cgit v1.2.3 From 81d09860f7b815a662c5192e36fcf5e83b3729f6 Mon Sep 17 00:00:00 2001 From: rliang <48518695+rkmcode@users.noreply.github.com> Date: Thu, 25 Jan 2024 03:36:15 +0800 Subject: Fix basic_string::_M_create exception when 1000>hz>999.5, round(hz)=1000 btop_draw.cpp: 793: Symbols::h_line * (7 - cpuHz.size()) exception --- src/linux/btop_collect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linux/btop_collect.cpp b/src/linux/btop_collect.cpp index 0c1ab66..5e0af36 100644 --- a/src/linux/btop_collect.cpp +++ b/src/linux/btop_collect.cpp @@ -583,7 +583,7 @@ namespace Cpu { cpuhz += " GHz"; } else if (hz > 0) - cpuhz = to_string((int)round(hz)) + " MHz"; + cpuhz = to_string((int)hz) + " MHz"; } catch (const std::exception& e) { -- cgit v1.2.3 From 69363487bc3888cb5d975409f890a4ef4b51a8a2 Mon Sep 17 00:00:00 2001 From: Steven Ward Date: Tue, 30 Jan 2024 20:12:58 -0500 Subject: Write newline at end of config file --- src/btop_config.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/btop_config.cpp b/src/btop_config.cpp index 18e60ae..3bff815 100644 --- a/src/btop_config.cpp +++ b/src/btop_config.cpp @@ -729,9 +729,9 @@ namespace Config { if (geteuid() != Global::real_uid and seteuid(Global::real_uid) != 0) return; std::ofstream cwrite(conf_file, std::ios::trunc); if (cwrite.good()) { - cwrite << "#? Config file for btop v. " << Global::Version; + cwrite << "#? Config file for btop v. " << Global::Version << "\n"; for (auto [name, description] : descriptions) { - cwrite << "\n\n" << (description.empty() ? "" : description + "\n") + cwrite << "\n" << (description.empty() ? "" : description + "\n") << name << " = "; if (strings.contains(name)) cwrite << "\"" << strings.at(name) << "\""; @@ -739,6 +739,7 @@ namespace Config { cwrite << ints.at(name); else if (bools.contains(name)) cwrite << (bools.at(name) ? "True" : "False"); + cwrite << "\n"; } } } -- cgit v1.2.3 From bc0eb4291f353a97f6087b55eccc9e70ae7da58d Mon Sep 17 00:00:00 2001 From: Mathieu Sviridov <74146348+M-Sviridov@users.noreply.github.com> Date: Fri, 2 Feb 2024 12:49:30 +1100 Subject: Add theme based on Everforest Dark Medium palette --- themes/everforest-dark-medium.theme | 92 +++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 themes/everforest-dark-medium.theme diff --git a/themes/everforest-dark-medium.theme b/themes/everforest-dark-medium.theme new file mode 100644 index 0000000..f6aeadf --- /dev/null +++ b/themes/everforest-dark-medium.theme @@ -0,0 +1,92 @@ +# All graphs and meters can be gradients +# For single color graphs leave "mid" and "end" variable empty. +# Use "start" and "end" variables for two color gradient +# Use "start", "mid" and "end" for three color gradient + +# Main background, empty for terminal default, need to be empty if you want transparent background +theme[main_bg]="#2d353b" + +# Main text color +theme[main_fg]="#d3c6aa" + +# Title color for boxes +theme[title]="#d3c6aa" + +# Highlight color for keyboard shortcuts +theme[hi_fg]="#e67e80" + +# Background color of selected items +theme[selected_bg]="#3d484d" + +# Foreground color of selected items +theme[selected_fg]="#dbbc7f" + +# Color of inactive/disabled text +theme[inactive_fg]="#2d353b" + +# Color of text appearing on top of graphs, i.e uptime and current network graph scaling +theme[graph_text]="#d3c6aa" + +# Misc colors for processes box including mini cpu graphs, details memory graph and details status text +theme[proc_misc]="#a7c080" + +# Cpu box outline color +theme[cpu_box]="#3d484d" + +# Memory/disks box outline color +theme[mem_box]="#3d484d" + +# Net up/down box outline color +theme[net_box]="#3d484d" + +# Processes box outline color +theme[proc_box]="#3d484d" + +# Box divider line and small boxes line color +theme[div_line]="#3d484d" + +# Temperature graph colors +theme[temp_start]="#a7c080" +theme[temp_mid]="#dbbc7f" +theme[temp_end]="#f85552" + +# CPU graph colors +theme[cpu_start]="#a7c080" +theme[cpu_mid]="#dbbc7f" +theme[cpu_end]="#f85552" + +# Mem/Disk free meter +theme[free_start]="#f85552" +theme[free_mid]="#dbbc7f" +theme[free_end]="#a7c080" + +# Mem/Disk cached meter +theme[cached_start]="#7fbbb3" +theme[cached_mid]="#83c092" +theme[cached_end]="#a7c080" + +# Mem/Disk available meter +theme[available_start]="#f85552" +theme[available_mid]="#dbbc7f" +theme[available_end]="#a7c080" + +# Mem/Disk used meter +theme[used_start]="#a7c080" +theme[used_mid]="#dbbc7f" +theme[used_end]="#f85552" + +# Download graph colors +theme[download_start]="#a7c080" +theme[download_mid]="#83c092" +theme[download_end]="#7fbbb3" + +# Upload graph colors +theme[upload_start]="#dbbc7f" +theme[upload_mid]="#e69875" +theme[upload_end]="#e67e80" + +# Process box color gradient for threads, mem and cpu usage +theme[process_start]="#a7c080" +theme[process_mid]="#e67e80" +theme[process_end]="#f85552" + -- cgit v1.2.3 a id='n1184' href='#n1184'>1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771