a process

Hello,

I want the computer to show a number, wait, increase the number and then show it again. Some simple print commands. If I press a key the program should stop. And if I press it again the program should play again.

I've tried this code:

My problem is, it isn't working. Only if 10 numbers have been showed I'm able to press some keys. I would like to have these 2 processes working parallel to each other. The process to wait until I press a key and the process to increase the numbers.
Of course it's only an abstract example. Think of an EGO-Shooter and you're doing nothing. Everything else is happening but you don't take any actions.

import wx
import time

class PressedKey(wx.Panel):
  def __init__(self, parent3):
    wx.Panel.__init__(self, parent3, -1, style=0)
    self.Bind(wx.EVT_CHAR, self.LogKeyEvent)
    self.SetFocus()
    
    self.Key_Enter = 13
    
    self.PressedKeyCode = 0
    self.Stop = 'NO'
    
  def do_action(self):
    if self.PressedKeyCode == self.Key_Enter:
      self.Stop = 'YES'
    elif self.PressedKeyCode == self.Key_a:
      self.Stop = 'NO'

  def LogKeyEvent(self, evt):
    self.PressedKeyCode = evt.GetKeyCode()
    self.do_action()

class Core:
  def __init__(self):
    self.counter = 0
    
  def run(self):
    self.counter += 1
    time.sleep(1)
    print self.counter

class MyApp(wx.App):
  def OnInit(self):
    frame3 = wx.Frame(None, -1, "Keep Focus", pos=(0, 0), size=(300, 250))
    
    c = Core()
    pk = PressedKey(frame3)
    
    frame3.Show(True)
    
    while c.counter < 10:
      if pk.Stop == 'NO':
        c.run()
    
    return True
    
app = MyApp(0)
app.MainLoop()

Hello,

I want the computer to show a number, wait, increase the number and then
show it again. Some simple print commands. If I press a key the program
should stop. And if I press it again the program should play again.

I've tried this code:

My problem is, it isn't working. Only if 10 numbers have been showed I'm
able to press some keys. I would like to have these 2 processes working
parallel to each other. The process to wait until I press a key and the
process to increase the numbers.

Your terminology is off. See:

With threads you usually have to be careful of 'deadlocks', 'race
conditions', and various other things. I have implemented the below
using threads (because it required the fewest lines of modification),
however, if you just want "some function foo triggered every k seconds",
you should look into wx.Timer, it will probably do what you want.

Of course it's only an abstract example. Think of an EGO-Shooter and
you're doing nothing. Everything else is happening but you don't take
any actions.

import wx
import time

import threading

class PressedKey(wx.Panel):
  def __init__(self, parent3):
    wx.Panel.__init__(self, parent3, -1, style=0)
    self.Bind(wx.EVT_CHAR, self.LogKeyEvent)
    self.SetFocus()
    
    self.Key_Enter = 13
    
    self.PressedKeyCode = 0
    self.Stop = 'NO'
    
  def do_action(self):
    if self.PressedKeyCode == self.Key_Enter:
      self.Stop = 'YES'
    elif self.PressedKeyCode == self.Key_a:
      self.Stop = 'NO'

Where is 'self.Key_a' coming from? It's not defined anywhere.

  def LogKeyEvent(self, evt):
    self.PressedKeyCode = evt.GetKeyCode()
    self.do_action()

class Core:

    def __init__(self, p):
        self.p = p

    self.counter = 0
    
  def run(self):

        while self.p.Stop == 'No':
            print self.counter
            self.counter += 1
            time.sleep(1)

class MyApp(wx.App):
  def OnInit(self):
    frame3 = wx.Frame(None, -1, "Keep Focus", pos=(0, 0), size=(300, 250))
    
    pk = PressedKey(frame3)

        c = Core(pk)

    
    frame3.Show(True)
    

        threading.Thread(target=c.run).start()

···

Franz <franzlinux@gmx.de> wrote:

    
    return True
    
app = MyApp(0)
app.MainLoop()

Use threading only if the process is blocking your application. A
good example is for example to download files.

Try to follow this order to implement, according to my experience:
1 wx.Timer as it is the most easy and implements the time interval for you
2 if the time interval might be to short for your process, try to use
an idle event (I even prefer this to timer)
3 if this is not possible, use threads, but it should be your last
resort. (If you want to update your user interface from a thread,
always use wx.CallAfter Don't ignore this golden rule or you will be
in trouble.)

