diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index f2d8c6dd..746db552 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -152,7 +152,8 @@ Makefile @thiagokokada
/modules/programs/i3status.nix @JustinLovinger
-/modules/programs/i3status-rust.nix @workflow
+/modules/programs/i3status-rust.nix @workflow @thiagokokada
+/tests/modules/programs/i3status-rust @thiagokokada
/modules/programs/ion.nix @jo1gi
diff --git a/modules/misc/news.nix b/modules/misc/news.nix
index 74b87706..0b9af543 100644
--- a/modules/misc/news.nix
+++ b/modules/misc/news.nix
@@ -931,6 +931,23 @@ in
A new module is available: 'services.avizo'.
'';
}
+
+ {
+ time = "2023-03-16:12:00+00:00";
+ condition = config.programs.i3status-rust.enable;
+ message = ''
+ Module 'i3status-rust' was updated to support the new configuration
+ format from 0.30.x releases, that introduces many breaking changes.
+ The documentation was updated with examples from 0.30.x to help
+ the transition.
+
+ See https://github.com/greshake/i3status-rust/blob/v0.30.0/NEWS.md
+ for instructions on how to migrate.
+
+ Users that don't want to migrate yet can set
+ 'programs.i3status-rust.package' to an older version.
+ '';
+ }
];
};
}
diff --git a/modules/programs/i3status-rust.nix b/modules/programs/i3status-rust.nix
index 33f2b146..b0363693 100644
--- a/modules/programs/i3status-rust.nix
+++ b/modules/programs/i3status-rust.nix
@@ -9,7 +9,7 @@ let
settingsFormat = pkgs.formats.toml { };
in {
- meta.maintainers = [ maintainers.farlion ];
+ meta.maintainers = with lib.maintainers; [ farlion thiagokokada ];
options.programs.i3status-rust = {
enable = mkEnableOption "a replacement for i3-status written in Rust";
@@ -21,36 +21,32 @@ in {
blocks = mkOption {
type = settingsFormat.type;
default = [
+ { block = "cpu"; }
{
block = "disk_space";
path = "/";
- alias = "/";
info_type = "available";
- unit = "GB";
- interval = 60;
+ interval = 20;
warning = 20.0;
alert = 10.0;
+ format = " $icon root: $available.eng(w:2) ";
}
{
block = "memory";
- display_type = "memory";
- format_mem = "{mem_used_percents}";
- format_swap = "{swap_used_percents}";
+ format = " $icon $mem_total_used_percents.eng(w:2) ";
+ format_alt = " $icon_swap $swap_used_percents.eng(w:2) ";
}
{
- block = "cpu";
- interval = 1;
+ block = "sound";
+ click = [{
+ button = "left";
+ cmd = "pavucontrol";
+ }];
}
- {
- block = "load";
- interval = 1;
- format = "{1m}";
- }
- { block = "sound"; }
{
block = "time";
- interval = 60;
- format = "%a %d/%m %R";
+ interval = 5;
+ format = " $timestamp.datetime(f:'%a %d/%m %R') ";
}
];
description = ''
@@ -64,20 +60,23 @@ in {
{
block = "disk_space";
path = "/";
- alias = "/";
info_type = "available";
- unit = "GB";
interval = 60;
warning = 20.0;
alert = 10.0;
}
{
block = "sound";
- format = "{output_name} {volume}%";
- on_click = "pavucontrol --tab=3";
+ format = " $icon $output_name {$volume.eng(w:2) |}";
+ click = [
+ {
+ button = "left";
+ cmd = "pavucontrol --tab=3";
+ }
+ ];
mappings = {
- "alsa_output.pci-0000_00_1f.3.analog-stereo" = "";
- "bluez_sink.70_26_05_DA_27_A4.a2dp_sink" = "";
+ "alsa_output.pci-0000_00_1f.3.analog-stereo" = "";
+ "bluez_sink.70_26_05_DA_27_A4.a2dp_sink" = "";
};
}
];
@@ -94,7 +93,7 @@ in {
example = literalExpression ''
{
theme = {
- name = "solarized-dark";
+ theme = "solarized-dark";
overrides = {
idle_bg = "#123456";
idle_fg = "#abcdef";
@@ -109,10 +108,10 @@ in {
default = "none";
description = ''
The icons set to use. See
-
+
for a list of available icon sets.
'';
- example = "awesome5";
+ example = "awesome6";
};
theme = mkOption {
@@ -120,7 +119,7 @@ in {
default = "plain";
description = ''
The theme to use. See
-
+
for a list of available themes.
'';
example = "gruvbox-dark";
@@ -134,18 +133,15 @@ in {
{
block = "disk_space";
path = "/";
- alias = "/";
info_type = "available";
- unit = "GB";
interval = 60;
warning = 20.0;
alert = 10.0;
}
{
block = "memory";
- display_type = "memory";
- format_mem = "{mem_used_percents}";
- format_swap = "{swap_used_percents}";
+ format = " $icon mem_used_percents ";
+ format_alt = " $icon $swap_used_percents ";
}
{
block = "cpu";
@@ -154,13 +150,13 @@ in {
{
block = "load";
interval = 1;
- format = "{1m}";
+ format = " $icon $1m ";
}
{ block = "sound"; }
{
block = "time";
interval = 60;
- format = "%a %d/%m %R";
+ format = " $timestamp.datetime(f:'%a %d/%m %R') ";
}
];
};
@@ -187,18 +183,15 @@ in {
{
block = "disk_space";
path = "/";
- alias = "/";
info_type = "available";
- unit = "GB";
interval = 60;
warning = 20.0;
alert = 10.0;
}
{
block = "memory";
- display_type = "memory";
- format_mem = "{mem_used_percents}";
- format_swap = "{swap_used_percents}";
+ format_mem = " $icon $mem_used_percents ";
+ format_swap = " $icon $swap_used_percents ";
}
{
block = "cpu";
@@ -207,18 +200,18 @@ in {
{
block = "load";
interval = 1;
- format = "{1m}";
+ format = " $icon $1m ";
}
{ block = "sound"; }
{
block = "time";
interval = 60;
- format = "%a %d/%m %R";
+ format = " $timestamp.datetime(f:'%a %d/%m %R') ";
}
];
settings = {
theme = {
- name = "solarized-dark";
+ theme = "solarized-dark";
overrides = {
idle_bg = "#123456";
idle_fg = "#abcdef";
@@ -248,7 +241,7 @@ in {
home.packages = [ cfg.package ];
- xdg.configFile = mapAttrs' (cfgFileSuffix: cfg:
+ xdg.configFile = mapAttrs' (cfgFileSuffix: cfgBar:
nameValuePair ("i3status-rust/config-${cfgFileSuffix}.toml") ({
onChange = mkIf config.xsession.windowManager.i3.enable ''
i3Socket="''${XDG_RUNTIME_DIR:-/run/user/$UID}/i3/ipc-socket.*"
@@ -258,10 +251,16 @@ in {
'';
source = settingsFormat.generate ("config-${cfgFileSuffix}.toml") ({
- theme = cfg.theme;
- icons = cfg.icons;
- block = cfg.blocks;
- } // cfg.settings);
+ theme = if lib.versionAtLeast cfg.package.version "0.30.0" then {
+ theme = cfgBar.theme;
+ } else
+ cfgBar.theme;
+ icons = if lib.versionAtLeast cfg.package.version "0.30.0" then {
+ icons = cfgBar.icons;
+ } else
+ cfgBar.icons;
+ block = cfgBar.blocks;
+ } // cfgBar.settings);
})) cfg.bars;
};
}
diff --git a/tests/modules/programs/i3status-rust/default.nix b/tests/modules/programs/i3status-rust/default.nix
index 50d8c7b8..4002f4b4 100644
--- a/tests/modules/programs/i3status-rust/default.nix
+++ b/tests/modules/programs/i3status-rust/default.nix
@@ -3,4 +3,5 @@
i3status-rust-with-custom = ./with-custom.nix;
i3status-rust-with-extra-settings = ./with-extra-settings.nix;
i3status-rust-with-multiple-bars = ./with-multiple-bars.nix;
+ i3status-rust-with-version-02xx = ./with-version-02xx.nix;
}
diff --git a/tests/modules/programs/i3status-rust/with-custom.nix b/tests/modules/programs/i3status-rust/with-custom.nix
index c4131e02..46887a58 100644
--- a/tests/modules/programs/i3status-rust/with-custom.nix
+++ b/tests/modules/programs/i3status-rust/with-custom.nix
@@ -1,7 +1,5 @@
{ config, lib, pkgs, ... }:
-with lib;
-
{
config = {
programs.i3status-rust = {
@@ -12,9 +10,7 @@ with lib;
{
block = "disk_space";
path = "/";
- alias = "/";
info_type = "available";
- unit = "GB";
interval = 60;
warning = 20.0;
alert = 10.0;
@@ -28,34 +24,27 @@ with lib;
{
block = "cpu";
interval = 1;
- format = "{barchart}";
+ format = " $icon $barchart ";
}
{
block = "load";
interval = 1;
- format = "{1m} {5m}";
+ format = " $icon $1m $5m ";
}
{
block = "temperature";
- collapsed = true;
interval = 10;
- format = "{min}° min, {max}° max, {average}° avg";
+ format = "$icon $min min, $max max, $average avg";
chip = "*-isa-*";
}
- {
- block = "networkmanager";
- ap_format = "{ssid} @ {strength}%";
- on_click = "kcmshell5 kcm_networkmanagement";
- }
{
block = "net";
device = "enp9s0u2u1u2c2";
- speed_up = true;
interval = 5;
}
{
block = "speedtest";
- bytes = true;
+ format = " ^icon_ping $ping ";
}
{
block = "xrandr";
@@ -65,7 +54,10 @@ with lib;
{
block = "sound";
format = "{output_name} {volume}%";
- on_click = "pavucontrol --tab=3";
+ click = [{
+ button = "left";
+ cmd = "pavucontrol --tab=3";
+ }];
mappings = {
"alsa_output.pci-0000_00_1f.3.analog-stereo" = "";
"bluez_sink.70_26_05_DA_27_A4.a2dp_sink" = "";
@@ -75,12 +67,25 @@ with lib;
block = "music";
player = "spotify";
buttons = [ "play" "prev" "next" ];
- on_collapsed_click = "i3-msg '[class=Spotify] focus'";
+ click = [
+ {
+ button = "play";
+ action = "music_play";
+ }
+ {
+ button = "prev";
+ action = "music_prev";
+ }
+ {
+ button = "next";
+ action = "music_next";
+ }
+ ];
}
{
block = "time";
interval = 60;
- format = "%a %d.%m %R";
+ format = " $timestamp.datetime(f:'%a %d/%m %R') ";
}
{ block = "battery"; }
];
@@ -92,23 +97,19 @@ with lib;
};
};
- test.stubs.i3status-rust = { };
+ test.stubs.i3status-rust = { version = "0.30.0"; };
nmt.script = ''
assertFileExists home-files/.config/i3status-rust/config-custom.toml
assertFileContent home-files/.config/i3status-rust/config-custom.toml \
${
pkgs.writeText "i3status-rust-expected-config" ''
- icons = "awesome5"
- theme = "gruvbox-dark"
[[block]]
alert = 10.0
- alias = "/"
block = "disk_space"
info_type = "available"
interval = 60
path = "/"
- unit = "GB"
warning = 20.0
[[block]]
@@ -119,35 +120,28 @@ with lib;
[[block]]
block = "cpu"
- format = "{barchart}"
+ format = " $icon $barchart "
interval = 1
[[block]]
block = "load"
- format = "{1m} {5m}"
+ format = " $icon $1m $5m "
interval = 1
[[block]]
block = "temperature"
chip = "*-isa-*"
- collapsed = true
- format = "{min}° min, {max}° max, {average}° avg"
+ format = "$icon $min min, $max max, $average avg"
interval = 10
- [[block]]
- ap_format = "{ssid} @ {strength}%"
- block = "networkmanager"
- on_click = "kcmshell5 kcm_networkmanagement"
-
[[block]]
block = "net"
device = "enp9s0u2u1u2c2"
interval = 5
- speed_up = true
[[block]]
block = "speedtest"
- bytes = true
+ format = " ^icon_ping $ping "
[[block]]
block = "xrandr"
@@ -156,7 +150,10 @@ with lib;
[[block]]
block = "sound"
format = "{output_name} {volume}%"
- on_click = "pavucontrol --tab=3"
+
+ [[block.click]]
+ button = "left"
+ cmd = "pavucontrol --tab=3"
[block.mappings]
"alsa_output.pci-0000_00_1f.3.analog-stereo" = ""
@@ -165,16 +162,33 @@ with lib;
[[block]]
block = "music"
buttons = ["play", "prev", "next"]
- on_collapsed_click = "i3-msg '[class=Spotify] focus'"
player = "spotify"
+ [[block.click]]
+ action = "music_play"
+ button = "play"
+
+ [[block.click]]
+ action = "music_prev"
+ button = "prev"
+
+ [[block.click]]
+ action = "music_next"
+ button = "next"
+
[[block]]
block = "time"
- format = "%a %d.%m %R"
+ format = " $timestamp.datetime(f:'%a %d/%m %R') "
interval = 60
[[block]]
block = "battery"
+
+ [icons]
+ icons = "awesome5"
+
+ [theme]
+ theme = "gruvbox-dark"
''
}
'';
diff --git a/tests/modules/programs/i3status-rust/with-default.nix b/tests/modules/programs/i3status-rust/with-default.nix
index b5c20cee..4d10ceea 100644
--- a/tests/modules/programs/i3status-rust/with-default.nix
+++ b/tests/modules/programs/i3status-rust/with-default.nix
@@ -1,35 +1,28 @@
{ config, lib, pkgs, ... }:
-with lib;
-
{
config = {
programs.i3status-rust = { enable = true; };
- test.stubs.i3status-rust = { };
+ test.stubs.i3status-rust = { version = "0.30.0"; };
nmt.script = ''
assertFileExists home-files/.config/i3status-rust/config-default.toml
assertFileContent home-files/.config/i3status-rust/config-default.toml \
${
pkgs.writeText "i3status-rust-expected-config" ''
- icons = "none"
- theme = "plain"
[[block]]
alert = 10.0
- alias = "/"
block = "disk_space"
info_type = "available"
interval = 60
path = "/"
- unit = "GB"
warning = 20.0
[[block]]
block = "memory"
- display_type = "memory"
- format_mem = "{mem_used_percents}"
- format_swap = "{swap_used_percents}"
+ format = " $icon mem_used_percents "
+ format_alt = " $icon $swap_used_percents "
[[block]]
block = "cpu"
@@ -37,7 +30,7 @@ with lib;
[[block]]
block = "load"
- format = "{1m}"
+ format = " $icon $1m "
interval = 1
[[block]]
@@ -45,8 +38,14 @@ with lib;
[[block]]
block = "time"
- format = "%a %d/%m %R"
+ format = " $timestamp.datetime(f:'%a %d/%m %R') "
interval = 60
+
+ [icons]
+ icons = "none"
+
+ [theme]
+ theme = "plain"
''
}
'';
diff --git a/tests/modules/programs/i3status-rust/with-extra-settings.nix b/tests/modules/programs/i3status-rust/with-extra-settings.nix
index aad7618e..0d8b4663 100644
--- a/tests/modules/programs/i3status-rust/with-extra-settings.nix
+++ b/tests/modules/programs/i3status-rust/with-extra-settings.nix
@@ -1,7 +1,5 @@
{ config, lib, pkgs, ... }:
-with lib;
-
{
config = {
programs.i3status-rust = {
@@ -12,9 +10,7 @@ with lib;
{
block = "disk_space";
path = "/";
- alias = "/";
info_type = "available";
- unit = "GB";
interval = 60;
warning = 20.0;
alert = 10.0;
@@ -28,34 +24,27 @@ with lib;
{
block = "cpu";
interval = 1;
- format = "{barchart}";
+ format = " $icon $barchart ";
}
{
block = "load";
interval = 1;
- format = "{1m} {5m}";
+ format = " $icon $1m $5m ";
}
{
block = "temperature";
- collapsed = true;
interval = 10;
- format = "{min}° min, {max}° max, {average}° avg";
+ format = "$icon $min min, $max max, $average avg";
chip = "*-isa-*";
}
- {
- block = "networkmanager";
- ap_format = "{ssid} @ {strength}%";
- on_click = "kcmshell5 kcm_networkmanagement";
- }
{
block = "net";
device = "enp9s0u2u1u2c2";
- speed_up = true;
interval = 5;
}
{
block = "speedtest";
- bytes = true;
+ format = " ^icon_ping $ping ";
}
{
block = "xrandr";
@@ -65,7 +54,10 @@ with lib;
{
block = "sound";
format = "{output_name} {volume}%";
- on_click = "pavucontrol --tab=3";
+ click = [{
+ button = "left";
+ cmd = "pavucontrol --tab=3";
+ }];
mappings = {
"alsa_output.pci-0000_00_1f.3.analog-stereo" = "";
"bluez_sink.70_26_05_DA_27_A4.a2dp_sink" = "";
@@ -75,12 +67,25 @@ with lib;
block = "music";
player = "spotify";
buttons = [ "play" "prev" "next" ];
- on_collapsed_click = "i3-msg '[class=Spotify] focus'";
+ click = [
+ {
+ button = "play";
+ action = "music_play";
+ }
+ {
+ button = "prev";
+ action = "music_prev";
+ }
+ {
+ button = "next";
+ action = "music_next";
+ }
+ ];
}
{
block = "time";
interval = 60;
- format = "%a %d.%m %R";
+ format = " $timestamp.datetime(f:'%a %d/%m %R') ";
}
{ block = "battery"; }
];
@@ -89,7 +94,7 @@ with lib;
settings = {
theme = {
- name = "solarized-dark";
+ theme = "solarized-dark";
overrides = {
idle_bg = "#123456";
idle_fg = "#abcdef";
@@ -102,22 +107,19 @@ with lib;
};
};
- test.stubs.i3status-rust = { };
+ test.stubs.i3status-rust = { version = "0.30.0"; };
nmt.script = ''
assertFileExists home-files/.config/i3status-rust/config-extra-settings.toml
assertFileContent home-files/.config/i3status-rust/config-extra-settings.toml \
${
pkgs.writeText "i3status-rust-expected-config" ''
- icons = "awesome5"
[[block]]
alert = 10.0
- alias = "/"
block = "disk_space"
info_type = "available"
interval = 60
path = "/"
- unit = "GB"
warning = 20.0
[[block]]
@@ -128,35 +130,28 @@ with lib;
[[block]]
block = "cpu"
- format = "{barchart}"
+ format = " $icon $barchart "
interval = 1
[[block]]
block = "load"
- format = "{1m} {5m}"
+ format = " $icon $1m $5m "
interval = 1
[[block]]
block = "temperature"
chip = "*-isa-*"
- collapsed = true
- format = "{min}° min, {max}° max, {average}° avg"
+ format = "$icon $min min, $max max, $average avg"
interval = 10
- [[block]]
- ap_format = "{ssid} @ {strength}%"
- block = "networkmanager"
- on_click = "kcmshell5 kcm_networkmanagement"
-
[[block]]
block = "net"
device = "enp9s0u2u1u2c2"
interval = 5
- speed_up = true
[[block]]
block = "speedtest"
- bytes = true
+ format = " ^icon_ping $ping "
[[block]]
block = "xrandr"
@@ -165,7 +160,10 @@ with lib;
[[block]]
block = "sound"
format = "{output_name} {volume}%"
- on_click = "pavucontrol --tab=3"
+
+ [[block.click]]
+ button = "left"
+ cmd = "pavucontrol --tab=3"
[block.mappings]
"alsa_output.pci-0000_00_1f.3.analog-stereo" = ""
@@ -174,19 +172,33 @@ with lib;
[[block]]
block = "music"
buttons = ["play", "prev", "next"]
- on_collapsed_click = "i3-msg '[class=Spotify] focus'"
player = "spotify"
+ [[block.click]]
+ action = "music_play"
+ button = "play"
+
+ [[block.click]]
+ action = "music_prev"
+ button = "prev"
+
+ [[block.click]]
+ action = "music_next"
+ button = "next"
+
[[block]]
block = "time"
- format = "%a %d.%m %R"
+ format = " $timestamp.datetime(f:'%a %d/%m %R') "
interval = 60
[[block]]
block = "battery"
+ [icons]
+ icons = "awesome5"
+
[theme]
- name = "solarized-dark"
+ theme = "solarized-dark"
[theme.overrides]
idle_bg = "#123456"
diff --git a/tests/modules/programs/i3status-rust/with-multiple-bars.nix b/tests/modules/programs/i3status-rust/with-multiple-bars.nix
index a8ffd373..2a56d6a9 100644
--- a/tests/modules/programs/i3status-rust/with-multiple-bars.nix
+++ b/tests/modules/programs/i3status-rust/with-multiple-bars.nix
@@ -1,7 +1,5 @@
{ config, lib, pkgs, ... }:
-with lib;
-
{
config = {
programs.i3status-rust = {
@@ -13,19 +11,15 @@ with lib;
blocks = [
{
block = "disk_space";
- path = "/";
- alias = "/";
info_type = "available";
- unit = "GB";
interval = 60;
warning = 20.0;
alert = 10.0;
}
{
block = "memory";
- display_type = "memory";
- format_mem = "{Mug}GB ({Mup}%)";
- format_swap = "{SUp}%";
+ format_mem = " $icon $Mug ($Mup) ";
+ format_swap = " $icon $SUp ";
}
];
};
@@ -35,12 +29,12 @@ with lib;
{
block = "cpu";
interval = 1;
- format = "{barchart}";
+ format = " $icon $barchart ";
}
{
block = "load";
interval = 1;
- format = "{1m} {5m}";
+ format = " $icon $1m $5m ";
}
];
icons = "awesome5";
@@ -52,30 +46,30 @@ with lib;
};
- test.stubs.i3status-rust = { };
+ test.stubs.i3status-rust = { version = "0.30.0"; };
nmt.script = ''
assertFileExists home-files/.config/i3status-rust/config-top.toml
assertFileContent home-files/.config/i3status-rust/config-top.toml \
${
pkgs.writeText "i3status-rust-expected-config" ''
- icons = "none"
- theme = "plain"
[[block]]
alert = 10.0
- alias = "/"
block = "disk_space"
info_type = "available"
interval = 60
- path = "/"
- unit = "GB"
warning = 20.0
[[block]]
block = "memory"
- display_type = "memory"
- format_mem = "{Mug}GB ({Mup}%)"
- format_swap = "{SUp}%"
+ format_mem = " $icon $Mug ($Mup) "
+ format_swap = " $icon $SUp "
+
+ [icons]
+ icons = "none"
+
+ [theme]
+ theme = "plain"
''
}
@@ -84,17 +78,21 @@ with lib;
home-files/.config/i3status-rust/config-bottom.toml \
${
pkgs.writeText "i3status-rust-expected-config" ''
- icons = "awesome5"
- theme = "gruvbox-dark"
[[block]]
block = "cpu"
- format = "{barchart}"
+ format = " $icon $barchart "
interval = 1
[[block]]
block = "load"
- format = "{1m} {5m}"
+ format = " $icon $1m $5m "
interval = 1
+
+ [icons]
+ icons = "awesome5"
+
+ [theme]
+ theme = "gruvbox-dark"
''
}
'';
diff --git a/tests/modules/programs/i3status-rust/with-version-02xx.nix b/tests/modules/programs/i3status-rust/with-version-02xx.nix
new file mode 100644
index 00000000..ec8c2f9a
--- /dev/null
+++ b/tests/modules/programs/i3status-rust/with-version-02xx.nix
@@ -0,0 +1,49 @@
+{ config, lib, pkgs, ... }:
+
+{
+ config = {
+ programs.i3status-rust = { enable = true; };
+
+ test.stubs.i3status-rust = { version = "0.29.9"; };
+
+ nmt.script = ''
+ assertFileExists home-files/.config/i3status-rust/config-default.toml
+ assertFileContent home-files/.config/i3status-rust/config-default.toml \
+ ${
+ pkgs.writeText "i3status-rust-expected-config" ''
+ icons = "none"
+ theme = "plain"
+ [[block]]
+ alert = 10.0
+ block = "disk_space"
+ info_type = "available"
+ interval = 60
+ path = "/"
+ warning = 20.0
+
+ [[block]]
+ block = "memory"
+ format = " $icon mem_used_percents "
+ format_alt = " $icon $swap_used_percents "
+
+ [[block]]
+ block = "cpu"
+ interval = 1
+
+ [[block]]
+ block = "load"
+ format = " $icon $1m "
+ interval = 1
+
+ [[block]]
+ block = "sound"
+
+ [[block]]
+ block = "time"
+ format = " $timestamp.datetime(f:'%a %d/%m %R') "
+ interval = 60
+ ''
+ }
+ '';
+ };
+}