SaltyCrane Blog — Notes on JavaScript and web development

How to use Eclipse and CDT to edit C source files

Eclipse is a good integrated development environment rivaling Microsoft Visual Studio 2005. I have Visual Studio 2005 installed on my computer, though for some reason, I don't care to use it. Eclipse originally was used for Java development but now includes plugins for C/C++, Python, Perl, and many others. I use the Pydev plugin for Python development and it is good.

I am using Tornado 2.2 to develop C code for VxWorks. The editor in Tornado isn't the greatest, so I want to edit my code in Eclipse with the CDT plugin. I will still be using Tornado to build the projects, so instead of using a Standard or Managed Make Project, I just created a folder which linked to my source files. Note that you may get messages in Tornado that say "This file has been changed outside the source editor. Do you want to reload it?" Just make sure you don't have any unsaved changes from Tornado and click "Yes". Or just make sure all your source code windows are closed in Tornado. I know this isn't the most elegant solution, but it will have to do unless we upgrade to VxWorks 6 and Workbench.

Update 2/13/07: I've found a better way to use Eclipse with Tornado projects. See my post How to use Tornado GNU tools with Eclipse/CDT for how to use Eclipse to edit *and build* your Tornado project.

Here are the steps:
  1. Start with your .c and .h files in a directory called "c:\sofeng\proj\stuff"
  2. Download and install eclipse-SDK-3.2.1-win32.zip from http://www.eclipse.org/downloads/download.php?file=/eclipse/downloads/drops/R-3.2.1-200609210945/eclipse-SDK-3.2.1-win32.zip
  3. Download and install org.eclipse.cdt-3.1.1-win32.x86.zip from http://download.eclipse.org/tools/cdt/releases/callisto/dist/3.1.1/
  4. Run "eclipse.exe"
    5. From the menu: "Window" -> "Open Perspective" -> "Other..." -> "C/C++" -> "OK"
  5. From the menu: "File" -> "New" -> "Other..."
  6. Under "General", select "Project"
  7. Click "Next"
  8. In the "Project name:" field, type "dummy". Leave the "Use default location" box checked.
  9. Click "Finish"
  10. From the menu: "File" -> "New" -> "Folder"
  11. In the "Enter or select the parent folder:" enter or select the "dummy" project you just created.
  12. Click the ">> Advanced" button
  13. Click the "Link to folder in the file system" checkbox and enter "c:\sofeng\proj\stuff" or "Browse..." to that location.
  14. Click "Finish"
NOTE: If you do not see the ">> Advanced" button, follow these steps:
  1. From the "Window" menu, select "Preferences..."
  2. Go to "General" > "Workspace" > "Linked Resources" and check "Enable linked resources"
  3. Click "OK"

How to create a downloadable vxworks project in Tornado 2.2

Start with your .c and .h files in a directory called "c:\sofeng\proj\myproj"

TORNADO DOWNLOADABLE PROJECT
1. Install Tornado 2.2
2. Run Tornado ("Start" -> "All Programs" -> "Tornado 2.2" -> "Tornado")
3. If the "Create Project in New/Existing Workspace" dialog is up, click on "New". If not, go to "File" -> "New Project..."
4. Click "Create downloadable application modules for VxWorks", click "OK"
5. In the "Name:" field, enter "myproj"
6. In the "Location:" field, enter "c:\sofeng\proj\myproj"
7. In the "Add to a New or Existing Workspace" field, enter "c:\sofeng\proj\Workspace0.wsp"
8. Click "Next"
9. Choose the "A toolchain" option
10. From the dropdown, choose "SIMNTgnu" if you are using the simulator. Otherwise choose the proper toolchain for your processor.
11. Click "Next" then click "Finish"
12. In the "Workspace:Workspace0" window, make sure the "Files" tab is selected. Make sure the "Workspace0" branch is expanded.
12. Right-click on "myproj Files" and select "Add files..."
13. Navigate to c:\sofeng\proj\myproj
14. Select all the files. (Click the first file, then while holding the "Shift" key, click the last file.)
15. Click "Add"
16. To build your project, right-click on "myproj Files"in the "Workspace:Workspace0" window and select "Build 'myproj.out'"

