Tuesday 7 December 2010

http://svn.python.org/projects/python/trunk/Demo/pdist/rcslib.py

"""RCS interface module.Defines the class RCS, which represents a directory with rcs versionfiles and (possibly) corresponding work files."""import fnmatchimport osimport reimport stringimport tempfileclass RCS:    """RCS interface class (local filesystem version).    An instance of this class represents a directory with rcs version    files and (possible) corresponding work files.    Methods provide access to most rcs operations such as    checkin/checkout, access to the rcs metadata (revisions, logs,    branches etc.) as well as some filesystem operations such as    listing all rcs version files.    XXX BUGS / PROBLEMS    - The instance always represents the current directory so it's not    very useful to have more than one instance around simultaneously    """    # Characters allowed in work file names    okchars = string.ascii_letters + string.digits + '-_=+'    def __init__(self):        """Constructor."""        pass    def __del__(self):        """Destructor."""        pass    # --- Informational methods about a single file/revision ---    def log(self, name_rev, otherflags = ''):        """Return the full log text for NAME_REV as a string.        Optional OTHERFLAGS are passed to rlog.        """        f = self._open(name_rev, 'rlog ' + otherflags)        data = f.read()        status = self._closepipe(f)        if status:            data = data + "%s: %s" % status        elif data[-1] == '\n':            data = data[:-1]        return data    def head(self, name_rev):        """Return the head revision for NAME_REV"""        dict = self.info(name_rev)        return dict['head']    def info(self, name_rev):        """Return a dictionary of info (from rlog -h) for NAME_REV        The dictionary's keys are the keywords that rlog prints        (e.g. 'head' and its values are the corresponding data        (e.g. '1.3').        XXX symbolic names and locks are not returned        """        f = self._open(name_rev, 'rlog -h')        dict = {}        while 1:            line = f.readline()            if not line: break            if line[0] == '\t':                # XXX could be a lock or symbolic name                # Anything else?                continue            i = string.find(line, ':')            if i > 0:                key, value = line[:i], string.strip(line[i+1:])                dict[key] = value        status = self._closepipe(f)        if status:            raise IOError, status        return dict    # --- Methods that change files ---    def lock(self, name_rev):        """Set an rcs lock on NAME_REV."""        name, rev = self.checkfile(name_rev)        cmd = "rcs -l%s %s" % (rev, name)        return self._system(cmd)    def unlock(self, name_rev):        """Clear an rcs lock on NAME_REV."""        name, rev = self.checkfile(name_rev)        cmd = "rcs -u%s %s" % (rev, name)        return self._system(cmd)    def checkout(self, name_rev, withlock=0, otherflags=""):        """Check out NAME_REV to its work file.        If optional WITHLOCK is set, check out locked, else unlocked.        The optional OTHERFLAGS is passed to co without        interpretation.        Any output from co goes to directly to stdout.        """        name, rev = self.checkfile(name_rev)        if withlock: lockflag = "-l"        else: lockflag = "-u"        cmd = 'co %s%s %s %s' % (lockflag, rev, otherflags, name)        return self._system(cmd)    def checkin(self, name_rev, message=None, otherflags=""):        """Check in NAME_REV from its work file.        The optional MESSAGE argument becomes the checkin message        (default "<none>" if None); or the file description if this is        a new file.        The optional OTHERFLAGS argument is passed to ci without        interpretation.        Any output from ci goes to directly to stdout.        """        name, rev = self._unmangle(name_rev)        new = not self.isvalid(name)        if not message: message = "<none>"        if message and message[-1] != '\n':            message = message + '\n'        lockflag = "-u"        if new:            f = tempfile.NamedTemporaryFile()            f.write(message)            f.flush()            cmd = 'ci %s%s -t%s %s %s' % \                  (lockflag, rev, f.name, otherflags, name)        else:            message = re.sub(r'([\"$`])', r'\\\1', message)            cmd = 'ci %s%s -m"%s" %s %s' % \                  (lockflag, rev, message, otherflags, name)        return self._system(cmd)    # --- Exported support methods ---    def listfiles(self, pat = None):        """Return a list of all version files matching optional PATTERN."""        files = os.listdir(os.curdir)        files = filter(self._isrcs, files)        if os.path.isdir('RCS'):            files2 = os.listdir('RCS')            files2 = filter(self._isrcs, files2)            files = files + files2        files = map(self.realname, files)        return self._filter(files, pat)    def isvalid(self, name):        """Test whether NAME has a version file associated."""        namev = self.rcsname(name)        return (os.path.isfile(namev) or                os.path.isfile(os.path.join('RCS', namev)))    def rcsname(self, name):        """Return the pathname of the version file for NAME.        The argument can be a work file name or a version file name.        If the version file does not exist, the name of the version        file that would be created by "ci" is returned.        """        if self._isrcs(name): namev = name        else: namev = name + ',v'        if os.path.isfile(namev): return namev        namev = os.path.join('RCS', os.path.basename(namev))        if os.path.isfile(namev): return namev        if os.path.isdir('RCS'):            return os.path.join('RCS', namev)        else:            return namev    def realname(self, namev):        """Return the pathname of the work file for NAME.        The argument can be a work file name or a version file name.        If the work file does not exist, the name of the work file        that would be created by "co" is returned.        """        if self._isrcs(namev): name = namev[:-2]        else: name = namev        if os.path.isfile(name): return name        name = os.path.basename(name)        return name    def islocked(self, name_rev):        """Test whether FILE (which must have a version file) is locked.        XXX This does not tell you which revision number is locked and        ignores any revision you may pass in (by virtue of using rlog        -L -R).        """        f = self._open(name_rev, 'rlog -L -R')        line = f.readline()        status = self._closepipe(f)        if status:            raise IOError, status        if not line: return None        if line[-1] == '\n':            line = line[:-1]        return self.realname(name_rev) == self.realname(line)    def checkfile(self, name_rev):        """Normalize NAME_REV into a (NAME, REV) tuple.        Raise an exception if there is no corresponding version file.        """        name, rev = self._unmangle(name_rev)        if not self.isvalid(name):            raise os.error, 'not an rcs file %r' % (name,)        return name, rev    # --- Internal methods ---    def _open(self, name_rev, cmd = 'co -p', rflag = '-r'):        """INTERNAL: open a read pipe to NAME_REV using optional COMMAND.        Optional FLAG is used to indicate the revision (default -r).        Default COMMAND is "co -p".        Return a file object connected by a pipe to the command's        output.        """        name, rev = self.checkfile(name_rev)        namev = self.rcsname(name)        if rev:            cmd = cmd + ' ' + rflag + rev        return os.popen("%s %r" % (cmd, namev))    def _unmangle(self, name_rev):        """INTERNAL: Normalize NAME_REV argument to (NAME, REV) tuple.        Raise an exception if NAME contains invalid characters.        A NAME_REV argument is either NAME string (implying REV='') or        a tuple of the form (NAME, REV).        """        if type(name_rev) == type(''):            name_rev = name, rev = name_rev, ''        else:            name, rev = name_rev        for c in rev:            if c not in self.okchars:                raise ValueError, "bad char in rev"        return name_rev    def _closepipe(self, f):        """INTERNAL: Close PIPE and print its exit status if nonzero."""        sts = f.close()        if not sts: return None        detail, reason = divmod(sts, 256)        if reason == 0: return 'exit', detail   # Exit status        signal = reason&0x7F        if signal == 0x7F:            code = 'stopped'            signal = detail        else:            code = 'killed'        if reason&0x80:            code = code + '(coredump)'        return code, signal    def _system(self, cmd):        """INTERNAL: run COMMAND in a subshell.        Standard input for the command is taken from /dev/null.        Raise IOError when the exit status is not zero.        Return whatever the calling method should return; normally        None.        A derived class may override this method and redefine it to        capture stdout/stderr of the command and return it.        """        cmd = cmd + " </dev/null"        sts = os.system(cmd)        if sts: raise IOError, "command exit status %d" % sts    def _filter(self, files, pat = None):        """INTERNAL: Return a sorted copy of the given list of FILES.        If a second PATTERN argument is given, only files matching it        are kept.  No check for valid filenames is made.        """        if pat:            def keep(name, pat = pat):                return fnmatch.fnmatch(name, pat)            files = filter(keep, files)        else:            files = files[:]        files.sort()        return files    def _remove(self, fn):        """INTERNAL: remove FILE without complaints."""        try:            os.unlink(fn)        except os.error:            pass    def _isrcs(self, name):        """INTERNAL: Test whether NAME ends in ',v'."""        return name[-2:] == ',v'

