Auto Pw Change

I had to change this script a lot, so take with a grain of salt. That said, we changed about 1000 LOCAL passwords in a couple hours – which would have really taken all day and been more boring.

#!/usr/bin/python

import pexpect

#most likely should be first for speed
passlist = ["pass1", "pass2", "pass3"]
#most critical should be listed in file first for speed
user="root"
newpass="newpass"

#open hosts file
hostfile=open("hosts.txt", "r")

for host in hostfile:
  host = host.strip()
  changeSuccesful = False
  #need to find the currpass to change it
  #so auth by key may not be ideal in this case
  p = pexpect.spawn("ssh " + user + "@" + host + " passwd"
  
  #try block so it doesn't crash the program
  try:
    #different systmes vary with exact text
    conn_result = p.expect(["assword:", pexpect.EOF, "Are you sure you want to continue"])
    if conn_result == 2:
      print "accepting public key for ", host
      p.sendline("yes")
      conn_result = p.expect(["assword:", pexpect.EOF])
    if conn_result == 0:
      for password in passlist:
        print "tryin password for ", host
        p.sendline(password)
        pass_result = p.expect(["denied", "current.*assword:", "new.*assword", pexpect.EOF])
        if pass_result == 1:
          p.sendline(password)
          p.expect("new.*assword:")
        #this should execute if a key OR password was accepted
        if pass_result == 1 or pass_result == 2:
          p.sendline(newpass)
          p.expect("new.*assword:")
          p.sendline(newpass)
          changeSuccesful = True
          print "Succesful pwchange: host "+ host 
          break
    if not changeSuccesful:
      print "UnSuccesful pwchange: host "+ host 
  except:
    print "Uncaught exception: host "+ host 


8-queens problem hill climbing python implementation

It was written in an AI book I’m reading that the hill-climbing algorithm finds about 14% of solutions. I implemented a version and got 18%, but this could easily be due to different implementations – like starting in random columns rather than random places on the board, and optimizing per column. Anyway, here is the program.

README

This program is a hillclimbing program solution to the 8 queens problem. The algorithm is silly in some places, but suits the purposes for what I was working on I think. It was tested with python 2.6.1 with psyco installed. If big runs are being tried, having psyco may be important to maintain sanity, since it will speed things up significanlty. Otherwise, you may want to stick to –numrun being less than around 50.

The board is simply defined as a two dimensional list, with the occupied elements stored as “Q” and empty emements as 0. The initial board is generated by picking a random row and column to place a queen, although the class structure allows for predefined boards to be manually passed in. If the spot on the board is occupied, then another spot is randomly chosen.

Violations are calculated by iterating through every queen and checking horizontally, vertically, and diagonally for other queens. Each violation is totalled up, and at the end they are divided by 2 since violations were overcounted. This could certainly be optimized further.

The hill solution works by checking every possible single move and returning the best of these. Obviously, this could also be improved upon. The book’s algorithm (which was not available while programming this) simply attempts to move every space within a column rather than every open spot on the board – which would speed up the process by an order of magnitude and also decrease the likelihood of finding a solution by a small percentage. Also, it appears that the random initial state only contains one queen per column, which is also different from this implementation. The assignment specification mentions a randomly generated board, which is what this implementation was based on. If an implementation closer to that of the book is desired, please let me know, as it would only be a minor adjustment.

With this algorithm, every queen on the board tries to move to every spot on the board, and violations are re-calculated. A move with the least violations is chosen and the process repeats until there is no improvement. It there is no improvement after every queen has had a go, there is no solution found and the algorithm returns. If there is an improvement, the algorithm continues for another go-around.

The biggest run so far is just 1000 nodes. It returned 175 successes, which is fairly close to the book’s given percentage or .14.

Here is sample usage:

mopey-mackey:hillclimb user$ python eight_queen.py –help
Usage: eight_queen.py [options]

Options:
-h, –help show this help message and exit
-q, –quiet Don’t print all the moves… wise option if using large
numbers
–numrun=NUMRUN Number of random Boards

mopey-mackey:hillclimb user$ python eight_queen.py –numrun=1000 –quiet
Total Runs: 1000
Total Success: 175
Success Percentage: 0.175
Average number of steps: 3.83

mopey-mackey:hillclimb user$ python eight_queen.py
====================
BOARD 0
====================
Board Violations 7
0 0 Q 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 Q 0 0
Q 0 0 0 0 0 0 0
0 0 0 0 Q 0 0 0
Q Q 0 0 0 0 Q 0
0 0 0 0 0 0 0 0
0 0 0 0 Q 0 0 0

Board Violations 4
0 0 Q 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 Q 0 0
Q 0 0 0 0 0 0 0
0 0 0 0 Q 0 0 0
Q Q 0 0 0 0 0 0
0 0 0 0 0 0 0 Q
0 0 0 0 Q 0 0 0

Board Violations 3
0 0 Q 0 0 0 0 0
Q 0 0 0 0 0 0 0
0 0 0 0 0 Q 0 0
0 0 0 0 0 0 0 0
0 0 0 0 Q 0 0 0
Q Q 0 0 0 0 0 0
0 0 0 0 0 0 0 Q
0 0 0 0 Q 0 0 0

Board Violations 2
0 0 Q 0 0 0 0 0
Q 0 0 0 0 0 0 0
0 0 0 0 0 Q 0 0
0 Q 0 0 0 0 0 0
0 0 0 0 Q 0 0 0
0 Q 0 0 0 0 0 0
0 0 0 0 0 0 0 Q
0 0 0 0 Q 0 0 0

NO SOLUTION FOUND
Total Runs: 1
Total Success: 0
Success Percentage: 0.0
Average number of steps: 4.0

mopey-mackey:hillclimb user$ python eight_queen.py –numrun=4
====================
BOARD 0
====================
Board Violations 3
0 0 Q 0 0 0 0 0
Q 0 0 0 Q 0 0 0
0 0 0 0 0 0 0 Q
0 0 0 Q 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 Q 0
0 Q 0 0 0 0 0 0
0 0 0 0 0 0 0 Q

Board Violations 1
0 0 Q 0 0 0 0 0
Q 0 0 0 Q 0 0 0
0 0 0 0 0 0 0 Q
0 0 0 Q 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 Q 0
0 Q 0 0 0 0 0 0
0 0 0 0 0 Q 0 0

Board Violations 0
0 0 Q 0 0 0 0 0
0 0 0 0 Q 0 0 0
0 0 0 0 0 0 0 Q
0 0 0 Q 0 0 0 0
Q 0 0 0 0 0 0 0
0 0 0 0 0 0 Q 0
0 Q 0 0 0 0 0 0
0 0 0 0 0 Q 0 0

SOLUTION FOUND
====================
BOARD 1
====================
Board Violations 8
Q 0 0 0 0 0 0 Q
0 0 0 0 0 0 Q 0
0 0 Q 0 Q 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 Q 0 0
0 0 0 0 0 0 0 0
0 Q 0 0 Q 0 0 0
0 0 0 0 0 0 0 0

Board Violations 5
Q 0 0 0 0 0 0 Q
0 0 0 0 0 0 Q 0
0 0 Q 0 Q 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 Q 0 0
0 0 0 0 0 0 0 0
0 0 0 0 Q 0 0 0
0 Q 0 0 0 0 0 0

Board Violations 3
0 0 0 0 0 0 0 Q
0 0 0 0 0 0 Q 0
0 0 Q 0 Q 0 0 0
Q 0 0 0 0 0 0 0
0 0 0 0 0 Q 0 0
0 0 0 0 0 0 0 0
0 0 0 0 Q 0 0 0
0 Q 0 0 0 0 0 0

Board Violations 2
0 0 0 0 0 0 0 Q
0 0 0 0 0 0 Q 0
0 0 Q 0 0 0 0 0
Q 0 0 0 0 0 0 0
0 0 0 0 0 Q 0 0
Q 0 0 0 0 0 0 0
0 0 0 0 Q 0 0 0
0 Q 0 0 0 0 0 0

NO SOLUTION FOUND
====================
BOARD 2
====================
Board Violations 5
0 Q 0 Q 0 0 0 0
0 0 0 0 0 Q 0 Q
Q 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
Q 0 0 0 0 0 0 0
Q 0 0 0 0 0 0 0
0 0 0 0 0 0 Q 0
0 0 0 0 0 0 0 0

Board Violations 3
0 Q 0 Q 0 0 0 0
0 0 0 0 0 Q 0 Q
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
Q 0 0 0 0 0 0 0
Q 0 0 0 0 0 0 0
0 0 0 0 0 0 Q 0
0 0 0 0 Q 0 0 0

Board Violations 2
0 Q 0 Q 0 0 0 0
0 0 0 0 0 Q 0 0
0 0 0 0 0 0 0 Q
0 0 0 0 0 0 0 0
Q 0 0 0 0 0 0 0
Q 0 0 0 0 0 0 0
0 0 0 0 0 0 Q 0
0 0 0 0 Q 0 0 0

Board Violations 1
0 Q 0 Q 0 0 0 0
0 0 0 0 0 Q 0 0
0 0 0 0 0 0 0 Q
0 0 Q 0 0 0 0 0
Q 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 Q 0
0 0 0 0 Q 0 0 0

Board Violations 0
0 Q 0 0 0 0 0 0
0 0 0 0 0 Q 0 0
0 0 0 0 0 0 0 Q
0 0 Q 0 0 0 0 0
Q 0 0 0 0 0 0 0
0 0 0 Q 0 0 0 0
0 0 0 0 0 0 Q 0
0 0 0 0 Q 0 0 0

SOLUTION FOUND
====================
BOARD 3
====================
Board Violations 5
0 0 0 Q Q 0 0 0
0 0 0 0 0 0 0 Q
0 0 0 0 0 0 0 0
0 0 0 0 0 Q 0 0
0 0 0 0 0 0 0 Q
0 Q 0 0 0 0 0 0
0 0 0 0 Q 0 0 0
0 0 Q 0 0 0 0 0

Board Violations 3
0 0 0 0 Q 0 0 0
0 0 0 0 0 0 0 Q
0 0 0 Q 0 0 0 0
0 0 0 0 0 Q 0 0
0 0 0 0 0 0 0 Q
0 Q 0 0 0 0 0 0
0 0 0 0 Q 0 0 0
0 0 Q 0 0 0 0 0

Board Violations 1
0 0 0 0 Q 0 0 0
Q 0 0 0 0 0 0 0
0 0 0 Q 0 0 0 0
0 0 0 0 0 Q 0 0
0 0 0 0 0 0 0 Q
0 Q 0 0 0 0 0 0
0 0 0 0 Q 0 0 0
0 0 Q 0 0 0 0 0

Board Violations 0
0 0 0 0 Q 0 0 0
Q 0 0 0 0 0 0 0
0 0 0 Q 0 0 0 0
0 0 0 0 0 Q 0 0
0 0 0 0 0 0 0 Q
0 Q 0 0 0 0 0 0
0 0 0 0 0 0 Q 0
0 0 Q 0 0 0 0 0

SOLUTION FOUND
Total Runs: 4
Total Success: 3
Success Percentage: 0.75
Average number of steps: 4.0

And here is the source

#!/usr/bin/python

import random,sys,copy
from optparse import OptionParser
try:
  import psyco
  psyco.full()
except ImportError:
  pass

"""
cowboy code, but seems to work
USAGE: python prog <numberruns=1> <verbocity=False>
"""

class board:
  def __init__(self, list=None):
    if list == None:
      self.board = [[0 for i in range(0,8)] for j in range(0,8)]
      #initialize queens at random places
      for i in range(0,8):
        while 1:
          rand_row = random.randint(0,7)
          rand_col = random.randint(0,7)
          if self.board[rand_row][rand_col] == 0:
            self.board[rand_row][rand_col] = "Q"
            break
    #TODO raise errors if board is not right format or dimension
  #define how to print the board
  def __repr__(self):
    mstr = ""
    for i in range(0,8):
      for j in range(0,8):
        mstr = mstr + str(self.board[i][j]) + " "
      mstr = mstr + "n"
    return (mstr)

class queens:
  def __init__(self, numruns, verbocity, passedboard=None):
    #TODO check options
    self.totalruns = numruns
    self.totalsucc = 0
    self.totalnumsteps = 0
    self.verbocity = verbocity
    for i in range(0,numruns):
      if self.verbocity == True:
        print "===================="
        print "BOARD",i
        print "===================="
      self.mboard = board(passedboard)
      self.cost = self.calc_cost(self.mboard)
      self.hill_solution()

  def hill_solution(self):
    while 1:
      currViolations = self.cost
      self.getlowercostboard()
      if currViolations == self.cost:
        break
      self.totalnumsteps += 1
      if self.verbocity == True:
        print "Board Violations", self.calc_cost(self.mboard)
        print self.mboard
    if self.cost != 0:
      if self.verbocity == True:
        print "NO SOLUTION FOUND"
    else:
      if self.verbocity == True:
        print "SOLUTION FOUND"
      self.totalsucc += 1
    return self.cost

  def printstats(self):
    print "Total Runs: ", self.totalruns
    print "Total Success: ", self.totalsucc
    print "Success Percentage: ", float(self.totalsucc)/float(self.totalruns)
    print "Average number of steps: ", float(self.totalnumsteps)/float(self.totalruns)

  def calc_cost(self, tboard):
    #these are separate for easier debugging
    totalhcost = 0
    totaldcost = 0
    for i in range(0,8):
      for j in range(0,8):
        #if this node is a queen, calculate all violations
        if tboard.board[i][j] == "Q":
          #subtract 2 so don't count self
          #sideways and vertical
          totalhcost -= 2
          for k in range(0,8):
            if tboard.board[i][k] == "Q":
              totalhcost += 1
            if tboard.board[k][j] == "Q":
              totalhcost += 1
          #calculate diagonal violations
          k, l = i+1, j+1
          while k < 8 and l < 8:
            if tboard.board[k][l] == "Q":
              totaldcost += 1
            k +=1
            l +=1
          k, l = i+1, j-1
          while k < 8 and l >= 0:
            if tboard.board[k][l] == "Q":
              totaldcost += 1
            k +=1
            l -=1
          k, l = i-1, j+1
          while k >= 0 and l < 8:
            if tboard.board[k][l] == "Q":
              totaldcost += 1
            k -=1
            l +=1
          k, l = i-1, j-1
          while k >= 0 and l >= 0:
            if tboard.board[k][l] == "Q":
              totaldcost += 1
            k -=1
            l -=1
    return ((totaldcost + totalhcost)/2)

  #this function tries moving every queen to every spot, with only one move
  #and returns the move that has the leas number of violations
  def getlowercostboard(self):
    lowcost = self.calc_cost(self.mboard)
    lowestavailable = self.mboard
    #move one queen at a time, the optimal single move by brute force
    for q_row in range(0,8):
      for q_col in range(0,8):
        if self.mboard.board[q_row][q_col] == "Q":
          #get the lowest cost by moving this queen
          for m_row in range(0,8):
            for m_col in range(0,8):
              if self.mboard.board[m_row][m_col] != "Q":
                #try placing the queen here and see if it's any better
                tryboard = copy.deepcopy(self.mboard)
                tryboard.board[q_row][q_col] = 0
                tryboard.board[m_row][m_col] = "Q"
                thiscost = self.calc_cost(tryboard)
                if thiscost < lowcost:
                  lowcost = thiscost
                  lowestavailable = tryboard
    self.mboard = lowestavailable
    self.cost = lowcost

if __name__ == "__main__":

  parser = OptionParser()
  parser.add_option("-q", "--quiet", dest="verbose",
                   action="store_false", default=True,
                   help="Don't print all the moves... wise option if using large numbers")

  parser.add_option("--numrun", dest="numrun", help="Number of random Boards", default=1,
                   type="int")

  (options, args) = parser.parse_args()

  mboard = queens(verbocity=options.verbose, numruns=options.numrun)
  mboard.printstats()

The square of random is less uniform (derr)

This is something obvious to statisticians but maybe less obvious to most programmers. I recently came across some code that essentially looks like this:

x = rand() #random number uniformly distributed between [0,1]
...
x= x**n #raise x to a power

The programer was for some reason assuming that x was still uniform between [0,1]. Of course, this isn’t the case. Although the domain is still between [0,1] the numbers will now be squished down closer to 0.

It is easy to analyze this with a change of variables.

The frequency distribution Fx(x) = P(X<=x)=x
Y=x^n
Fy(y) = P(Y<=y) = P(x^n<=y) = P(X<=y^(1/n) = y^(1/n) for 0<=y<=1
The density function is the derivitive
Fp(y)= (1/n)*y^-(1/n) = 1/(s*sqrt(y))

The graphs of the distributions look like this, first the one generated by rand, then one with n=2:

sorta captcha breaking thing

game 2 of hackthissite.org’s programming challenge

The directions (you have 30 seconds to upload the code)

“The pixels in the above image are numbered 0..99 for the first row, 100..199 for the second row etc. White pixels represent ascii codes. The ascii code for a particular white pixel is equal to the offset from the last white pixel. For example, the first white pixel at location 65 would represent ascii code 65 (‘A’), the next at location 131 would represent ascii code (131 – 65) = 66 (‘B’) and so on.

The text contained in the image is the answer encoded in Morse, where “a test” would be encoded as “.- / – . … -”"

Sample image:

Solution:

#!/usr/bin/env python
from PIL import Image

#load some image information
imagefile = Image.open('./PNG.png')

key = {  ".-":"A",
         "-...":"B",
         "-.-.":"C",
         "-..":"D",
         ".":"E",
         "..-.":"F",
         "--.":"G",
         "....":"H",
         "..":"I",
         ".---":"J",
         "-.-":"K",
         ".-..":"L",
         "--":"M",
         "-.":"N",
         "---":"O",
         ".--.":"P",
         "--.-":"Q",
         ".-.":"R",
         "...":"S",
         "-":"T",
         "..-":"U",
         "...-":"V",
         ".--":"W",
         "-..-":"X",
         "-.--":"Y",
         "--..":"Z",
	 ".----":"1",
         "..---":"2",
         "...==":"3",
         "....-":"4",
         ".....":"5",
         "-....":"6",
         "--...":"7",
         "---..":"8",
         "----.":"9",
         "-----":"0",
         }

#imagedata = imagefile.load()
#width,height = imagefile.size
#print imagedata[0,9]

imagelist = list(imagefile.getdata())

plaintext = ""

lastval = 0
thislettercoded = ""
for i in range(0,len(imagelist)):
  #we only care if the spot is white
  if imagelist[i] == 1:
    thischar = chr(i - lastval)
    if thischar == '.' or thischar == '-':
      thislettercoded = thislettercoded + thischar
    else:
      thislettercoded = thislettercoded.strip()
      plaintext = plaintext + key[thislettercoded]
      thislettercoded = ""
    lastval = i

print plaintext

modular exponentiation python program

This is a simple – not efficient – but doable way to do modular exponentiation

#!/usr/bin/python

def modexp(base, pow, mod):
  exponent = 1
  i = 0
  while i < pow:
    exponent = (exponent * base) % mod
    i += 1
  return exponent

if __name__ == "__main__":
  import sys
  print modexp(int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3]))