See also VxWorks/Tornado bootable project tutorial

Standard Make vs. Managed Make in CDT in Eclipse

From this presentation, here are differences between Standard Make and Managed Make in CDT in Eclipse.


Standard Make
  • Re-uses existing makefiles
  • Simple integration with arbitrary build systems
  • Parsing of toolchain output to generate error markers
Managed Make
  • Manages compiles and toolchain directly
  • No makefile editing
  • Fine control over compile, link settings
Also, see "When do I use the standard make feature" from the CDT FAQ.

How to install Easy Install for Python

Update 2009-03-31:
How to install Easy Install on Ubuntu Linux
$ sudo apt-get install python-setuptools python-dev build-essential

How to install Easy Install on Windows
  1. Go to http://peak.telecommunity.com/DevCenter/EasyInstall#installing-easy-install
  2. Right click on "ez_setup.py" and save the file to "c:\temp"
  3. Open a cmd.exe prompt
  4. "cd c:\temp"
  5. "python ez_setup.py"

How to install Easy Install on Cygwin
  1. $ cd /tmp
  2. $ wget http://peak.telecommunity.com/dist/ez_setup.py
  3. $ python ez_setup.py

How to draw a simple line using python and the matplotlib API -

I'm continuing to learn the low level object oriented matplotlib API. My goal is to create very customizable, perfect plots. Here is how to draw a simple line. First create a figure that is 4 inches by 4 inches. Then create some axes with a 10% margin around each edge. Then add the axes to the figure. Then create a line from (0,0) to (1,1). Then add the line to the axes. Then create a canvase. Then create the .png file. Looks like good object oriented python fun to me...


""" line_ex.py                                             
"""
from matplotlib.figure import Figure
from matplotlib.axes import Axes
from matplotlib.lines import Line2D
from matplotlib.backends.backend_agg import FigureCanvasAgg

fig = Figure(figsize=[4,4])
ax = Axes(fig, [.1,.1,.8,.8])
fig.add_axes(ax)
l = Line2D([0,1],[0,1])
ax.add_line(l)

canvas = FigureCanvasAgg(fig)
canvas.print_figure("line_ex.png")

How to use the pylab API vs. the matplotlib API

This article has a good description of the 2 API's in matplotlib: the pylab API and the matplotlib API. I've been using the pylab interface because it is easier, especially coming from a matlab background. But I wanted to get direct access to the matplotlib classes so I needed to use the matplotlib API. Here is a simple example that creates a .png figure using the 2 different API's.

Here is the example using the pylab API:
""" api_pylab.py          
"""
from pylab import *

figure(figsize=[4,4])
axes([.1,.1,.8,.8])
scatter([1,2],[3,4])
savefig('api_pylab.png')

Here is the example using the matplotlib API:
""" api_matplotlib.py                                        
"""
from matplotlib.figure import Figure
from matplotlib.backends.backend_agg import FigureCanvasAgg

fig = Figure(figsize=[4,4])
ax = fig.add_axes([.1,.1,.8,.8])
ax.scatter([1,2], [3,4])
canvas = FigureCanvasAgg(fig)
canvas.print_figure("api_matplotlib.png")

How to create some derived arrow classes with matplotlib and python

Here is an example of how to create some derived arrow classes with matplotlib and python. The arrow() function inmatplotlib accepts origin and delta x and delta y inputs. I changed this to polor coordinates so Arrow2 accepts the x and y coordinates of the origin, the length, and the angle. Then I created 4 classes derived from Arrow2 called ArrowRight, ArrowLeft, ArrowUp, and ArrowDown. These just set the angle for you to 0, 180, 90, and 270 respectively.Notice too that the **kwargs can be passed down so you can still set all the other parameters.
""" arrow_ex2.py """ 
from pylab import *  