Posted via email from kwhitefoot's posterous

Wednesday 1 December 2010

BBP formula in Python

See http://mathworld.wolfram.com/BBPFormula.html

Not the most efficient Python but it works.


def x(n):
    return (4.0/(8*n+1)-2.0/(8*n+4) - 1.0/(8*n+5) -1.0/(8*n+6))*((1.0/16)**n)

def pi(n):
    s = 0
    for i in range(n):
        s+=x(i)
    return s


>>> pi(1)
3.1333333333333333
>>> pi(2)
3.1414224664224664
>>> pi(4)
3.1415924575674357
>>> pi(10)
3.1415926535897913
>>> pi(20)
3.141592653589793
>>> pi(40)
3.141592653589793

 

Posted via email from kwhitefoot's posterous

Sunday 14 November 2010

Monday 1 November 2010

Deleted posts on Guardian Cif

kwhitefoot

31 October 2010 8:54PM

I think I'll have to start archiving these comments myself. Ostmark's has been deleted and so has the reply but worse the fact of the reply has disappeared as well.

BeautifulBurnout

31 October 2010 9:13PM

kwhitefoot

I know! It is really annoying when you craft a response to a bunch of nonsense, only to find that cos the nonsense has been deleted, your own post is zapped into the ether as well!

At least it wasn't really long and difficult to do...

kwhitefoot

31 October 2010 9:54PM

As an antidote to the Guardian's occasional lapse into the covering up of Cif history I have installed a Firefox add-on called History Search that takes snapshots of every page you visit every time you visit so that you can search in the history of the page. So, if a comment unexpectedly disappears and you have a feeling that it said something important, relevant, or merely amusing, you can at least satisfy your own curiosity. Of course one could also repost the offending comment either on Cif or elsewhere. You can find it at https://addons.mozilla.org/en-US/firefox/addon/7028/

Perhaps Cif should consider disemvowelling as on Boing-Boing and ScienceBlogs instead of outright deletion.

This one hasn't been deleted yet:

kwhitefoot

1 November 2010 7:36AM

This is getting silly. The moderator has now removed my post that began:


31 October 2010 9:54PM

As an antidote to the Guardian's occasional lapse into the covering up of Cif history I have installed a Firefox add-on called History Search

Several of BeautifulBurnout's comments that referred to either me or Ostmark have also disappeared.

In a thread that is all about access to information and exercise of civil liberty it seems strange that the moderators should be both anonymous and arbitrary and that they do not have the courtesy to explain to the commenter even briefly why the comment has been deleted.

 

Posted via email from kwhitefoot's posterous

Sunday 24 October 2010

The enemy of your enemy isn't your friend: He's just the next enemy in a long line of enemies who could have been your friend if it weren't for the fact that you keep seeing enemies everywhere.

From El Reg:

The enemy of my enemy 

OK the military might have a valid point about putting lives at risk, but you have to wonder how organisations like the Taliban have managed to garner enough support to warrant going after them with guns.

Well the reason why is - we gave them guns and ammo during the Cold War in an attempt to dislodge the Russians from Afghanistan and it all kinda snowballed from there. We weren't that bothered that this might be a problem at the time because they were keeping the Russians away from us. Unfortunately this attitude seems to have gotten us into a spot of bother.

So the question is, seeing as this "arm them and don't be too concerned with the consequences" would seem to be a repeated pattern of behaviour (at least as US foreign policy is concerned), who the hell are we arming right now? Because it will be them - whoever they are - that we have to deal with next. In fact if we are currently arming someone else in the next phase of whatever ideological battle we're supposed to be having maybe we should be learning from recent history and not repeating the same behaviour over and over again?