In case of using 1 or 2 also consider to Unbind events when processes
or stopped and just to bind them when they are started, if you care
about CPU use.

Stani

···

--

On 12/23/05, Josiah Carlson <jcarlson@uci.edu> wrote:

Franz <franzlinux@gmx.de> wrote:
>
> Hello,
>
> I want the computer to show a number, wait, increase the number and then
> show it again. Some simple print commands. If I press a key the program
> should stop. And if I press it again the program should play again.
>
> I've tried this code:
>
> My problem is, it isn't working. Only if 10 numbers have been showed I'm
> able to press some keys. I would like to have these 2 processes working
> parallel to each other. The process to wait until I press a key and the
> process to increase the numbers.

Your terminology is off. See:
Process (computing) - Wikipedia
Thread (computing) - Wikipedia

With threads you usually have to be careful of 'deadlocks', 'race
conditions', and various other things. I have implemented the below
using threads (because it required the fewest lines of modification),
however, if you just want "some function foo triggered every k seconds",
you should look into wx.Timer, it will probably do what you want.

> Of course it's only an abstract example. Think of an EGO-Shooter and
> you're doing nothing. Everything else is happening but you don't take
> any actions.
>
> import wx
> import time

import threading

> class PressedKey(wx.Panel):
> def __init__(self, parent3):
> wx.Panel.__init__(self, parent3, -1, style=0)
> self.Bind(wx.EVT_CHAR, self.LogKeyEvent)
> self.SetFocus()
>
> self.Key_Enter = 13
>
> self.PressedKeyCode = 0
> self.Stop = 'NO'
>
> def do_action(self):
> if self.PressedKeyCode == self.Key_Enter:
> self.Stop = 'YES'
> elif self.PressedKeyCode == self.Key_a:
> self.Stop = 'NO'

Where is 'self.Key_a' coming from? It's not defined anywhere.

> def LogKeyEvent(self, evt):
> self.PressedKeyCode = evt.GetKeyCode()
> self.do_action()
>
> class Core:
    def __init__(self, p):
        self.p = p
> self.counter = 0
>
> def run(self):
        while self.p.Stop == 'No':
            print self.counter
            self.counter += 1
            time.sleep(1)

> class MyApp(wx.App):
> def OnInit(self):
> frame3 = wx.Frame(None, -1, "Keep Focus", pos=(0, 0), size=(300, 250))
>
> pk = PressedKey(frame3)
        c = Core(pk)
>
> frame3.Show(True)
>
        threading.Thread(target=c.run).start()
>
> return True
>
>
> app = MyApp(0)
> app.MainLoop()

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org

--

http://pythonide.stani.be/screenshots
http://pythonide.stani.be/manual/html/manual.html

Use threading only if the process is blocking your application. A
good example is for example to download files.

But only if your sockets are blocking. If you use non-blocking sockets
with asyncore you can use the non-thread tricks below, or if you use
Twisted, they have a special event loop so that you don't even have to
worry about it.

Try to follow this order to implement, according to my experience:
1 wx.Timer as it is the most easy and implements the time interval for you

I agree with this completely. Note that I stated that I used threads
because it required the fewest line change to make work.

2 if the time interval might be to short for your process, try to use
an idle event (I even prefer this to timer)

The signaling of an idle event sometimes occurs too often, sometimes not
often enough. On Windows, when you move the mouse across the window, an
idle event is signaled for every update from the mouse (in 2k and xp
this is about 200 times/second), but when the mouse stops moving, you
get an idle event every second or so. Ick.

3 if this is not possible, use threads, but it should be your last
resort. (If you want to update your user interface from a thread,
always use wx.CallAfter Don't ignore this golden rule or you will be
in trouble.)

wx.PostEvent() also works well.

In case of using 1 or 2 also consider to Unbind events when processes
or stopped and just to bind them when they are started, if you care
about CPU use.

Unless you are binding and unbinding hundreds of events (which would be
crazy), I can't imagine that the wx.Timer() event or two would cause a
slowdown which was measureable by your computer, let alone observable by
the user.

- Josiah