def main(): 
    figure() 
    axes() 
    Arrow2(.5,.5,.2,45) 
    ArrowRight(.5,.5,.2) 
    ArrowLeft(.5,.5,.2) 
    ArrowUp(.5,.5,.2) 
    ArrowDown(.5,.5,.2) 
    show() 

class Arrow2: 
    def __init__(self, x0, y0, length, angle=0.0, color='k', width=0.01, **kwargs):          
        dx = length*cos(angle*pi/180) 
        dy = length*sin(angle*pi/180) 
        arrow (x0, y0, dx, dy, 
               width=width, 
               edgecolor=color,  
               facecolor=color,  
               antialiased=True,  
               head_width=5*width, 
               head_length=7.5*width, 
               **kwargs)

class ArrowRight(Arrow2): 
    def __init__(self, x0, y0, length, **kwargs): 
        Arrow2.__init__(self, x0, y0, length, angle=0.0, **kwargs)

class ArrowLeft(Arrow2): 
    def __init__(self, x0, y0, length, **kwargs): 
        Arrow2.__init__(self, x0, y0, length, angle=180.0, **kwargs)                      

class ArrowUp(Arrow2): 
    def __init__(self, x0, y0, length, **kwargs): 
        Arrow2.__init__(self, x0, y0, length, angle=90.0, **kwargs) 

class ArrowDown(Arrow2): 
    def __init__(self, x0, y0, length, **kwargs): 
        Arrow2.__init__(self, x0, y0, length, angle=270.0, **kwargs) 

if __name__ == "__main__": 
    main() 

Example pie charts using python and matplotlib


I needed to make some pie charts and didn't like the results I got from Excel. It was too hard to customize the plots exactly the way I wanted them. I have used Matlab before and I preferred Matlab to Excel. However, Python is my favorite thing to use so I searched for python and matlab on Google and found matplotlib. Matplotlib is a matlab-like plotting library for Python. You can get matplotlib from http://matplotlib.sourceforge.net/, but it is also bundled with the Enthought version of Python so I got it from there. Update: I realized that the Enthought bundle didn't include the latest version of matplotlib so I installed the latest version of matplotlib and the required NumPy as well.

Step-by-step:
1. Download enthought version of Python 2.4.3 from http://code.enthought.com/enthon/ (Click on the "enthon-python2.4-1.0.0.exe" link is at the bottom of the page) and install it.
2. Download "numpy-1.0.1.win32-py2.4.exe" from http://sourceforge.net/project/showfiles.php?group_id=1369 and install it.
3. Download "matplotlib-0.87.7.win32-py2.4.exe" from http://sourceforge.net/projects/matplotlib and install it.
3. Open a text editor and type this inside:
#!/usr/bin/env python
"""
http://matplotlib.sf.net/matplotlib.pylab.html#-pie for the docstring.
"""
from pylab import *

# create figure
figwidth = 10.0    # inches
figheight = 3.5   # inches
figure(1, figsize=(figwidth, figheight))
rcParams['font.size'] = 12.0
rcParams['axes.titlesize'] = 16.0
rcParams['xtick.labelsize'] = 12.0
rcParams['legend.fontsize'] = 12.0
explode=(0.05, 0.0)
colors=('b','g')
Ncols = 3
plotheight = figwidth/Ncols
H = plotheight/figheight
W = 1.0 / Ncols
margin = 0.1
left = [W*margin, W*(1+margin), W*(2+margin)]
bottom = H*margin
width = W*(1-2*margin)
height = H*(1-2*margin)

# cpu utilization
utilized = 10.0
free = 100.0 - utilized
fracs = [utilized, free]
axes([left[0], bottom, width, height])
patches = pie(fracs, colors=colors, explode=explode, autopct='%1.f%%', shadow=True)
title('CPU Throughput')
legend((patches[0], patches[2]), ('Processing', 'Idle'), loc=(0,-.05))