The enemy of your enemy isn't your friend: He's just the next enemy in a long line of enemies who could have been your friend if it weren't for the fact that you keep seeing enemies everywhere.

I hope AC doesn't mind my reposting this.  The final sentence says it all so well.

Posted via email from kwhitefoot's posterous

The enemy of your enemy isn't your friend: He's just the next enemy in a long line of enemies who could have been your friend if it weren't for the fact that you keep seeing enemies everywhere.

From El Reg:

The enemy of my enemy 

OK the military might have a valid point about putting lives at risk, but you have to wonder how organisations like the Taliban have managed to garner enough support to warrant going after them with guns.

Well the reason why is - we gave them guns and ammo during the Cold War in an attempt to dislodge the Russians from Afghanistan and it all kinda snowballed from there. We weren't that bothered that this might be a problem at the time because they were keeping the Russians away from us. Unfortunately this attitude seems to have gotten us into a spot of bother.

So the question is, seeing as this "arm them and don't be too concerned with the consequences" would seem to be a repeated pattern of behaviour (at least as US foreign policy is concerned), who the hell are we arming right now? Because it will be them - whoever they are - that we have to deal with next. In fact if we are currently arming someone else in the next phase of whatever ideological battle we're supposed to be having maybe we should be learning from recent history and not repeating the same behaviour over and over again?

The enemy of your enemy isn't your friend: He's just the next enemy in a long line of enemies who could have been your friend if it weren't for the fact that you keep seeing enemies everywhere.

I hope AC doesn't mind my reposting this.  The final sentence says it all so well.

Posted via email from kwhitefoot's posterous

Friday 8 October 2010

... on Twitpic

TEACHINGS OF DIOGENES

From http://members.optushome.com.au/davidquinn000/Diogenes%20Folder/Diogenes.html *** Plato was discoursing on his theory of ideas and, pointing to the cups on the table before him, said while there are many cups in the world, there is only one `idea' of a cup, and this cupness precedes the existence of all particular cups. "I can see the cup on the table," interupted Diogenes, "but I can't see the `cupness'". "That's because you have the eyes to see the cup," said Plato, "but", tapping his head with his forefinger, "you don't have the intellect with which to comprehend `cupness'." Diogenes walked up to the table, examined a cup and, looking inside, asked, "Is it empty?" Plato nodded. "Where is the `emptiness' which procedes this empty cup?" asked Diogenes. Plato allowed himself a few moments to collect his thoughts, but Diogenes reached over and, tapping Plato's head with his finger, said "I think you will find here is the `emptiness'." ***

Posted via email from kwhitefoot's posterous

Saturday 2 October 2010

Parallel port output in Linux with Python

Parallel port output

 

http://pyserial.sourceforge.net/pyparallel.html

http://www.hare.demon.co.uk/ioport/ioport.html

http://bigasterisk.com/projects/parallel

http://www.ladyada.net/make/spokepov/download.html

http://book.opensourceproject.org.cn/kernel/kernelpri/index.html?page=opensource/0131181637/ch05lev1sec4.html

 

pyParallel

On Ubuntu 10.04 pyParallel can be installed from Synaptic.

Then start python:

>>> import parallel

>>> p=parallel.Parallel()

but that won't work

unless you first make /dev/parpart0 writable

# sudo chmod o+wr /dev/parport0

and unload the lp module

# sudo rmmod lp

For permanent changes it is best to add the user to the lp group instead of changing the permissions.  You still need to unload the lp module though.  Presumably you can do this in the init scripts.

 

 

 

Posted via email from kwhitefoot's posterous

Tuesday 28 September 2010

Fetch email from gmail by command

Well I don't really want to fetch email, I want to be able to get my backups back.

But getting the email is a start.  Here are some pages that describe how:

 

Posted via email from kwhitefoot's posterous

Send email from the command line to gmail

Just some notes about what works and what is simple.

Works and is simple

http://www.debianadmin.com/how-to-sendemail-from-the-command-line-using-a-gma...

You can install sendEmail via Synaptic in Ubuntu but you will need to also install

  • libio-socket-ssl-perl
  • libnet-ssleay-perl
  • perl

You can, of course, just tell Synaptic to do that.  You can also do it all from the command line:

$ sudo apt-get install sendemail libio-socket-ssl-perl libnet-ssleay-perl perl

 

Caveats and questions

sendEmail can use tls authentication but presumably this does not mean that the actual traffic is secure.  Of course email is normally transmitted in the clear anyway so this might not be a problem; however, if you are using this to backup confidential files to your gmail account you should try to use secure sockets to secure the connection against eavesdroppers.  And, especially in the light of recent reports of a Google employee snooping on email, you should encrypt the files themselves.

So the question: can sendEmail use SSL?

Posted via email from kwhitefoot's posterous

Wednesday 22 September 2010

Buffered csp oscilloscope

Add a buffer process so that the oscilloscope gets a whole frame at once.  the buffer process triggers on positive zero crossings.

traces.py

#!/usr/bin/env python

#
# Example oscilloscope traces.
#

import sys
from csp.csp import *
from csp.builtins import Sin, Cos, GenerateFloats, Mux2, Delta2
from bscope import Oscilloscope


@forever
def Random(outchan):
    """Random process.

    Generates random data and writes it to outchan.
    """
    import random
    while True:
        outchan.write(random.random())
        yield
    return


@forever
def Buffer(inchan, outchan):
    """Buffer one frame and send as a list.  This version simply uses
    a literal constant frame size which should mathc that used in
    oscilloscope.py.
    """
    a = []
    while True:
        y = inchan.read()
        a.append(y)
        if len(a) == 512:
            outchan.write(a)
            a = []
        yield

@forever
def TriggeredBuffer(inchan, outchan):
    """Buffer one frame and send as a list.  This version simply uses
    a literal constant frame size which should mathc that used in
    oscilloscope.py.

    Waits for positive going zero crossing.
    """
    a = []
    armed = False
    while True:
        y = inchan.read()
        if 0 < len(a):
            a.append(y)
            if len(a) == 512:
                outchan.write(a)
                a = []
                armed = False
        elif armed:
            if yp < y and 0 <= y:
                a.append(y);
        elif y < 0:
            armed = True
        yp = y
        yield

