You are not logged in.
There have been suggestions for an exit submenu on the main menu, so you can go straight to logout, suspend etc without having to bring up the bl-exit window. This seems quite a good idea, except that bl-exit is written to be system-agnostic to some extent in that it doesn't depend on systemd, while menu items suggested are things like 'systemctl poweroff'.
If menus etc were able to call e.g. 'bl-exit --reboot' to go straight to the action wanted, it would mean that they would work with or without systemd, and if anything about the system changed in the future it could all be dealt with in bl-exit, and menus, keyboard shortcuts etc would go on working. Does that sound like a good idea?
If so, I wonder if any pythonistas would feel like writing the necessary patch to bl-exit?
I guess we'd want --logout --suspend --reboot and --poweroff options.
...elevator in the Brain Hotel, broken down but just as well...
( a boring Japan blog (currently paused), now on Bluesky, there's also some GitStuff )
Offline
Are we talking about as openbox root menu items?
"I've... seen things you people wouldn't believe; attack ships on fire off the shoulder of Orion; I've watched C-beams glitter in the dark near the Tannhauser Gate."
Offline
I guess we'd want --logout --suspend --reboot and --poweroff options.
and hibernate (if there's a swap partition available (that's also not shared with another OS [but I guess the latter condition should be something the user'll have to remember themselves)), maybe?
(I've added it to my own (systemd-dependent) exit-submenu.)
<menu id="exit-alternatives" label="Exit Alternatives">
<item label="Log Out">
<action name="Execute">
<command>
openbox --exit
</command>
</action>
</item>
<item label="Suspend">
<action name="Execute">
<command>
systemctl suspend
</command>
</action>
</item>
<item label="Hibernate">
<action name="Execute">
<command>
systemctl hibernate
</command>
</action>
</item>
<item label="Restart">
<action name="Execute">
<command>
systemctl reboot
</command>
</action>
</item>
<item label="Shutdown">
<action name="Execute">
<command>
systemctl poweroff
</command>
</action>
</item>
</menu>
as of 2020-Jun-08: Bunsenlabs 10 "Lithium" (RC3) (and BunsenLabs 9.8 "Helium", and Windows 8.1) on mainly-at-home (64-bit UEFI; defunct battery) | 64-bit Windows 10 on carry-around || TypeMatrix 2030 USB (blank) + "skin", Logitech Marble Mouse USB, Logitech B105
¤ Se vi scivolas: Mi estas ina. ¤ (Mi provas lerni E-on, sed ankoraŭ ne majstri ĝin.) ¤
Offline
Here's a quick go. It can probably use some cleanups, but it gets the job done. Let me know if I should pursue this further and make a PR.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import getopt
import getpass
import gtk
import os
import pygtk
pygtk.require('2.0')
import sys
class bl_exit:
def disable_buttons(self):
self.cancel.set_sensitive(False)
self.logout.set_sensitive(False)
self.suspend.set_sensitive(False)
self.reboot.set_sensitive(False)
self.shutdown.set_sensitive(False)
def cancel_action(self,btn):
self.disable_buttons()
gtk.main_quit()
def logout_action(self,btn):
self.disable_buttons()
self.status.set_label("Exiting Openbox, please standby...")
logout()
gtk.main_quit()
def suspend_action(self,btn):
self.disable_buttons()
self.status.set_label("Suspending, please standby...")
suspend()
gtk.main_quit()
def reboot_action(self,btn):
self.disable_buttons()
self.status.set_label("Rebooting, please standby...")
reboot()
def shutdown_action(self,btn):
self.disable_buttons()
self.status.set_label("Shutting down, please standby...")
poweroff()
def create_window(self):
self.window = gtk.Window()
title = "Log out " + getpass.getuser() + "? Choose an option:"
self.window.set_title(title)
self.window.set_border_width(5)
self.window.set_size_request(500, 80)
self.window.set_resizable(False)
self.window.set_keep_above(True)
self.window.stick
self.window.set_position(1)
self.window.connect("delete_event", gtk.main_quit)
windowicon = self.window.render_icon(gtk.STOCK_QUIT, gtk.ICON_SIZE_DIALOG)
self.window.set_icon(windowicon)
#Create HBox for buttons
self.button_box = gtk.HBox()
#Cancel button
self.cancel = gtk.Button(stock = gtk.STOCK_CANCEL)
self.cancel.set_border_width(4)
self.cancel.connect("clicked", self.cancel_action)
self.button_box.pack_start(self.cancel)
#Cancel key (Escape)
accelgroup = gtk.AccelGroup()
self.key, self.mod = gtk.accelerator_parse('Escape')
accelgroup.connect_group(self.key, self.mod, gtk.ACCEL_VISIBLE, gtk.main_quit)
self.window.add_accel_group(accelgroup)
#Logout button
self.logout = gtk.Button("_Log out")
self.logout.set_border_width(4)
self.logout.connect("clicked", self.logout_action)
self.button_box.pack_start(self.logout)
#Suspend button
self.suspend = gtk.Button("_Suspend")
self.suspend.set_border_width(4)
self.suspend.connect("clicked", self.suspend_action)
self.button_box.pack_start(self.suspend)
#Reboot button
self.reboot = gtk.Button("_Reboot")
self.reboot.set_border_width(4)
self.reboot.connect("clicked", self.reboot_action)
self.button_box.pack_start(self.reboot)
#Shutdown button
self.shutdown = gtk.Button("_Power off")
self.shutdown.set_border_width(4)
self.shutdown.connect("clicked", self.shutdown_action)
self.button_box.pack_start(self.shutdown)
#Create HBox for status label
self.label_box = gtk.HBox()
self.status = gtk.Label()
self.label_box.pack_start(self.status)
#Create VBox and pack the above HBox's
self.vbox = gtk.VBox()
self.vbox.pack_start(self.button_box)
self.vbox.pack_start(self.label_box)
self.window.add(self.vbox)
self.window.show_all()
def __init__(self):
self.create_window()
def send_dbus(string):
dbus_send = "dbus-send --print-reply --system --dest=org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager.{} boolean:true"
os.system(dbus_send.format(string))
def logout():
os.system("openbox --logout")
def suspend():
os.system("bl-lock")
send_dbus("Suspend")
def reboot():
send_dbus("Reboot")
def poweroff():
send_dbus("Poweroff")
def print_usage(status):
print ("bl-exit: usage:\n" \
" -h, --help show this message and exit\n" \
" -l, --logout log out from openbox\n" \
" -s, --suspend suspend the system\n" \
" -r, --reboot reboot the system\n" \
" -p, --poweroff power the system down")
sys.exit(status)
def main(argv):
try:
opts, args = getopt.getopt(argv, "hlsrp", ["help","logout","suspend","reboot","poweroff"])
except getopt.GetoptError:
print_usage(1)
for opt, arg in opts:
if opt in ("-h", "--help"):
print_usage(0)
elif opt in ("-l", "--logout"):
logout()
sys.exit(0)
elif opt in ("-s", "--suspend"):
suspend()
sys.exit(0)
elif opt in ("-r", "--reboot"):
reboot()
sys.exit(0)
elif opt in ("-p", "--poweroff"):
poweroff()
sys.exit(0)
go = bl_exit()
gtk.main()
if __name__ == "__main__":
main(sys.argv[1:])
EDIT: Obligatory diff so you can easier review my changes:
diff --git a/bl-exit b/bl-exit
index 7c2d6e7..674f854 100755
--- a/bl-exit
+++ b/bl-exit
@@ -1,13 +1,13 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-import pygtk
-pygtk.require('2.0')
+import getopt
+import getpass
import gtk
import os
-import getpass
-
-dbus_send = "dbus-send --print-reply --system --dest=org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager.{} boolean:true"
+import pygtk
+pygtk.require('2.0')
+import sys
class bl_exit:
def disable_buttons(self):
@@ -24,24 +24,24 @@ class bl_exit:
def logout_action(self,btn):
self.disable_buttons()
self.status.set_label("Exiting Openbox, please standby...")
- os.system("openbox --exit")
+ logout()
+ gtk.main_quit()
def suspend_action(self,btn):
self.disable_buttons()
self.status.set_label("Suspending, please standby...")
- os.system("bl-lock")
- os.system(dbus_send.format("Suspend"))
+ suspend()
gtk.main_quit()
def reboot_action(self,btn):
self.disable_buttons()
self.status.set_label("Rebooting, please standby...")
- os.system(dbus_send.format("Reboot"))
+ reboot()
def shutdown_action(self,btn):
self.disable_buttons()
self.status.set_label("Shutting down, please standby...")
- os.system(dbus_send.format("PowerOff"))
+ poweroff()
def create_window(self):
self.window = gtk.Window()
@@ -57,17 +57,14 @@ class bl_exit:
windowicon = self.window.render_icon(gtk.STOCK_QUIT, gtk.ICON_SIZE_DIALOG)
self.window.set_icon(windowicon)
-
#Create HBox for buttons
self.button_box = gtk.HBox()
- self.button_box.show()
#Cancel button
self.cancel = gtk.Button(stock = gtk.STOCK_CANCEL)
self.cancel.set_border_width(4)
self.cancel.connect("clicked", self.cancel_action)
self.button_box.pack_start(self.cancel)
- self.cancel.show()
#Cancel key (Escape)
accelgroup = gtk.AccelGroup()
@@ -80,52 +77,89 @@ class bl_exit:
self.logout.set_border_width(4)
self.logout.connect("clicked", self.logout_action)
self.button_box.pack_start(self.logout)
- self.logout.show()
#Suspend button
self.suspend = gtk.Button("_Suspend")
self.suspend.set_border_width(4)
self.suspend.connect("clicked", self.suspend_action)
self.button_box.pack_start(self.suspend)
- self.suspend.show()
#Reboot button
self.reboot = gtk.Button("_Reboot")
self.reboot.set_border_width(4)
self.reboot.connect("clicked", self.reboot_action)
self.button_box.pack_start(self.reboot)
- self.reboot.show()
#Shutdown button
self.shutdown = gtk.Button("_Power off")
self.shutdown.set_border_width(4)
self.shutdown.connect("clicked", self.shutdown_action)
self.button_box.pack_start(self.shutdown)
- self.shutdown.show()
#Create HBox for status label
self.label_box = gtk.HBox()
- self.label_box.show()
self.status = gtk.Label()
- self.status.show()
self.label_box.pack_start(self.status)
#Create VBox and pack the above HBox's
self.vbox = gtk.VBox()
self.vbox.pack_start(self.button_box)
self.vbox.pack_start(self.label_box)
- self.vbox.show()
self.window.add(self.vbox)
- self.window.show()
+ self.window.show_all()
def __init__(self):
self.create_window()
-
-def main():
+def send_dbus(string):
+ dbus_send = "dbus-send --print-reply --system --dest=org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager.{} boolean:true"
+ os.system(dbus_send.format(string))
+
+def logout():
+ os.system("openbox --logout")
+
+def suspend():
+ os.system("bl-lock")
+ send_dbus("Suspend")
+
+def reboot():
+ send_dbus("Reboot")
+
+def poweroff():
+ send_dbus("Poweroff")
+
+def print_usage(status):
+ print ("bl-exit: usage:\n" \
+ " -h, --help show this message and exit\n" \
+ " -l, --logout log out from openbox\n" \
+ " -s, --suspend suspend the system\n" \
+ " -r, --reboot reboot the system\n" \
+ " -p, --poweroff power the system down")
+ sys.exit(status)
+
+def main(argv):
+ try:
+ opts, args = getopt.getopt(argv, "hlsrp", ["help","logout","suspend","reboot","poweroff"])
+ except getopt.GetoptError:
+ print_usage(1)
+ for opt, arg in opts:
+ if opt in ("-h", "--help"):
+ print_usage(0)
+ elif opt in ("-l", "--logout"):
+ logout()
+ sys.exit(0)
+ elif opt in ("-s", "--suspend"):
+ suspend()
+ sys.exit(0)
+ elif opt in ("-r", "--reboot"):
+ reboot()
+ sys.exit(0)
+ elif opt in ("-p", "--poweroff"):
+ poweroff()
+ sys.exit(0)
+ go = bl_exit()
gtk.main()
if __name__ == "__main__":
- go = bl_exit()
- main()
+ main(sys.argv[1:])
If you can't sit by a cozy fire with your code in hand enjoying its simplicity and clarity, it needs more work. --Carlos Torres
Offline
Hi Unia,
As a minor optimization, perhaps import the graphical modules only if no options are specified.
Offline
Offline
Hi Unia,
As a minor optimization, perhaps import the graphical modules only if no options are specified.
Thanks, I usually don't work with Python so I didn't know this was possible. It makes for some clunky looking code, though, and as you said it is only a minor optimization so I don't think I will add this. Perhaps more people (some who often program in Python, maybe) can shed their opinion on it?
If you can't sit by a cozy fire with your code in hand enjoying its simplicity and clarity, it needs more work. --Carlos Torres
Offline
What do you think of this?
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import getopt
import getpass
import os
import sys
class bl_exit:
def disable_buttons(self):
self.cancel.set_sensitive(False)
self.logout.set_sensitive(False)
self.suspend.set_sensitive(False)
self.reboot.set_sensitive(False)
self.shutdown.set_sensitive(False)
def cancel_action(self,btn):
self.disable_buttons()
gtk.main_quit()
def logout_action(self,btn):
self.disable_buttons()
self.status.set_label("Exiting Openbox, please standby...")
logout()
gtk.main_quit()
def suspend_action(self,btn):
self.disable_buttons()
self.status.set_label("Suspending, please standby...")
suspend()
gtk.main_quit()
def reboot_action(self,btn):
self.disable_buttons()
self.status.set_label("Rebooting, please standby...")
reboot()
def shutdown_action(self,btn):
self.disable_buttons()
self.status.set_label("Shutting down, please standby...")
poweroff()
def create_window(self):
self.window = gtk.Window()
title = "Log out " + getpass.getuser() + "? Choose an option:"
self.window.set_title(title)
self.window.set_border_width(5)
self.window.set_size_request(500, 80)
self.window.set_resizable(False)
self.window.set_keep_above(True)
self.window.stick
self.window.set_position(1)
self.window.connect("delete_event", gtk.main_quit)
windowicon = self.window.render_icon(gtk.STOCK_QUIT, gtk.ICON_SIZE_DIALOG)
self.window.set_icon(windowicon)
#Create HBox for buttons
self.button_box = gtk.HBox()
#Cancel button
self.cancel = gtk.Button(stock = gtk.STOCK_CANCEL)
self.cancel.set_border_width(4)
self.cancel.connect("clicked", self.cancel_action)
self.button_box.pack_start(self.cancel)
#Cancel key (Escape)
accelgroup = gtk.AccelGroup()
self.key, self.mod = gtk.accelerator_parse('Escape')
accelgroup.connect_group(self.key, self.mod, gtk.ACCEL_VISIBLE, gtk.main_quit)
self.window.add_accel_group(accelgroup)
#Logout button
self.logout = gtk.Button("_Log out")
self.logout.set_border_width(4)
self.logout.connect("clicked", self.logout_action)
self.button_box.pack_start(self.logout)
#Suspend button
self.suspend = gtk.Button("_Suspend")
self.suspend.set_border_width(4)
self.suspend.connect("clicked", self.suspend_action)
self.button_box.pack_start(self.suspend)
#Reboot button
self.reboot = gtk.Button("_Reboot")
self.reboot.set_border_width(4)
self.reboot.connect("clicked", self.reboot_action)
self.button_box.pack_start(self.reboot)
#Shutdown button
self.shutdown = gtk.Button("_Power off")
self.shutdown.set_border_width(4)
self.shutdown.connect("clicked", self.shutdown_action)
self.button_box.pack_start(self.shutdown)
#Create HBox for status label
self.label_box = gtk.HBox()
self.status = gtk.Label()
self.label_box.pack_start(self.status)
#Create VBox and pack the above HBox's
self.vbox = gtk.VBox()
self.vbox.pack_start(self.button_box)
self.vbox.pack_start(self.label_box)
self.window.add(self.vbox)
self.window.show_all()
def __init__(self):
self.create_window()
def send_dbus(string):
dbus_send = "dbus-send --print-reply --system --dest=org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager.{} boolean:true"
os.system(dbus_send.format(string))
def logout():
os.system("openbox --logout")
def suspend():
os.system("bl-lock")
send_dbus("Suspend")
def reboot():
send_dbus("Reboot")
def poweroff():
send_dbus("Poweroff")
def print_usage(status):
print ("bl-exit: usage:\n" \
" -h, --help show this message and exit\n" \
" -l, --logout log out from openbox\n" \
" -s, --suspend suspend the system\n" \
" -r, --reboot reboot the system\n" \
" -p, --poweroff power the system down")
sys.exit(status)
if __name__ == "__main__":
try:
opts, args = getopt.getopt(sys.argv[1:], "hlsrp", ["help","logout","suspend","reboot","poweroff"])
except getopt.GetoptError:
print_usage(1)
for opt, arg in opts:
if opt in ("-h", "--help"):
print_usage(0)
sys.exit(0)
elif opt in ("-l", "--logout"):
logout()
sys.exit(0)
elif opt in ("-s", "--suspend"):
suspend()
sys.exit(0)
elif opt in ("-r", "--reboot"):
reboot()
sys.exit(0)
elif opt in ("-p", "--poweroff"):
poweroff()
sys.exit(0)
# Only import the following graphical modules
# when no runtime options are specified.
import gtk
import pygtk
pygtk.require('2.0')
go = bl_exit()
gtk.main()
If you run the program in debugging mode with
python -m pdb bl-exit
you will notice that importing pygtk takes a noticable amount of time, and it is not used in case an option is specified.
Last edited by xaos52 (2015-10-07 14:42:55)
Offline
I'm not at my machine right now; how much time are we talking about?
If you can't sit by a cozy fire with your code in hand enjoying its simplicity and clarity, it needs more work. --Carlos Torres
Offline
Oh,
I am off to run some measurements.
Last edited by xaos52 (2015-10-07 16:48:26)
Offline
On my system the graphical imports would take about 1.7 seconds .
Calculated with following script:
#!/usr/bin/python
def test():
"""Stupid test function"""
import gtk
import pygtk
pygtk.require('2.0')
if __name__ == '__main__':
import timeit
# print(timeit.timeit("test()", setup="from __main__ import test"))
print(timeit.repeat("test()", setup="from __main__ import test", repeat=100))
Results:
me@medion:~/tmp/today$ ./test.py
[1.7818810939788818, 1.6782581806182861, 1.677238941192627, 1.675894021987915, 1.6739718914031982, 1.675201177597046, 1.6758880615234375, 1.6757519245147705, 1.676764965057373, 1.6750850677490234, 1.6775450706481934, 1.6773359775543213, 1.6761760711669922, 1.6765360832214355, 1.6753830909729004, 1.6824989318847656, 1.6774811744689941, 1.6768779754638672, 1.675177812576294, 1.6767759323120117, 1.6766459941864014, 1.685642957687378, 1.686673879623413, 1.686331033706665, 1.7301018238067627, 1.8507440090179443, 1.7009119987487793, 1.6913800239562988, 1.69451904296875, 1.6874101161956787, 1.691404104232788, 1.693532943725586, 1.6880710124969482, 1.6887710094451904, 1.700256109237671, 1.690180778503418, 1.702329158782959, 1.6978991031646729, 1.6915900707244873, 1.7086429595947266, 1.6895408630371094, 1.7439489364624023, 1.6894021034240723, 1.6853408813476562, 1.686460018157959, 1.6943738460540771, 1.6871650218963623, 1.686150074005127, 1.6858570575714111, 1.6966781616210938, 1.6873829364776611, 1.6848669052124023, 1.6848578453063965, 1.6870479583740234, 1.6856739521026611, 1.6859121322631836, 1.6839370727539062, 1.684140920639038, 1.6848490238189697, 1.685912847518921, 1.686812162399292, 1.6860289573669434, 1.6853749752044678, 1.6852078437805176, 1.6856861114501953, 1.6859290599822998, 1.6848299503326416, 1.6856961250305176, 1.6873490810394287, 1.687391996383667, 1.6866099834442139, 1.68697190284729, 1.6860568523406982, 1.6872670650482178, 1.6850271224975586, 1.6851568222045898, 1.6866371631622314, 1.6852378845214844, 1.6852538585662842, 1.6860899925231934, 1.6880648136138916, 1.6852259635925293, 1.6868031024932861, 1.6857199668884277, 1.6853721141815186, 1.685863971710205, 1.685359001159668, 1.6878540515899658, 1.685317039489746, 1.6849150657653809, 1.6856191158294678, 1.6849188804626465, 1.6849730014801025, 1.6859080791473389, 1.6866509914398193, 1.6858909130096436, 1.686527967453003, 1.6843981742858887, 1.6852200031280518, 1.6862480640411377]
me@medion:~/tmp/today$
Last edited by xaos52 (2015-10-07 16:54:43)
Offline
Can it be done without graphics?
Graphics - Icons of some type????
Or is my nobbishness showing?
Debian 12 Beardog, SoxDog and still a Conky 1.9er
Offline
Can it be done without graphics?
Graphics - Icons of some type????
Or is my nobbishness showing?
EDIT by Unia: Whoops, accidentally edited instead of quoted. :8
[Not denigrating the efforts, but it all seems a lot of work when it can be done with a bash/yad script ]
Last edited by damo (2015-10-07 20:02:28)
Be Excellent to Each Other...
The Bunsenlabs Lithium Desktop » Here
FORUM RULES and posting guidelines «» Help page for forum post formatting
Artwork on DeviantArt «» BunsenLabs on DeviantArt
Offline
There are links to /bin/systemctl in /sbin, named poweroff, reboot and shutdown. There are no other places, where we can find files or links named poweroff, reboot and shutdown in the system. If we run poweroff, reboot or shutdown in gmrun or terminal, they simply work. We don't have to write systemctl in front of them. What we can't find are the suspend and hibernate links to /bin/systemctl. So, in the root-menu, we can write,
<menu id="exit" label="Exit">
<item label="Logout">
<action name="Execute">
<command>openbox --exit</command>
</action>
</item>
<item label="Suspend">
<action name="Execute">
<command>systemctl suspend</command>
</action>
</item>
<item label="Reboot">
<action name="Execute">
<command>reboot</command>
</action>
</item>
<item label="Poweroff">
<action name="Execute">
<command>poweroff</command>
</action>
</item>
</menu>
We can make a two links to /bin/systemctl anywhere, for example in the home directory, rename them poweroff and reboot, they'd work. They are executable and owned by root. The renaming won't work with suspend. Debian default is Systemd, anyway.
I have also given some gtkdialog, yad scripts here, http://crunchbang.org/forums/viewtopic.php?id=40572 You can delete the systemctl before poweroff and reboot in them.
Offline
If we run poweroff, reboot or shutdown in gmrun or terminal, they simply work.
Only if /sbin is in your user's $PATH
The advantage of calling `systemctl` is that it's in /bin and so accessable by all users.
Offline
ostrołęk wrote:If we run poweroff, reboot or shutdown in gmrun or terminal, they simply work.
Only if /sbin is in your user's $PATH
The advantage of calling `systemctl` is that it's in /bin and so accessable by all users.
There are no other places, where we can find files or links named poweroff, reboot and shutdown in the system. In Debian, what is in /sbin are executable.
Offline
@ostrolek
The guys are aware of the system shutdown options. This thread is specifically about command arguments for the bl-exit python script.
If you can code in python then please contribute, otherwise can we stay on topic please?
Be Excellent to Each Other...
The Bunsenlabs Lithium Desktop » Here
FORUM RULES and posting guidelines «» Help page for forum post formatting
Artwork on DeviantArt «» BunsenLabs on DeviantArt
Offline
...and the point of running commands through bl-exit is that if at some time in the future the necessary system commands change, we'll only have to edit this one file to take care of it.
...elevator in the Brain Hotel, broken down but just as well...
( a boring Japan blog (currently paused), now on Bluesky, there's also some GitStuff )
Offline
[Not denigrating the efforts, but it all seems a lot of work when it can be done with a bash/yad script
]
I was thinking the same, but AFAIK you can not reproduce the current UI with zenity. The alternative is a drop-down list, but that doesn't have the same ease of use. Is it possible with yad?
If you can't sit by a cozy fire with your code in hand enjoying its simplicity and clarity, it needs more work. --Carlos Torres
Offline
On my system the graphical imports would take about 1.7 seconds .
Oh wow, that is actually quite noticable. I will add your suggestion
If you can't sit by a cozy fire with your code in hand enjoying its simplicity and clarity, it needs more work. --Carlos Torres
Offline