# ROM utilization
utilized = 30.0
free = 100.0 - utilized
fracs = [utilized, free]
axes([left[1], bottom, width, height])
patches = pie(fracs, colors=colors, explode=explode, autopct='%1.f%%', shadow=True)
title('ROM Memory Usage')
legend((patches[0], patches[2]), ('Used', 'Unused'), loc=(0,-.05))

# RAM utilization
utilized = 15.0
free = 100.0 - utilized
fracs = [utilized, free]
axes([left[2], bottom, width, height])
patches = pie(fracs, colors=colors, explode=explode, autopct='%1.f%%', shadow=True)
title('RAM Memory Usage')
legend((patches[0], patches[2]), ('Used', 'Unused'), loc=(0,-.05))

savefig('utilization')
show()
4. Save the file as piechart.py in c:\temp
5. In Windows, go to Start -> All Programs -> Python 2.4 (Enthought Edition) -> IPython Shell
6. Type in "cd c:\temp"
7. Type "run piechart.py" and hit enter
Technorati tags: , ,

Larger python qt pyqt example

This script is used to parse Windows Event Viewer logs. It uses dumpel.exe. It colors significant events and presents results in a QT GUI.
"""windows_audit.py
"""

__author__ = "So Feng"
__version__ = "$Revision: 1.0 $"
__date__ = "$Date: 2006/10/17 $"
__license__ = "Python"

import re
import datetime
from datetime import date
import time
import glob
import os
import sys
from Qt import *
import StringIO

# constants
NCHARS_TO_WRAP = 30
EARLY_HOUR = 6
LATE_HOUR = 20
outfile = "audit_" + str(datetime.date.today()) + ".txt"
red_eventids = ["560","565","592","678"] orange_eventids = ["539","629","644","531","544","545","675","676"]
yellow_eventids = ["529","530","532","533","534","535","536","537","681",
                   "576","608","609","610","611","624","625","626","627",
                   "628","630","631","632","633","634","635","636","637",
                   "638","639","640","641","642","643","645","646","647",
                   "648","649","650","651","652","653","654","655","656",
                   "657","658","659","660","661","662","663","664","665",
                   "666","667","668","669","670","672"]