···

"SPE Stani's Python Editor" <spe.stani.be@gmail.com> wrote:

On 12/23/05, Josiah Carlson <jcarlson@uci.edu> wrote:
>
> Franz <franzlinux@gmx.de> wrote:
> >
> > Hello,
> >
> > I want the computer to show a number, wait, increase the number and then
> > show it again. Some simple print commands. If I press a key the program
> > should stop. And if I press it again the program should play again.
> >
> > I've tried this code:
> >
> > My problem is, it isn't working. Only if 10 numbers have been showed I'm
> > able to press some keys. I would like to have these 2 processes working
> > parallel to each other. The process to wait until I press a key and the
> > process to increase the numbers.
>
> Your terminology is off. See:
> Process (computing) - Wikipedia
> Thread (computing) - Wikipedia
>
> With threads you usually have to be careful of 'deadlocks', 'race
> conditions', and various other things. I have implemented the below
> using threads (because it required the fewest lines of modification),
> however, if you just want "some function foo triggered every k seconds",
> you should look into wx.Timer, it will probably do what you want.
>
> > Of course it's only an abstract example. Think of an EGO-Shooter and
> > you're doing nothing. Everything else is happening but you don't take
> > any actions.
> >
> > import wx
> > import time
>
> import threading
>
> > class PressedKey(wx.Panel):
> > def __init__(self, parent3):
> > wx.Panel.__init__(self, parent3, -1, style=0)
> > self.Bind(wx.EVT_CHAR, self.LogKeyEvent)
> > self.SetFocus()
> >
> > self.Key_Enter = 13
> >
> > self.PressedKeyCode = 0
> > self.Stop = 'NO'
> >
> > def do_action(self):
> > if self.PressedKeyCode == self.Key_Enter:
> > self.Stop = 'YES'
> > elif self.PressedKeyCode == self.Key_a:
> > self.Stop = 'NO'
>
> Where is 'self.Key_a' coming from? It's not defined anywhere.
>
>
> > def LogKeyEvent(self, evt):
> > self.PressedKeyCode = evt.GetKeyCode()
> > self.do_action()
> >
> > class Core:
> def __init__(self, p):
> self.p = p
> > self.counter = 0
> >
> > def run(self):
> while self.p.Stop == 'No':
> print self.counter
> self.counter += 1
> time.sleep(1)
>
> > class MyApp(wx.App):
> > def OnInit(self):
> > frame3 = wx.Frame(None, -1, "Keep Focus", pos=(0, 0), size=(300, 250))
> >
> > pk = PressedKey(frame3)
> c = Core(pk)
> >
> > frame3.Show(True)
> >
> threading.Thread(target=c.run).start()
> >
> > return True
> >
> >
> > app = MyApp(0)
> > app.MainLoop()
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
> For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org
>
>

--
http://pythonide.stani.be
http://pythonide.stani.be/screenshots
http://pythonide.stani.be/manual/html/manual.html

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org

Hello,

thank you for your replies. I have tried the first example with threads, but I've got the problem that it is not working properly. I press <enter> and the program stops, but if I now press <a> the program isn't going back to work.
But nevertheless, it is a step in the right direction.

Josiah Carlson schrieb:

if you just want "some function foo triggered every k seconds",
you should look into wx.Timer, it will probably do what you want.

I want to have a running code. Abstract just the output of numbers. Around this 'Core'-code should be laid the design of getting and evalutaing input by the user. ex: User presses a key and the program is stopped. Press it again and the program continues with its work.

I would also like to know how it is possible to solve this problem with the idle-event.
I would prefer an example because I regard learning from examples as the easiest way.

So here now my modified code with self.Key_a defined :wink:

import wx
import time
import threading

class PressedKey(wx.Panel):
  def __init__(self, parent3):
    wx.Panel.__init__(self, parent3, -1, style=0)
    self.Bind(wx.EVT_CHAR, self.LogKeyEvent)
    self.SetFocus()
    
    self.Key_Enter = 13
    self.Key_a = 97
    
    self.PressedKeyCode = 0
    self.Stop = 'NO'
    
  def do_action(self):
    if self.PressedKeyCode == self.Key_Enter:
      self.Stop = 'YES'
    elif self.PressedKeyCode == self.Key_a:
      self.Stop = 'NO'

  def LogKeyEvent(self, evt):
    self.PressedKeyCode = evt.GetKeyCode()
    self.do_action()