Example usage

$ modexponent.py 2 1234 789
481

For large numbers this method isn’t practical. The below program implements the improved python algorithms for modular exponents.

#!/usr/bin/python
#Let x be an integer written in binary, y and n be integers
#I'm sure this isn't the best, but this is only called once per program
def binconvert(n):
  barray = []
  if n < 0: 
    raise ValueError, "must be positive"
  if n == 0:
    return 0
  while n > 0:
    #barray = n%2 + barray[:]
    barray.append(n%2)
    n = n >> 1
  barray.reverse()
  return barray
#this is the intuitive but slow way
def modexp(base, pow, mod):
  exponent = 1
  i = 0
  while i < pow:
    exponent = (exponent * base) % mod  
    i += 1
  return exponent
#y**x mod n
def modexp1(y, x, n):
  #convert x to a binary list
  x = binconvert(x)
  
  s = [1]
  r = x[:]
  for k in range (0, len(x)):
    if x[k] == 1:
      r[k] = (s[k] * y) % n
    else:
      r[k] = s[k]
    s.append ((r[k]**2)%n)
  #print s
  #print r
  return r[-1]
#similar to modexp1 except uses the bits in reverse order
def modexp2(y, x, n):
  a = x
  b = 1
  c = y
  while a != 0:
    if a % 2 == 0:
      a = a/2
      c = (c**2) % n
    else:
      a = a -1
      b = (b * c) % n
  return b