green_eventids = ["528", "538", "540", "680"] other_eventids = ["612", "617", "618", "619"] failure_list = ('529', '530', '531', '532', '533', '534', '535', '536', '537', '539', '544', '545', '546', '547', '616', '675', '676', '677', '679', '681', ) success_list = ('512', '513', '514', '515', '516', '517', '518', '528', '538', '540', '541', '542', '543', '560', '561', '562', '563', '564', '565', '566', '576', '577', '578', '592', '593', '594', '595', '608', '609', '610', '611', '612', '613', '614', '615', '617', '618', '619', '620', '624', '625', '626', '627', '628', '630', '631', '632', '633', '634', '635', '636', '637', '638', '639', '640', '641', '642', '643', '644', '645', '646', '647', '648', '649', '650', '651', '652', '653', '654', '655', '656', '657', '658', '659', '660', '661', '662', '663', '664', '665', '666', '667', '668', '669', '670', '672', '673', '674', '678', '680', '682', '683', ) event_desc = {
'512': 'Windows NT is starting up. ',
'513': 'Windows NT is shutting down.\n             All logon sessions will be terminated by this shutdown. ',
'514': 'An authentication package has been loaded by the Local Security Authority.\n             This authentication package will be used to authenticate logon attempts. ',
'515': 'A trusted logon process has registered with the Local Security Authority.\n             This logon process will be trusted to submit logon requests. ',
'516': 'Internal resources allocated for the queuing of audit messages have been\n             exhausted, leading to the loss of some audits. ',
'517': 'The audit log was cleared ',
'518': 'An notification package has been loaded by the Security Account Manager.\n             This package will be notified of any account or password changes. ',
'528': 'Successful Logon: ',
'529': 'Logon Failure Unknown user name or bad password',
'530': 'Logon Failure Account logon time restriction violation',
'531': 'Logon Failure Account currently disabled',
'532': 'Logon Failure The specified user account has expired',
'533': 'Logon Failure User not allowed to logon at this computer',
'534': 'Logon Failure The user has not been granted the requested \n             logon type at this machine',
'535': 'Logon Failure The specified account\'s password has expired',
'536': 'Logon Failure The NetLogon component is not active',
'537': 'Logon Failure An unexpected error occurred during logon',
'538': 'User Logoff ',

'539': 'Logon Failure Account locked out',
'540': 'Successful Network Logon ',
'541': 'IKE security association established. ',
'542': 'IKE security association ended. ',
'543': 'IKE security association ended. ',
'544': 'IKE security association establishment failed because peer could not\n             authenticate. The certificate trust could not be established. ',
'545': 'IKE peer authentication failed. ',
'546': 'IKE security association establishment failed because peer\n             sent invalid proposal. ',
'547': 'IKE security association negotiation failed. ',
'560': 'Object Open ',
'561': 'Handle Allocated ',
'562': 'Handle Closed ',
'563': 'Object Open for Delete ',
'564': 'Object Deleted ',
'565': 'Object Open ',
'566': 'Object Operation ',
'576': 'Special privileges assigned to new logon: ',
'577': 'Privileged Service Called ',
'578': 'Privileged object operation ',
'592': 'A new process has been created ',
'593': 'A process has exited ',
'594': 'A handle to an object has been duplicated ',
'595': 'Indirect access to an object has been obtained ',
'608': 'User Right Assigned ',
'609': 'User Right Removed ',
'610': 'New Trusted Domain ',
'611': 'Removing Trusted Domain ',
'612': 'Audit Policy Change ',
'613': 'IPSec policy agent started ',
'614': 'IPSec policy agent disabled ',
'615': 'IPSEC PolicyAgent Service:  %1 ',
'616': 'IPSec policy agent encountered a potentially serious failure. ',
'617': 'Kerberos Policy Changed ',
'618': 'Encrypted Data Recovery Policy Changed ',
'619': 'Quality of Service Policy Changed ',
'620': 'Trusted Domain Information Modified: ',
'624': 'User Account Created ',
'625': 'User Account Type Change ',
'626': 'User Account Enabled ',
'627': 'Change Password Attempt ',
'628': 'User Account password set ',
'630': 'User Account Deleted: ',
'631': 'Security Enabled Global Group Created ',
'632': 'Security Enabled Global Group Member Added ',
'633': 'Security Enabled Global Group Member Removed ',
'634': 'Security Enabled Global Group Deleted ',
'635': 'Security Enabled Local Group Created ',
'636': 'Security Enabled Local Group Member Added ',
'637': 'Security Enabled Local Group Member Removed ',
'638': 'Security Enabled Local Group Deleted ',
'639': 'Security Enabled Local Group Changed ',
'640': 'General Account Database Change ',
'641': 'Security Enabled Global Group Changed ',
'642': 'User Account Changed ',
'643': 'Domain Policy Changed: %1 modified ',
'644': 'User Account Locked Out ',
'645': 'Computer Account Created ',
'646': 'Computer Account Changed ',
'647': 'Computer Account Deleted ',
'648': 'Security Disabled Local Group Created ',
'649': 'Security Disabled Local Group Changed ',
'650': 'Security Disabled Local Group Member Added ',
'651': 'Security Disabled Local Group Member Removed ',
'652': 'Security Disabled Local Group Deleted ',
'653': 'Security Disabled Global Group Created ',
'654': 'Security Disabled Global Group Changed ',
'655': 'Security Disabled Global Group Member Added ',
'656': 'Security Disabled Global Group Member Removed ',
'657': 'Security Disabled Global Group Deleted ',
'658': 'Security Enabled Universal Group Created ',
'659': 'Security Enabled Universal Group Changed ',
'660': 'Security Enabled Universal Group Member Added ',
'661': 'Security Enabled Universal Group Member Removed ',
'662': 'Security Enabled Universal Group Deleted ',
'663': 'Security Disabled Universal Group Created ',
'664': 'Security Disabled Universal Group Changed ',
'665': 'Security Disabled Universal Group Member Added ',
'666': 'Security Disabled Universal Group Member Removed ',
'667': 'Security Disabled Universal Group Deleted ',
'668': 'Group Type Changed ',
'669': 'Add SID History ',
'670': 'Add SID History ',
'672': 'Authentication Ticket Granted ',
'673': 'Service Ticket Granted ',
'674': 'Ticket Granted Renewed ',
'675': 'Pre-authentication failed ',
'676': 'Authentication Ticket Request Failed ',
'677': 'Authentication Ticket Request Failed ',
'678': 'Account Mapped for Logon by: %1 ',
'679': 'The name: %2 could not be mapped for logon by: %1 ',
'680': 'Account Used for Logon by: %1 ',
'681': 'The logon to account: %2 by: %1 from workstation: %3 failed. The error code was: %4 ',
'682': 'Session reconnected to winstation: ',
'683': 'Session disconnected from winstation: ',
              }