def trace_random():
    """Test the Oscilloscope with random data.
    """
    channel = Channel()
    par = Par(Random(channel), Oscilloscope(channel))
    par.start()
    return


def trace_sin():
    """Plot a sine wave on the oscilloscope.
    """
    channels = Channel(), Channel()
    par = Par(GenerateFloats(channels[0]),
              Sin(channels[0], channels[1]),
              Oscilloscope(channels[1]))
    par.start()
    return   


def trace_cos():
    """Plot a cosine wave on the oscilloscope.
    """
    channels = Channel(), Channel(), Channel()
    par = Par(GenerateFloats(channels[0]),
              Cos(channels[0], channels[1]),
              TriggeredBuffer(channels[1],channels[2]),
              Oscilloscope(channels[2]))
    par.start()
    return   


def trace_mux():
    """Plot sine and cosine waves on the oscilloscope.
    """
    channels = [Channel() for i in range(6)]
    par = Par(GenerateFloats(channels[0]),
              Delta2(channels[0], channels[1], channels[2]),
              Cos(channels[1], channels[3]),
              Sin(channels[2], channels[4]),
              Mux2(channels[3], channels[4], channels[5]),
              Oscilloscope(channels[5]))
    par.start()
    return   

EXAMPLES = {}
for name, func in globals().items():
    if name.startswith('trace_'):
        EXAMPLES[name[6:]] = func

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print('Syntax: python {0} {1}'.format(sys.argv[0],
                                              ' | '.join(EXAMPLES.keys())))
        for name, func in EXAMPLES.items():
            print(' {0:<9} {1}'.format(name, func.func_doc.strip()))
    elif sys.argv[1] not in EXAMPLES:
        print('Unknown example {0}'.format(sys.argv[1]))
    else:
        print('Use cursor up/down for scaling, s for save and q for quit')
        EXAMPLES[sys.argv[1]]()

bscope.py

#!/usr/bin/env python

"""
Simple oscilloscope traces for python-csp.
Requires Pygame.

Features:
    * Press 's' to save an oscilloscope trace as a PNG.
    * Press UP and DOWN to scale the input more / less.

Copyright (C) Sarah Mount, 2009.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

Changes: (C) Kevin Whitefoot, 2010 

  Allow sender to send a complete frame instead of just a single new sample.

"""


from csp.csp import *

import copy
import numpy
import pygame


__author__ = 'Sarah Mount <s.mount@wlv.ac.uk>'
__date__ = 'November 2009'
__version__ = '0.2'


@forever
def Oscilloscope(inchan, scale=80.0, _process=None):
    # Constants
    WIDTH, HEIGHT = 512, 256
    TRACE, GREY = (80, 255, 100), (110, 110, 110)
    caption = 'Oscilloscope'
    filename = caption + '.png'
    # Open window
    pygame.init()
    screen = pygame.display.set_mode((WIDTH, HEIGHT), 0)
    pygame.display.set_caption(caption)
    # Create a blank chart with vertical ticks, etc
    blank = numpy.zeros((WIDTH, HEIGHT, 3), dtype=numpy.int8)
    # Draw x-axis
    xaxis = HEIGHT // 2
    blank[::, xaxis] = GREY
    # Draw vertical ticks
    vticks = [-100, -50, +50, +100]
    for vtick in vticks: blank[::5, xaxis + vtick] = GREY # Horizontals
    blank[::50, ::5] = GREY          # Verticals
    # Draw the 'blank' screen.
    pygame.surfarray.blit_array(screen, blank)      # Blit the screen buffer
    pygame.display.flip()                           # Flip the double buffer
    # ydata stores data for the trace.
    ydata = [0.0 for i in range(WIDTH)] # assert len(ydata) <= WIDTH

    QUIT = False
    while not QUIT:

        pixels = copy.copy(blank)
        indata = inchan.read()       
        if type(indata) == list: 
            # We have  been sent a complete frame  
            ydata = map(lambda(x): x*scale, indata)    
        else:  
            # we only have one new point  
            ydata.append(inchan.read() * scale)
            ydata.pop(0)

        for x in range(WIDTH):
            try: pixels[x][xaxis - int(ydata[x])] = TRACE
            except: pass
        pygame.surfarray.blit_array(screen, pixels)     # Blit the screen buffer
        pygame.display.flip()                           # Flip the double buffer
        #pygame.display.update(0, xaxis-100, WIDTH, 201) # Flip the double buffer
        del pixels # Use constant space.
        for event in pygame.event.get():
            if event.type == pygame.QUIT \
            or event.type == pygame.KEYDOWN and event.key == pygame.K_q:
                QUIT = True
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_s:
                pygame.image.save(screen, filename)
                print('Saving oscope image in: ' + str ( filename ) )
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_UP:
                scale += 10.0
                print('Oscilloscope scaling by %f' % scale)
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN:
                if scale - 10.0 > 0.0: scale -= 10.0
                print('Oscilloscope scaling by %f' % scale)
        yield
    inchan.poison()
    pygame.display.quit()
    return


if __name__ == '__main__':
    print('For this tutorial run traces.py')

Posted via email from kwhitefoot's posterous

CSP Oscilloscope

See http://python-csp.googlecode.com/hg/tutorial/part07/oscilloscope.py

 