if __name__ == "__main__":
import sys
  print modexp(int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3]))
  print modexp1(int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3]))
  print modexp2(int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3]))

Using the above program, some interesting things are easy to demonstrate. For example, here is a test that shows for 100,000 tries, the 2 algorithms get the correct answer.

import prob23
import random
import sys

BASEMAX = 60000
EXPMAX = 60000
MODMAX = 100000
ITERATIONS = 100000

print "beginning program"
print "This will take awhile... you need", ITERATIONS, "of these dots to complete."
p
for i in range (0, ITERATIONS):
  if i % 10 == 0:
    sys.stdout.write(".")
    sys.stdout.flush()
  r_base = random.randint(1, BASEMAX)
  r_exp = random.randint(1, EXPMAX)
  r_mod = random.randint(max(r_base, r_exp), MODMAX)
  trueval = prob23.modexp(r_base, r_exp, r_mod)
  testval1 = prob23.modexp1(r_base, r_exp, r_mod)
  testval2 = prob23.modexp2(r_base, r_exp, r_mod)
  if trueval != testval1 or trueval != testval2:
    print "One of these exponent things doesn't work"
    #sys.exit(1)
print "Done, all of these answers were the same."

Running this program several times with various parameters verifies the correctness of the algorithm (like how an Engineer verifies things).