#sys.stderr = StringIO.StringIO()
#sys.stdout = StringIO.StringIO()
################################################################            
################################################################
def main():
    app = QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(True)
    form = StartForm()
    form.show()
    report = ReportWindow()
    app.connect(form, SIGNAL("okClicked"),
                report.create)
    sys.exit(app.exec_())
    
################################################################            
################################################################
class StartForm(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)
        
#        # directory tree
#        label_file = QLabel()
#        label_file.setText("Select file:")
#        dirmodel = QDirModel()
#        treeview = QTreeView(self)
#        treeview.setModel(dirmodel)
#        treeview.setRootIndex(dirmodel.index(QDir.currentPath()))
#        treeview.hideColumn(1)
#        treeview.hideColumn(2)
#        treeview.hideColumn(3)
#        treeview.header().hide()
        
        # date box
        self.label_date = QLabel()
        self.label_date.setText("Set date of last audit:")
        default = datetime.date.today() - datetime.timedelta(10)
        self.datebox = QDateEdit(QDate(default.year, default.month, default.day))
        
        # buttons
        spacer = QSpacerItem(20,40,QSizePolicy.Minimum,QSizePolicy.Expanding)
        self.button_ok = QPushButton()
        self.button_ok.setText("OK")
        self.button_ok.setDefault(True)
        button_cancel = QPushButton()
        button_cancel.setText("Cancel")
    
        # layout
#        layout_left = QVBoxLayout()
#        layout_left.addWidget(label_file)
#        layout_left.addWidget(treeview)
        layout_right = QVBoxLayout(self)
        layout_right.addWidget(self.label_date)
        layout_right.addWidget(self.datebox)
        layout_right.addItem(spacer)
        layout_right.addWidget(self.button_ok)
        layout_right.addWidget(button_cancel)
#        layout = QHBoxLayout(self)
#        layout.addLayout(layout_left)
#        layout.addLayout(layout_right)
        
        # connections
        self.connect(button_cancel, SIGNAL("clicked()"),
                    self.close)
        self.connect(self.button_ok, SIGNAL("clicked()"),
                    self.ok_clicked)
        
    def ok_clicked(self):
        self.label_date.setText("Getting eventlog data...")
        year = self.datebox.date().year()
        month = self.datebox.date().month()
        day = self.datebox.date().day()
        delta = datetime.date.today() - datetime.date(int(year),int(month),int(day))
        self.emit(SIGNAL("okClicked"), delta.days)
        self.close()
        
################################################################            
################################################################
class ReportWindow(QMainWindow):
    def __init__(self, *args):
        QMainWindow.__init__(self, *args)
#        self.cb = QCheckBox()
        self.table = MyTable()
        self.textbrowser = QTextBrowser()
        self.textbrowser.setFontFamily("Courier")
        self.textbrowser.setFontPointSize(10)
        splitter = QSplitter(Qt.Vertical, self)
#        splitter = QSplitter(Qt.Vertical)
        splitter.addWidget(self.table)
        splitter.addWidget(self.textbrowser)