#!/usr/bin/env python  """ Simple oscilloscope traces for python-csp. Requires Pygame.  Features: * Press 's' to save an oscilloscope trace as a PNG. * Press UP and DOWN to scale the input more / less.  Copyright (C) Sarah Mount, 2009.  This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.  You should have rceeived a copy of the GNU General Public License along with this program.  If not, see <http://www.gnu.org/licenses/>. Changes: (C) Kevin Whitefoot, 2010  Allow for sender to send a complete frame instead of just a single new sample."""   from csp.csp import *  import copy import numpy import pygame   __author__ = 'Sarah Mount <s.mount@wlv.ac.uk>' __date__ = 'November 2009' __version__ = '0.2'   @forever def Oscilloscope(inchan, scale=80.0, _process=None): # Constants WIDTH, HEIGHT = 512, 256 TRACE, GREY = (80, 255, 100), (110, 110, 110) caption = 'Oscilloscope' filename = caption + '.png' # Open window pygame.init() screen = pygame.display.set_mode((WIDTH, HEIGHT), 0) pygame.display.set_caption(caption) # Create a blank chart with vertical ticks, etc blank = numpy.zeros((WIDTH, HEIGHT, 3), dtype=numpy.int8) # Draw x-axis xaxis = HEIGHT // 2 blank[::, xaxis] = GREY # Draw vertical ticks vticks = [-100, -50, +50, +100] for vtick in vticks: blank[::5, xaxis + vtick] = GREY # Horizontals blank[::50, ::5] = GREY          # Verticals # Draw the 'blank' screen. pygame.surfarray.blit_array(screen, blank)      # Blit the screen buffer pygame.display.flip()                           # Flip the double buffer # ydata stores data for the trace. ydata = [0.0 for i in range(WIDTH)] # assert len(ydata) <= WIDTH QUIT = False while not QUIT: pixels = copy.copy(blank) indata = inchan.read()        if type(indata).name == 'list':            # We have  been sent a complete frame            ydata = map(lambda(x) x*scale, indata)        else:            # we only have one new point            ydata.append(inchan.read() * scale)         ydata.pop(0) for x in range(WIDTH): try: pixels[x][xaxis - int(ydata[x])] = TRACE except: pass pygame.surfarray.blit_array(screen, pixels)     # Blit the screen buffer pygame.display.flip()                           # Flip the double buffer #pygame.display.update(0, xaxis-100, WIDTH, 201) # Flip the double buffer del pixels # Use constant space. for event in pygame.event.get(): if event.type == pygame.QUIT \ or event.type == pygame.KEYDOWN and event.key == pygame.K_q: QUIT = True elif event.type == pygame.KEYDOWN and event.key == pygame.K_s: pygame.image.save(screen, filename) print('Saving oscope image in: ' + str ( filename ) ) elif event.type == pygame.KEYDOWN and event.key == pygame.K_UP: scale += 10.0 print('Oscilloscope scaling by %f' % scale) elif event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN: if scale - 10.0 > 0.0: scale -= 10.0 print('Oscilloscope scaling by %f' % scale) yield inchan.poison() pygame.display.quit() return   if __name__ == '__main__': print('For this tutorial run traces.py')

Posted via email from kwhitefoot's posterous

Monday 20 September 2010

Electric.py


Electric.py

We need several processes, some explicitly created, others implicitly.

Use Tkinter for the UI.

Meter process reads audio and calculates rms puts value into queue.
Queue size is one item to ensure that we catch underrun errors in the
consumer.  Meter process will typically take 0.5 second samples.
Meter is a daemon process, it needs no input except for arguments to
construction.

The queue used is a common queue so the item must be a tuple where the
first item is a tag saying what the second means.  The queue is used
by the UI to send requests to the relay process.  This means that the
relay process need only wait on one queue instead of repeatedly
polling several queues.  Would be cleaner to use Occam's ALT function
but there appears to be no equivalent in Python (or Erlang for that
matter).

How about python-csp?

Posted via email from kwhitefoot's posterous

Saturday 18 September 2010

Python GUI

Emacs

I hate the Winows/CUA binding for the Home and End keys.  To make them go to the start and end of the document instead of the line add this to .emacs:

(global-set-key [kp-home]  'beginning-of-buffer) ; [Home]
(global-set-key [home]     'beginning-of-buffer) ; [Home]
(global-set-key [kp-end]   'end-of-buffer)       ; [End]
(global-set-key [end]      'end-of-buffer)       ; [End]

Many thanks to http://geosoft.no/development/emacs.html

Posted via email from kwhitefoot's posterous

Friday 17 September 2010

Sunday 12 September 2010

Wednesday 8 September 2010

-inurl:(htm|html|php) intitle:"index of" "last modified" "parent directory" description size (wma|mp3|ogg) "subirana" - Google Search

Why on earth should a search for Roger Subirana's music return a page saying that some items have been suppressed because of a DMCA take down notice (http://www.chillingeffects.org/notice.cgi?sID=26607)? As far as I know he has released everything under a Creative Commons license.

Posted via email from kwhitefoot's posterous

-inurl:(htm|html|php) intitle:"index of" "last modified" "parent directory" description size (wma|mp3|ogg) "subirana" - Google Search

Why on earth should a search for Roger Subirana's music return a page saying that some items have been suppressed because of a DMCA take down notice (http://www.chillingeffects.org/notice.cgi?sID=26607)? As far as I know he has released everything under a Creative Commons license.

Posted via email from kwhitefoot's posterous

IP Catcher - Link Record Log

If you want to reveal your IP address to me (as opposed to Posterous' server) you can click this link: http://s33.net/rec/?id=2jpx6 It will take you to www.google.com.

Posted via email from kwhitefoot's posterous

Sunday 29 August 2010

Flashcards on Symbian with Python

This program lets you use sets of flashcards downloaded from flashcarddb.com (or made yourself).  The cards must be lines withe front and back separated by @ signs.

'''
 Simplified Leitner.
 For use with decks from Flashcarddb.com exported with @ separators.

 Copyright 2010, Kevin Whitefoot <kwhitefoot@hotmail.com>

 License: use as you will so long as you maintain the credits.

 Language: mshell <http://www.m-shell.net>

 Method:

 See http://flashcarddb.com/leitner


Notes:

- My mobile has Python 2.2.2 so string formatting has to be done with
  the % operator not string interpolation.


'''


''' Decide if we are running in a terminal or on the mobile.  Note
that this probably only works for *nix not Windows.

Adapted from
http://www.gossamer-threads.com/lists/python/python/379465

'''
import sys
import time
import os
import os.path


def emitmobile(s):
    # Must set the cursor position because the up arrow key is
    # passed to the normal handler as well as ours so it moves the
    # cursor.
    text.set_pos(text.len())
    text.add('\n' + s)
    text.set_pos(text.len())


def emitterminal(s):
    print s


try:
    import tty, termios
   
    runningOnMobile = False
    emit = emitterminal
    def getch():
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
            return ch
except:
    # '... choose Symbian stuff instead'
    runningOnMobile = True
    emit = emitmobile


CmdCorrect = 1
CmdWrong = 2
CmdQuit  = 3
CmdAllDone = 4


'''
Return true if user is correct.
'''
def getcmd():
    if runningOnMobile:
        pass
    else:
        ch = getch()
        if ord(ch) == 27: # escape
            ch = getch()
            c = ord(getch())
            if c == 65:
                return CmdCorrect
            elif c in [53, 54]:
                ch =getch()
                return CmdWrong
            else:
                return CmdWrong
        elif ch ==  'q':
            return CmdQuit
        else:
            return CmdWrong
               
       

"""

 Initialize some tables, etc.
See http:# flashcarddb.com/leitner
Deck
Number    Time until next repetition
One    None
Two    1 day
Three    3 days
Four    1 week
Five    1 month
"""
oneday = 24*60*60 #  seconds in a day
expiry = [0, 0, 1 * oneday, 3 * oneday, 7 * oneday, 30 * oneday]

lsLoaded=0
lsLoadedWithDuplicates = 1
lsZeroLength = 2
lsTooManyStates = 3
lsTooFewStates = 4

""" debug
Set verbosity higher to generate more logging output.
"""
verbosity = 0

def verbose(n, s):
    if n < verbosity :
        print s
  # end
# end


class Card:
    """ Cards are simple data structures that can be read from an open
    text file.  A card has a front and a back.  They are never
    modified by the program.
    """
    # front
    # back

    #  f is an open file
    def load(self, line):
        i = line.index("@")
        self.front = line[0:i].strip()                
        self.back = line[i+1:].strip()       


    #  f is an open file
    def save(self, file)          :
        file.writeline(front + u"@" + back)
    # end


    #  f is an open file
    def __init__(self, line):
        self.load(line)
    # end

# end


class Cards:
    """Cards is a list of Card instances in the order they were found
    in a file.  The file name is generated from the set name by
    appending .cards. 
    """
    # cards
    # setname
   
   
    def count(self):
        return len(self.cards)
    # end


    def filename(self):
        return os.path.join(pathname,self.setname) + u".cards"                
    # end


    def get(self, i):
        return self.cards[i]                
    # end


    def add(self, c):
        self.cards.append(c)                
    # end
       

    #  f is an open file
    def load(self):
        t = time.time()
        f = open(self.filename())                
        for line in f :
            c = Card(line)                
            self.add(c)                
        # end
        d = time.time()-t
        # emit(u"Cards.load: {0} cards in {1} seconds".format(len(self.cards), d))
        emit(u"Cards.load: %s cards in %s seconds" % (len(self.cards), d))
    # end


    def __init__(self, setname):
        self.setname = setname                
        self.cards = []                
        self.load()  
    # end


    #  f is an open file
    def save(self, f):
        c = null
        for c in self.cards:
            c.save(f)                
    # end
  # end
   
# end

class CardState:
    """
    The state of each card is stored in a card state object.  These
    objects are stored in a file that is updated every time a card
    changes state. To save time the new stte is simply appended to the
    end of the file.  When reading the file back later entries for the
    same card overwrite the newer ones.  The state is : written out
    again so that the file does not grow indefinitely.
    """

    # card #  index into array of cards.
    # deck #  number of the deck to which this card belongs.
    # expires #  date at which the card should be reviewed expressed as
    #  seconds from the start of the epoch.


    def getcard(self, cards):
        return cards.get(self.card)
    # end


    def __init__(self, card, deck):
        self.card = card
        self.deck = deck
        self.expires = 0
    # end


    def loadfromstr(self, s):
        a = s.split()
        self.card = int(a[0])
        self.deck = int(a[1])
        self.expires = float(a[2])
    # end


    #  f is an open file
    def load(self, file):
        s = io.readln(file)
        self.loadfromstr(s)
    # end


    #  f is an open file
    def save(self, file):
        file.write("%s %s %s\n" % (self.card, self.deck, self.expires))
    # end


    def promote(self):
        if self.deck < 5 :
            self.deck += 1                
        # end
        self.expires = time.time() + expiry[self.deck]
    # end


    def demote(self):
        self.deck = 1
        self.expires = 0
    # end

# end


"""

"""
class CardStates:

    # cards:Cards
    # cardstates #  array of CardState
    # setname
   
   
    def get(self, i):
        return self.cardstates[i]
    # end


    def card(self, i):
        cs = self.cardstates[i]
        return cs.getcard(self.cards)
  # end


    def count(self):
        return self.cards.count()
  # end


    def filename(self):
        return os.path.join(pathname,self.setname) + u".state"                
  # end


    def savestate(self):
        # emit(u"CardStates.savestate {0} states".format(len(self.cardstates)))
        emit(u"CardStates.savestate %s states" % (len(self.cardstates)))
        f = open(self.filename(),'w')
       
        for cs in self.cardstates :
            cs.save(f)
        # end
        f.close()                
    # end


    def loadstate(self):
        """
        Returns a code indicating the result.  It can happen that the
        user will update the cards file.  In such a case the states file
        will have to be updated to match.
        """
        t = time.time()
        f = open(self.filename(), 'r')
        cr = 0 #  count read
        cu = 0 #  count used
        lc = self.cards.count()
        # Initialize array of cardstates to empty .
        for i in range(lc):
            self.cardstates.append(None)
        for s in f:
            cr += 1 #  count how many we read so that we can tell if
                    #  there were duplicates
            cs = CardState(0, 0)
            cs.loadfromstr(s)
            if cs.card < lc :
                #  Note that we do not just append because we want to ensure
                #  that later duplicates override the earlier ones
                if self.cardstates[cs.card] == None :
                    cu += 1
                # end
                #  overwrite even if was not null.
                self.cardstates[cs.card] = cs
            else:
                #  do nothing, discard state for non-existent card
                pass
                # end
                # end
            if s == None:
                break
        f.close #  want to open it for writing again.
        # emit(u"CardStates load: {0} states in {1} seconds".format(cr, time.time()-t))
        # emit(u"               : {0} state used".format(cu))
        emit(u"CardStates load: %s states in %s seconds" % (cr, time.time()-t))
        emit(u"               : %s state used" % (cu))
        if cu < lc :
            #  some cards do not have a state.  This happens when the user
            #  overwrites the cards file with a new longer (more lines)
            #  file.
            return lsTooFewStates
        elif cr != cu :
            #  some cards had duplicate state records this is not a bug, it
            #  happens because when we write a new state record we do just
            #  that instead of rewriting the whole state file.  When we start
            #  the program we remove the duplicates and rewrite the file.
            return lsLoadedWithDuplicates
        else:
            return lsLoaded
        # end
        # end


    def cardstate(self, card):
        return self.cardstates[card]
    # end


    def savecardstate(self, card):
        f = open(self.filename(), "a")
        # cs:CardState = cardstates[card]
        self.cardstate(card).save(f)
        f.close()
    # end


    def promote(self, card):
        cs = self.cardstates[card]
        cs.promote()
        self.savecardstate(card)
    # end


    def demote(self, card):
        cs = self.cardstates[card]
        cs.demote()
        self.savecardstate(card)
  # end


    def initstate(self):
        #  not found, first time
        for i in range(self.cards.count()):
            cs = CardState(i, 1)
            self.cardstates.append(cs)
        # end
        self.savestate()
    # end

 
    def qfixupstates(self):
        """ Attempt to add states for cards added to the cards file
        and remove states that are no longer needed.  At this stage
        the cardstates and cards list are both ordered by card number
        so all we have to do is look for nulls in the cardstates list.
    """
        emit(u"CardStates.qfixupstates")
        for i in range(len(self.cardstates)):
            cs = self.cardstates[i]
            if cs == None :
                #  no state for this card so add one in deck 1.
                self.cardstates[i] = CardState(i, 1)
            # end
            # end
            # end


    def __init__(self, setname):
        self.setname = setname                
        self.cardstates = []
        self.cards = Cards(setname)
        if os.path.exists(self.filename()) :
            r = self.loadstate()
            if r == lsTooFewStates :
                self.qfixupstates()
                self.savestate()
            elif r == lsTooManyStates :
                self.qfixupstates()
                self.savestate()
            elif r == lsZeroLength :
                self.initstate()
                self.savestate()
            elif r == lsLoadedWithDuplicates :
                #  Save the state to remove duplicates
                self.savestate()
                pass
            elif r == lsLoaded :
                #  success, nothing to do
                pass
            else:
                emit(u"Unxpected result from loadstates: %s" % (r))
            # end
        else:
            self.initstate()
        # end
        # end


    def getnext(self, currentcard):
        now = time.time()
        c = self.count()
        cc = currentcard
       
        while cc+1 < c:
            cc += 1                
            e = self.cardstate(cc).expires
            if e <= now :
                return cc                
        return -1                
    # end

# end
   
# States
ShowingFront = 0
ShowingBack = 1

class Flash_Set:

    # setname
    # cardstates # :CardStates
   
    # currentcard
    # currentdeck
   
   
    #  Load from disk if possible.
    def __init__(self, name):
        self.setname = name                
        self.cardstates = CardStates(name)                
        self.currentcard = -1                
        self.currentdeck = 1                
        self.state = 0
        # A hack to let me overcome the fact that the cursor in a text
        # object is moved by the navigation keys
        self.timer = e32.Ao_timer()


    def getnext(self):
        c =  self.cardstates.getnext(self.currentcard)
        if c != -1 :
            return c                
        # end
       
        #  Ran off the end so check from beginning again in case any have been demoted.
        emit(u"Studied all cards due today, checking for demoted cards.")
        self.currentcard = -1
        return self.cardstates.getnext(self.currentcard)
   
    # end


    def promote(self):
        self.cardstates.promote(self.currentcard)
    # end


    def demote(self):
        self.cardstates.demote(self.currentcard)                
    # end

    def showfront(self):
        """Show the front of the current card.
        """
        self.currentcard = self.getnext()      
        if self.currentcard == -1 :
            return CmdAllDone
        self.current = self.cardstates.card(self.currentcard)
        # emit(u"{0} {1} {2}".format(self.currentdeck, self.currentcard, c.front))
        emit(u"%s %s %s" % (self.currentdeck, self.currentcard, self.current.front))
        self.state = ShowingFront


    '''
    Return true if all shown or quit.
    '''
    def shownext(self):
       
        self.showfront()
       
        #  wait for user to click a key, don't care what unless it is quit.
        k = getcmd()
        if k == CmdQuit:
            return k

        #  show the back of the card                
        # print c
        emit(self.current.back)                

        #  wait for user to respond
        k = getcmd()
        if k == CmdCorrect:
            self.promote()
        elif k == CmdWrong:
            self.demote()
        # end

        return k

    # end


    def movecursortoend(arg):
        """Move the cursor to the end of the text because it is distracting.
        """
        if runningOnMobile:
            text.set_pos(text.len())


    def handleup(self):
        # Simple hack to move the cursor to the end out of the text
        # after the underlying up arrow event has been handled by the
        # text control because I find it distracting that the up key
        # moves the cursor to the middle of the line above the end.  A
        # ten milli-second delay is enough on the N73.
        self.timer.after(0.01, self.movecursortoend)
        if self.state == ShowingBack:
            self.promote()
            return self.showfront()
        else:
            emit(u"%s" % self.current.back)                
            self.state = ShowingBack


    def handledown(self):
        if self.state == ShowingBack:
            self.demote()
            return self.showfront()
        else:
            emit(u"%s" % self.current.back)                
            self.state = ShowingBack
           
           
    def showall(self):
        self.showfront()
        while True:
            k = getcmd()
            if k == CmdWrong:
                k = self.handledown()
            elif k == CmdCorrect:
                k = self.handleup()

            if (k in [CmdQuit, CmdAllDone]):
                break
       
        if k == CmdAllDone:
            emit(u"Studied all cards + nothing left to don today.")
        else:
            emit(u"User quitting")

    # end

# end


#Define the exit function
def quit():
    app_lock.signal()


# define functions to show notifications
def up():
    f.handleup()

 
def down():
    f.handledown()


def initMobile():

    global app_lock
    app_lock = e32.Ao_lock()

    appuifw.app.exit_key_handler = quit
 
    # Create an instance of Text and set it as the application's body
    global text
    text = appuifw.Text()
    appuifw.app.body = text
 

def runMobile():

    text.add(u"Flashcards for Symbian\n")
    # Bind keys
    text.bind(key_codes.EKeyUpArrow, up)
    text.bind(key_codes.EKeyDownArrow, down)
   
    # show the first card
    f.showfront()

    # Wait for the user to request the exit
    app_lock.wait()

#  main

#ui.keys(ui.strokes) #  return keystrokes
pathname = os.path.dirname(sys.argv[0]) 
pathname = os.path.abspath(pathname)
# print pathname

if runningOnMobile:
    # Do this before loading anything because the load functions emit
    # logging information.
    import appuifw, e32, key_codes
    initMobile()

f = Flash_Set("flashcards")
if runningOnMobile:
    runMobile()
else:
    f.showall()


Posted via email from kwhitefoot's posterous

Saturday 28 August 2010

Sustainable Energy - without the hot air

I wanted to read David McKay's book on my mobile but there doesn't seem to be a reader for ePub format files for the Nokia N73.

So Free Software to the rescue in the form of Calibre by Kovid Goyal <http://calibre-ebook.com/>.  I'm using Ubuntu so all I had to do was start Synaptic and install Calibre from there.  It's not quite the latest version but it seems to work.  If you aren't using a distro with Calibre in the repository or if that sentence makes no sense to you (using Windows or Mac?) or if you simply want the latest version download it from the Calibre web site.

The web page for the book is http://www.withouthotair.com/, the ePub version is at http://www.ivor.org/withouthotair/ and the version converted from ePub to Mobi by Calibre is attached to this blog entry

Posted via email from kwhitefoot's posterous

Monday 23 August 2010

In the Beginning was the Command Line by Neal Stephenson, excerpt.

I hope Neal Stephenson doesn't mind me posting this excerpt from "In the Beginning was the Command Line".


Imagine a crossroads where four competing auto dealerships are situated. One of them (Microsoft) is much, much bigger than the others. It started out years ago selling three-speed bicycles (MS-DOS); these were not perfect, but they worked, and when they broke you could easily fix them.

There was a competing bicycle dealership next door (Apple) that one day began selling motorized vehicles--expensive but attractively styled cars with their innards hermetically sealed, so that how they worked was something of a mystery.

The big dealership responded by rushing a moped upgrade kit (the original Windows) onto the market. This was a Rube Goldberg contraption that, when bolted onto a three-speed bicycle, enabled it to keep up, just barely, with Apple-cars. The users had to wear goggles and were always picking bugs out of their teeth while Apple owners sped along in hermetically sealed comfort, sneering out the windows. But the Micro-mopeds were cheap, and easy to fix compared with the Apple-cars, and their market share waxed.

Eventually the big dealership came out with a full-fledged car: a colossal station wagon (Windows 95). It had all the aesthetic appeal of a Soviet worker housing block, it leaked oil and blew gaskets, and it was an enormous success. A little later, they also came out with a hulking off-road vehicle intended for industrial users (Windows NT) which was no more beautiful than the station wagon, and only a little more reliable.

Since then there has been a lot of noise and shouting, but little has changed. The smaller dealership continues to sell sleek Euro-styled sedans and to spend a lot of money on advertising campaigns. They have had GOING OUT OF BUSINESS! signs taped up in their windows for so long that they have gotten all yellow and curly. The big one keeps making bigger and bigger station wagons and ORVs.

On the other side of the road are two competitors that have come along more recently.

One of them (Be, Inc.) is selling fully operational Batmobiles (the BeOS). They are more beautiful and stylish even than the Euro-sedans, better designed, more technologically advanced, and at least as reliable as anything else on the market--and yet cheaper than the others.

With one exception, that is: Linux, which is right next door, and which is not a business at all. It's a bunch of RVs, yurts, tepees, and geodesic domes set up in a field and organized by consensus. The people who live there are making tanks. These are not old-fashioned, cast-iron Soviet tanks; these are more like the M1 tanks of the U.S. Army, made of space-age materials and jammed with sophisticated technology from one end to the other. But they are better than Army tanks. They've been modified in such a way that they never, ever break down, are light and maneuverable enough to use on ordinary streets, and use no more fuel than a subcompact car. These tanks are being cranked out, on the spot, at a terrific pace, and a vast number of them are lined up along the edge of the road with keys in the ignition. Anyone who wants can simply climb into one and drive it away for free.

Customers come to this crossroads in throngs, day and night. Ninety percent of them go straight to the biggest dealership and buy station wagons or off-road vehicles. They do not even look at the other dealerships.

Of the remaining ten percent, most go and buy a sleek Euro-sedan, pausing only to turn up their noses at the philistines going to buy the station wagons and ORVs. If they even notice the people on the opposite side of the road, selling the cheaper, technically superior vehicles, these customers deride them cranks and half-wits.

The Batmobile outlet sells a few vehicles to the occasional car nut who wants a second vehicle to go with his station wagon, but seems to accept, at least for now, that it's a fringe player.

The group giving away the free tanks only stays alive because it is staffed by volunteers, who are lined up at the edge of the street with bullhorns, trying to draw customers' attention to this incredible situation. A typical conversation goes something like this:

Hacker with bullhorn: "Save your money! Accept one of our free tanks! It is invulnerable, and can drive across rocks and swamps at ninety miles an hour while getting a hundred miles to the gallon!"

Prospective station wagon buyer: "I know what you say is true...but...er...I don't know how to maintain a tank!"

Bullhorn: "You don't know how to maintain a station wagon either!"

Buyer: "But this dealership has mechanics on staff. If something goes wrong with my station wagon, I can take a day off work, bring it here, and pay them to work on it while I sit in the waiting room for hours, listening to elevator music."

Bullhorn: "But if you accept one of our free tanks we will send volunteers to your house to fix it for free while you sleep!"

Buyer: "Stay away from my house, you freak!"

Bullhorn: "But..."

Buyer: "Can't you see that everyone is buying station wagons?"

Posted via email from kwhitefoot's posterous

Followers