Also, it’s interesting to time these algorithms when compared to the brute force method (multiplying every number). All three algorithms were timed to find a solution. Below is some example code that accomplishes this (this particular code is for the brute force version, but it is almost identical to the other algorithms – the only change is the modexponent call).

import modexponent

for i in range(1, 65538):
  thistry = modexponent.modexp(3, i, 65537)
  if thistry == 2:
    print i
    break
  if i % 15000 == 0:
    print "trying", i

Running all three algorithms, the results are shown below.

me@Opteron:~/math/chp3$ time python bruteforce.py
55296
real 11m28.131s
user 11m18.710s
sys 0m1.170s
me@Opteron:~/math/chp3$ time python algorithm1.py
55296
real 0m3.285s
user 0m3.290s
sys 0m0.000s
me@Opteron:~/math/chp3$ time python algorithm2.py
55296
real 0m2.621s
user 0m2.610s
sys 0m0.010s

This is a huge speedup – from 11 minutes in the case of brute forcing to under 4 seconds for the two algorithms.

gnu readline – python

This is the very start of our cryptanal program frontend

#!/usr/bin/env python

import readline

"""The shell class is the front end for cryptanal"""

class shell:
  def __init__(self, filename=None):
    print"""
WWW         WW eEeEeEeE LL        CCCCC    OOOO    MMMM    MMMM  eEeEeEeE
 WW         W  EE       LL       Cc      OOO  OOO  MM MM  M  MM  EE
  WW       WW  EeEeE    LL      CC       OO    OO  MM  MMM   MM  EeEeE
  WWw WW  WW   EE       LL       Cc      OOO  OOO  MM        MM  EE
   WWW  WWW    eEeEeEeE LlLlLlL   CCCCC    OOOO    MM        MM  eEeEeEeE

                             TO CRYPTO-SHELL
  (Useful for deciphering what little Susie is writing to little Billy)
"""

    self.filename = filename
    self.crypto = None
    #if self.filename != None:
      #self.crypto = freqcount.subCryptAnal(self.filename)

    #setup the tab completion information here
    self.commands = ["help", "printfreq"]
    readline.set_completer(self.completer)
    readline.parse_and_bind("tab: complete")

  #completer funtion for tab complete
  def completer(self, word, index):
    matches =
    try:
      return matches[index] + " "
    except IndexError:
      pass

  #this is the main event loop
  def mainloop(self):
    while 1:
      command=raw_input('> ').lstrip()
      if command.lower().startswith('help'):
        self.help(command[4:].lstrip())
      else:
        print "Error: command not recognized"

  def help(self, args):
    print "HELP"

if __name__ == '__main__':
  thisshell = shell()
  thisshell.mainloop()

Follow

Get every new post delivered to your Inbox.