class Core:
  def __init__(self, p):
    self.p = p
    self.counter = 0
    
  def run(self):
    while self.p.Stop == 'NO':
      print self.counter
      self.counter += 1
      time.sleep(0.1)
    
class MyApp(wx.App):
  def OnInit(self):
    frame3 = wx.Frame(None, -1, "Keep Focus", pos=(0, 0), size=(300, 250))
    
    pk = PressedKey(frame3)
    c = Core(pk)
    
    frame3.Show(True)
    
    threading.Thread(target=c.run).start()
    
    return True
    
app = MyApp(0)
app.MainLoop()

Hello,

thank you for your replies. I have tried the first example with threads,
but I've got the problem that it is not working properly. I press
<enter> and the program stops, but if I now press <a> the program isn't
going back to work.
But nevertheless, it is a step in the right direction.

I forgot about restarting the thread. I've inserted the necessary
pieces of code along with a note about the key code 97.

Josiah Carlson schrieb:
> if you just want "some function foo triggered every k seconds",
> you should look into wx.Timer, it will probably do what you want.

I want to have a running code. Abstract just the output of numbers.
Around this 'Core'-code should be laid the design of getting and
evalutaing input by the user. ex: User presses a key and the program is
stopped. Press it again and the program continues with its work.

I would also like to know how it is possible to solve this problem with
the idle-event.

It depends on what you actually want to happen as work. That is, it
depends on what you actually want to do in Core.run(). Tell us what you
want to do, and we can help you figure out what is a better way.

- Josiah

I would prefer an example because I regard learning from examples as the
  easiest way.

So here now my modified code with self.Key_a defined :wink:

import wx
import time
import threading

class PressedKey(wx.Panel):
  def __init__(self, parent3):
    wx.Panel.__init__(self, parent3, -1, style=0)
    self.Bind(wx.EVT_CHAR, self.LogKeyEvent)
    self.SetFocus()
    
    self.Key_Enter = 13
    self.Key_a = 97

Have you tried 65 as the value for Key_a? I amunsure of when keycodes
are passed as the upper or lower case variant of the key being pressed.

    self.PressedKeyCode = 0
    self.Stop = 'NO'
    
  def do_action(self):
    if self.PressedKeyCode == self.Key_Enter:
      self.Stop = 'YES'
    elif self.PressedKeyCode == self.Key_a:
      self.Stop = 'NO'

            if not workerthread.isAlive():
                global workerthread
                workerthread = threading.Thread(target=c.run)
                workerthread.start()

  def LogKeyEvent(self, evt):
    self.PressedKeyCode = evt.GetKeyCode()
    self.do_action()

class Core:
  def __init__(self, p):
    self.p = p
    self.counter = 0
    
  def run(self):
    while self.p.Stop == 'NO':
      print self.counter
      self.counter += 1
      time.sleep(0.1)
    
class MyApp(wx.App):
  def OnInit(self):
    frame3 = wx.Frame(None, -1, "Keep Focus", pos=(0, 0), size=(300, 250))
    
    pk = PressedKey(frame3)

        global c

    c = Core(pk)
    
    frame3.Show(True)
    
        global workerthread;
        workerthread = threading.Thread(target=c.run)
        workerthread.start()

···

Franz <franzlinux@gmx.de> wrote:

    
    return True
    
app = MyApp(0)
app.MainLoop()

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org

Thank you for changing the code. I didn't test it yet.

Josiah Carlson schrieb:

It depends on what you actually want to happen as work. That is, it
depends on what you actually want to do in Core.run(). Tell us what you
want to do, and we can help you figure out what is a better way.

Abstract: Just as I have said before. Program should constantly print numbers and if <enter> is pressed the process should be stopped and if <a> is pressed the process should continue.

The latest version of my project you can find here:
http://esnips.com/web/qweet-public
name: tape_reading_public_11.zip

To run it you have to press the right-arrow key. That is what I want to change. My program is only based on user input. I want it running also if the user isn't hitting any key.
But of course if he is, the program should react.