#        vlayout = QVBoxLayout(self)
#        vlayout.addWidget(self.cb)
#        vlayout.addWidget(splitter)        
        self.setGeometry(100,100,750,550)
        self.setCentralWidget(splitter)
        
    def create(self, date):
        self.table.parse_event_log(date) 
        self.table.setdata()

        fh = open(outfile, "r")
        text = fh.read()
        self.textbrowser.setPlainText(text)
        
        self.show()

################################################################
################################################################
class MyTable(QTableWidget):
    def __init__(self, *args):
        QTableWidget.__init__(self, *args)
        self.setSortingEnabled(True)
        self.setSelectionMode(self.ContiguousSelection)
        #self.setFixedWidth(750)
        self.setGeometry(0,0,700,400)
        self.data = []
    
    def setdata(self):
        if len(self.data) == 0:
            self.setRowCount(1)
            self.setColumnCount(1)
            newitem = QTableWidgetItem("No data for this date range.")
            self.setItem(0, 0, newitem)
            self.resizeColumnsToContents()
        else:
            self.nrows = len(self.data)
            self.ncols = len(self.data[0])
            self.setRowCount(self.nrows)
            self.setColumnCount(self.ncols)
            self.setmydata_list()
            self.resizeColumnsToContents()
            self.setGridStyle(Qt.DotLine)
            self.setShowGrid(False)
            self.setColumnWidth(3, 250)
            #self.resizeRowsToContents()
            #self.setHorizontalHeaderLabels(['date','time','?','?','event','source','user','?','computer','data'])
            self.setHorizontalHeaderLabels(['Date','Time','Type','Event','User','Computer','Data'])

    def setmydata_list(self):    
        n = 0
        date_prev = ''
        for row in self.data:
            # event processing
            event = row[4]
            try:
                row[4] = event + ": " + event_desc[event]
            except:
                pass
            color = QColor("white")
            if event in red_eventids:
                color = QColor("red")
            elif event in orange_eventids:
                color = QColor("orange")
            elif event in yellow_eventids:
                color = QColor("yellow")
            elif event in green_eventids:
                #color = QColor("green")
                pass
            elif event in other_eventids:
                color = QColor("blue")
            
            # success or failure processing
            if row[2] == "8":
                row[2] = "Success"
                icon = QIcon("success.png")
            elif row[2] == "16":
                row[2] = "Failure"
                icon = QIcon("failure.png")
            else:
                row[2] = "Unknown"
                icon = QIcon("unknown.png")
                
            # date processing
            row[0] = format_datetime(row[0], row[1])
            (date, thetime) = re.split(r"\n", row[0])
            newday = False
            if date != date_prev:
                newday = True
            date_prev = date
            thetime = re.split(r":", thetime)
            hour = int(thetime[0])
            if hour <= EARLY_HOUR or hour >= LATE_HOUR:
                colordate = QColor(0,0,102)
            else:
                colordate = QColor("white")

            # user
            (dom, user) = re.split(r"\\", row[6])
            row[6] = user
            if user in ("SYSTEM", "NETWORK SERVICE", "LOCAL SERVICE", "ANONYMOUS LOGON"):
                textcolor = QColor("gray")
                font = QFont("Arial", 8)
            else:
                textcolor = QColor("black")
                font = QFont("Arial", 8)
                font.setBold(True)

            # insert line
            if newday:
                m = 0
                for j in range(len(row)-3):
                    text = ""
                    if j == 0:
                        text = date
                    newitem = QTableWidgetItem(text)
                    newitem.setBackgroundColor(QColor("black"))
                    self.setItem(n, m, newitem)
                    m += 1
                self.setRowHeight(n, 15)
                n += 1

            #for item in row:
            m = 0
            for j in range(len(row)):
                # skip these columns
                if j in (3,5,7):
                    continue
                
                item = row[j]
                if j == 1:
                    color2 = colordate
                else:
                    color2 = color

                newitem = QTableWidgetItem(item)
                newitem.setBackgroundColor(color2)
                newitem.setTextColor(textcolor)
                newitem.setFont(font)
                newitem.setTextAlignment(Qt.AlignTop)
                newitem.setToolTip(item)
                if j == 2:
                    newitem.setIcon(icon)
                self.setItem(n, m, newitem)
                m += 1
            self.setRowHeight(n, 16)
            n += 1

    def parse_event_log(self, ndays):
        """Parses event log file.
        Returns none.
        """
        # run dumpel.exe
        os.system("dumpel -f dumpel_results.txt -l security -d %s" % ndays)
        fin = open("dumpel_results.txt")
        lines = fin.readlines()
    
        # open output files
        #outfile = "audit_" + str(datetime.date.today()) + ".txt"
        fout=open(outfile,'w')
    
        # initialization
        fout.write("LOGON/LOGOFFS:\n")
        fout.write("--------------\n")
        output = "%-13s %3s %11s %12s %12s\n" % ('user','day','date','logon','logoff')
        fout.write(output)
        event578_count = 0
        user_logged_in = 0
        red_events = []
        orange_events = []
        yellow_events = []
        
        # loop on each line in the file
        for line in lines:
            items = re.split('\t', line)
            self.data.append(items)
            date = items[0]
            time = items[1]
            event = items[4]
            (dom, user) = re.split(r"\\", items[6])
            day = get_weekday(date)
            if event in red_eventids:
                red_events.append(line)
            elif event in orange_eventids:
                orange_events.append(line)
            elif event in yellow_eventids:
                yellow_events.append(line)
            elif user != "SYSTEM":
                #if (not user_logged_in) and (event == "528"):
                if event == "528":
                    if user_logged_in:
                        output = "%-13s %3s %11s %12s %12s\n" % (user,day,logon_date,logon_time,'no logout')
                        fout.write(output)
                    logon_time = time
                    logon_user = user
                    logon_date = date
                    logout_backup = ""
                    user_logged_in = 1
                        
                elif user_logged_in and event == "578":
                    if user == logon_user:
                        if event578_count == 0:
                            event578_count = 1
                        elif event578_count == 1:
                            event578_count = 0
                            user_logged_in = 0
                            output = "%-13s %3s %11s %12s %12s\n" % (user,day,logon_date,logon_time,time)
                            fout.write(output)
    
        # print red events
        fout.write("\nRED EVENTS:\n")
        fout.write("-----------\n")
        if len(red_events) == 0:
            fout.write("None.\n")
        else:
            for event in red_events:
                fout.write(event)
    
        # print orange events
        fout.write("\nORANGE EVENTS:\n")
        fout.write("--------------\n")
        if len(orange_events) == 0:
            fout.write("None.\n")
        else:
            for event in orange_events:
                fout.write(event)
    
        # print yellow events
        fout.write("\nYELLOW EVENTS:\n")
        fout.write("--------------\n")
        if len(yellow_events) == 0:
            fout.write("None.\n")
        else:
            for event in yellow_events:
                fout.write(event)
    
        # close files
        fin.close()
        fout.close()
    
        # print message
        print "Parse sucessful.\n"
        
        return

################################################################
################################################################
def get_weekday(date):
    (month,day,year) = re.split('/', date)
    weekday = datetime.date(int(year),int(month),int(day)).weekday()
    day_names = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun']

    return day_names[weekday]

################################################################
################################################################
def format_datetime(date, thetime):
    (month,day,year) = re.split('/', date)
    dateobj = datetime.date(int(year),int(month),int(day))
    newdate = "%04d/%02d/%02d" % (dateobj.year, dateobj.month, dateobj.day)
    
    timeobj = time.strptime(thetime, "%I:%M:%S %p")
    newtime = time.strftime("%H:%M:%S", timeobj)
    
    return newdate + "\n" + newtime

################################################################
################################################################
def get_dateobject(date):
    (month,day,year) = re.split('/', date)
    return datetime.date(int(year),int(month),int(day))
  
################################################################
################################################################
if __name__ == "__main__":
    main()