I think of a running Core-code with defined parameters and methods. If the user is giving input, parameters are changing and so the behavior of the program.
So that one only needs to think of designing the Core, testing it, putting it into a box. Now add code to evaluate all input made my keyboard and just hook it on the Core. Same with mouse, joystick and so on...

Franz

ps: sorry josiah for sending it to you.

Thank you for changing the code. I didn't test it yet.

Josiah Carlson schrieb:
> It depends on what you actually want to happen as work. That is, it
> depends on what you actually want to do in Core.run(). Tell us what you
> want to do, and we can help you figure out what is a better way.

Abstract: Just as I have said before. Program should constantly print
numbers and if <enter> is pressed the process should be stopped and if
<a> is pressed the process should continue.

I can't imagine that incrementing a counter would properly capture the
entirety of the work that you would like the thread to do. If so, then
a wx.Timer() should be sufficient for you.

The latest version of my project you can find here:
http://esnips.com/web/qweet-public
name: tape_reading_public_11.zip

To run it you have to press the right-arrow key. That is what I want to
change. My program is only based on user input. I want it running also
if the user isn't hitting any key.
But of course if he is, the program should react.

Yeah, I don't run random binaries. Thankfully, you have included the
source in the 4.3 meg zip file, which allows me to take a look at it
(I'll check it out this afternoon when I have a bit more time).

I think of a running Core-code with defined parameters and methods. If
the user is giving input, parameters are changing and so the behavior of
the program.
So that one only needs to think of designing the Core, testing it,
putting it into a box. Now add code to evaluate all input made my
keyboard and just hook it on the Core. Same with mouse, joystick and so
on...

That's a good design ideal, though it may help us to figure out what is
the best way of going about this to know what this 'Core' is supposed to
do. If all it does is increment a counter, heck, you don't need a
thread. If it's running a genetic algorithm, sure, a thread would
probably help. There is a broad range of things that could be happening
in the core, but without knowing what is going to be running in there,
advising you to stick with a thread, or switch to wx.Timer(), is advice
given with incomplete knowledge.

- Josiah

···

Franz <franzlinux@gmx.de> wrote:

Josiah Carlson schrieb:

I can't imagine that incrementing a counter would properly capture the
entirety of the work that you would like the thread to do. If so, then
a wx.Timer() should be sufficient for you.

I don't know exactly about this one, but your thread is doing a fine work, so I won't change it :slight_smile:

Yeah, I don't run random binaries. Thankfully, you have included the
source in the 4.3 meg zip file, which allows me to take a look at it
(I'll check it out this afternoon when I have a bit more time).

to run it from the source you also need to grab this module:
http://www.random.org/clients/python-client.tgz

That's a good design ideal, though it may help us to figure out what is
the best way of going about this to know what this 'Core' is supposed to
do.

In my opinion the programmer is a part of the program. So the program should be a dynamic environment where every action which is taken can instantly be watched. To say this one is easy and to realize it is very hard I know.
But I can think of Spore (http://spore.ea.com/) where you are able to create things and then let them battle against others.
So you're 'programming' them, giving them bigger legs, arms, two heads...and so on.

If you transfer this idea to normal program, I guess it comes down to this:
Every object of the program should be kept very simple, understandable and of course independent.
So in my eyes the Core needs to be very easy and simple, an instant watch and you know what is happening there. And if you now want to see how the Core reacts with other parts the only thing to do is linking them and watch their behavior.

Yeah, but back to reality :wink:
Franz

Josiah Carlson schrieb:
> I can't imagine that incrementing a counter would properly capture the
> entirety of the work that you would like the thread to do. If so, then
> a wx.Timer() should be sufficient for you.

I don't know exactly about this one, but your thread is doing a fine
work, so I won't change it :slight_smile:

As I and others have stated, sometimes threads can be a pain in the ass.
Single-threaded applications lack those same pains, though can have
others. It's all about tradeoffs.

> That's a good design ideal, though it may help us to figure out what is
> the best way of going about this to know what this 'Core' is supposed to
> do.

In my opinion the programmer is a part of the program. So the program
should be a dynamic environment where every action which is taken can
instantly be watched. To say this one is easy and to realize it is very
hard I know.

It's quite easy to have a program respond to user action. It's a bit
trickier to make the program do what the programmer wants when things
happen.

But I can think of Spore (http://spore.ea.com/) where you are able to
create things and then let them battle against others.
So you're 'programming' them, giving them bigger legs, arms, two
heads...and so on.

If you transfer this idea to normal program, I guess it comes down to this:
Every object of the program should be kept very simple, understandable
and of course independent.

The point of interfaces and/or APIs, in general, was to allow for people
to replace the implementation of the internals as necessary without
needing to rewrite everything. The problem with APIs is that
implementation details tend to leak out, and the API design may be
reasonable now, but APIs always wander, and are rarely reasonable in a
few years (or days as the case may be).

So in my eyes the Core needs to be very easy and simple, an instant
watch and you know what is happening there. And if you now want to see
how the Core reacts with other parts the only thing to do is linking
them and watch their behavior.

Again, since we have no idea what this "Core" is supposed to do,
plugging things into it may or may not be reasonable, and its
implementation via threads may or may not be reasonable.

One thing you should realize is that if you have your "Core" running in
its own thread, either you are going to need to have your GUI polling
the values within the "Core" to display them (wx.Timer()), or you are
going to need to have your "Core" telling your API that something has
changed (wx.CallAfter(), wx.PostEvent(), etc.)

To the meat of it. In looking through your code (you really should
strip all tabs, use 4 space indents, and not leave more than a few blank
lines between lines that do stuff...), I notice that on line 623 is
defined the do_action() method. It seems as though you should be able
to plug in essentially the code that I provided before to restart the
thread whenever it isn't running. Heck, here's a function you can use
that will do that, in general...

def start_if_not_running(name, fcn):
    gl = globals()
    if name not in gl:
        running = 0
    else:
        running = gl[name].isAlive()
    if not running:
        gl[name] = threading.Thread(target=fcn)
        gl[name].start()

And you use it like...

class Core:
    ...
    def run(self):
        ...

x = Core()

start_if_not_running('worker_thread', x.run)

- Josiah

···

Franz <franzlinux@gmx.de> wrote:

Josiah Carlson schrieb:

It's quite easy to have a program respond to user action. It's a bit
trickier to make the program do what the programmer wants when things
happen.

I think I have programmed something like this in a primitive form. My latest version of tape_reading is number: #16.
http://esnips.com/web/qweet-public

You can see the price always changing and can take action to this changes. You may speed the program up, set you Stop Loss, you're able to take actions of buying and selling, instantly stopping the program if you want, yes. But it's all dynamical, in my opinion.

(you really should
strip all tabs, use 4 space indents, and not leave more than a few blank
lines between lines that do stuff...)

I do this because I want to clearly see what is connected with each other and what isn't.

Thanks for the code.
Franz

Josiah Carlson schrieb:
> It's quite easy to have a program respond to user action. It's a bit
> trickier to make the program do what the programmer wants when things
> happen.

I think I have programmed something like this in a primitive form. My
latest version of tape_reading is number: #16.
http://esnips.com/web/qweet-public

What kind of time resolution would you want/need in your "Core"
processing? 1/10th of a second? 1/100th of a second? If you are happy
with x/60th a second (where x is an integer >= 1) , wxTimer events can
handle your "core" quite easily.

What you could do is to make everything happen on 1/60th second
intervals, and if your "speed" is high enough, you just perform more
than one pass through the "loop" in some/all of your intervals (the GUI
probably won't be updating any faster anyways).

You can see the price always changing and can take action to this
changes. You may speed the program up, set you Stop Loss, you're able to
take actions of buying and selling, instantly stopping the program if
you want, yes. But it's all dynamical, in my opinion.

It's interactive, and the program responds to user input. If you want
to call it "dynamic", go ahead, I'll call it an interactive simulation.

> (you really should
> strip all tabs, use 4 space indents, and not leave more than a few blank
> lines between lines that do stuff...)

I do this because I want to clearly see what is connected with each
other and what isn't.

4 spaces isn't enough to differentiate indentation levels? You need 30
lines to differentiate sections of code? Have you ever thought about
commenting? Never underestimate how clearly syntax highlighting and
sections of the below works to differentiate code.

···

Franz <franzlinux@gmx.de> wrote:

    #
    # Blah blah blah blah, oh, and blah.
    #

- Josiah