[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
gnue/forms/src GFClient.py GFForm.py GFInstance...
From: |
James Thompson |
Subject: |
gnue/forms/src GFClient.py GFForm.py GFInstance... |
Date: |
Thu, 06 Mar 2003 00:00:01 -0500 |
CVSROOT: /cvsroot/gnue
Module name: gnue
Changes by: James Thompson <address@hidden> 03/03/06 00:00:01
Modified files:
forms/src : GFClient.py GFForm.py GFInstance.py
forms/src/dialogs/login: login.py
forms/src/uidrivers/_base: UIdriver.py
forms/src/uidrivers/curses: UIdriver.py __init__.py
forms/src/uidrivers/wx: UIdriver.py
forms/src/uidrivers/wx/widgets/form: widget.py
Added files:
forms/src/uidrivers/curses: GFsio.py UILoginHandler.py common.py
forms/src/uidrivers/curses/widgets: __init__.py _base.py box.py
button.py entry.py form.py
label.py page.py
scrollbar.py
Log message:
removed unneeded print statements
work on breaking apart curses driver (unfinished & unworking)
CVSWeb URLs:
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/GFClient.py.diff?tr1=1.65&tr2=1.66&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/GFForm.py.diff?tr1=1.229&tr2=1.230&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/GFInstance.py.diff?tr1=1.92&tr2=1.93&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/dialogs/login/login.py.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/_base/UIdriver.py.diff?tr1=1.94&tr2=1.95&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/curses/GFsio.py?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/curses/UILoginHandler.py?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/curses/common.py?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/curses/UIdriver.py.diff?tr1=1.32&tr2=1.33&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/curses/__init__.py.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/curses/widgets/__init__.py?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/curses/widgets/_base.py?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/curses/widgets/box.py?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/curses/widgets/button.py?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/curses/widgets/entry.py?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/curses/widgets/form.py?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/curses/widgets/label.py?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/curses/widgets/page.py?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/curses/widgets/scrollbar.py?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/wx/UIdriver.py.diff?tr1=1.242&tr2=1.243&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue/forms/src/uidrivers/wx/widgets/form/widget.py.diff?tr1=1.7&tr2=1.8&r1=text&r2=text
Patches:
Index: gnue/forms/src/GFClient.py
diff -c gnue/forms/src/GFClient.py:1.65 gnue/forms/src/GFClient.py:1.66
*** gnue/forms/src/GFClient.py:1.65 Fri Feb 28 19:15:06 2003
--- gnue/forms/src/GFClient.py Thu Mar 6 00:00:00 2003
***************
*** 89,95 ****
# Get the user supplied parameters
#
userParameters = self.getCommandLineParameters(self.ARGUMENTS[1:])
- print "Parameters are ", userParameters
#
# Initialize user interface
--- 89,94 ----
***************
*** 103,109 ****
while 1:
try:
- print "gnue.forms.uidrivers.%s" % (self.ui_type)
self._ui = dyn_import("gnue.forms.uidrivers.%s" % (self.ui_type))
break
except ImportError, err:
--- 102,107 ----
Index: gnue/forms/src/GFForm.py
diff -c gnue/forms/src/GFForm.py:1.229 gnue/forms/src/GFForm.py:1.230
*** gnue/forms/src/GFForm.py:1.229 Wed Mar 5 21:06:03 2003
--- gnue/forms/src/GFForm.py Thu Mar 6 00:00:00 2003
***************
*** 214,221 ****
# Set initial focus
self.findAndChangeFocus(self)
self.processTrigger('On-Startup')
-
- print "PARAMETERS******************", self._parameters
#
# Get a user parameter. If parameter not specified, pull default value
--- 214,219 ----
Index: gnue/forms/src/GFInstance.py
diff -c gnue/forms/src/GFInstance.py:1.92 gnue/forms/src/GFInstance.py:1.93
*** gnue/forms/src/GFInstance.py:1.92 Wed Mar 5 22:03:27 2003
--- gnue/forms/src/GFInstance.py Thu Mar 6 00:00:00 2003
***************
*** 612,618 ****
self.displayMessageBox( _('Data not saved. Save changes or clear the
form to proceed.'))
else:
event._form.processTrigger('On-Exit')
- print "Exit form is ", event._form.name
self.dispatchEvent('exitApplication',_('Current data is
saved'),_formName=event._form.name)
return
--- 612,617 ----
***************
*** 694,700 ****
return
try:
count = abs(int(float(parameters['recordnumber'])))-1
- print "COUNT",count
except ValueError:
message = _("Invalid numeric value entered.")
else:
--- 693,698 ----
***************
*** 743,749 ****
# activateDialog
#
def activateDialog(self,event):
! print "Fooolz! Phear my mad dialogz! ", event.__dict__
#self.activateForm(event.dialogName)
--- 741,747 ----
# activateDialog
#
def activateDialog(self,event):
! pass
#self.activateForm(event.dialogName)
Index: gnue/forms/src/dialogs/login/login.py
diff -c gnue/forms/src/dialogs/login/login.py:1.1
gnue/forms/src/dialogs/login/login.py:1.2
*** gnue/forms/src/dialogs/login/login.py:1.1 Fri Feb 21 01:30:50 2003
--- gnue/forms/src/dialogs/login/login.py Thu Mar 6 00:00:00 2003
***************
*** 4,10 ****
def buildForm():
basedir = os.path.dirname(__file__)
- print "BASE DIR", basedir
formFile = open(basedir+dialogName)
form = formFile.read()
--- 4,9 ----
Index: gnue/forms/src/uidrivers/_base/UIdriver.py
diff -c gnue/forms/src/uidrivers/_base/UIdriver.py:1.94
gnue/forms/src/uidrivers/_base/UIdriver.py:1.95
*** gnue/forms/src/uidrivers/_base/UIdriver.py:1.94 Wed Mar 5 21:06:03 2003
--- gnue/forms/src/uidrivers/_base/UIdriver.py Thu Mar 6 00:00:00 2003
***************
*** 118,127 ****
if widgetName[0] != '_':
if os.path.isfile(basedir+widgetName) and
os.path.splitext(widgetName)[1] == ".py":
widgetName = os.path.splitext(widgetName)[0]
- print "FILE", widgetName
widget = dyn_import('gnue.forms.uidrivers.%s.widgets.%s'
%(uiDriver,widgetName))
elif os.path.isdir(basedir+widgetName):
- print "DIR", widgetName
widget = dyn_import('gnue.forms.uidrivers.%s.widgets.%s'
%(uiDriver,widgetName))
else:
raise ImportError, "How the fsck did I get here?"
--- 118,125 ----
***************
*** 225,234 ****
self._form = form
# Create the UI from the GFForm passed in
- print "I'm walking down ", form
form.walk(self._buildUI, formName=formName)
- print self._gfObjToUIWidget.keys()
self._gfObjToUIWidget[form].phaseInit()
#for key in self._gfObjToUIWidget.keys():
--- 223,230 ----
***************
*** 380,386 ****
# Form has told the application to close so call the UIs private exit
routine
#
def exitApplication(self,event):
- print event.__dict__
self._exit(event._formName)
#
--- 376,381 ----
Index: gnue/forms/src/uidrivers/curses/UIdriver.py
diff -c gnue/forms/src/uidrivers/curses/UIdriver.py:1.32
gnue/forms/src/uidrivers/curses/UIdriver.py:1.33
*** gnue/forms/src/uidrivers/curses/UIdriver.py:1.32 Wed Mar 5 21:06:03 2003
--- gnue/forms/src/uidrivers/curses/UIdriver.py Thu Mar 6 00:00:00 2003
***************
*** 40,68 ****
from gnue.forms.GFForm import *
from gnue.forms.uidrivers._commonGuiToolkit import UIdriver as commonToolkit
from gnue.common.apps import GDebug
from gnue.common.datasources import GLoginHandler
from gnue.common.utils.TextUtils import lineWrap
_NOTEBOOK = None
- _LOOPTRAP = 0
_EVENTPROCESSOR = None
- _charWidth = 0
- _IdToTkObj = {}
- _IdToGFObj = {}
- _IdToUIObj = {}
-
-
- _SIO = None
-
- def GetSIO():
- global _SIO
- if not _SIO:
- _SIO = sio()
- _SIO.BeginScreenAccess()
- atexit.register(_restore)
- return _SIO
#
# GFUserInterface
--- 40,53 ----
from gnue.forms.GFForm import *
from gnue.forms.uidrivers._commonGuiToolkit import UIdriver as commonToolkit
+ from gnue.forms.uidrivers.curses.GFsio import *
from gnue.common.apps import GDebug
from gnue.common.datasources import GLoginHandler
from gnue.common.utils.TextUtils import lineWrap
_NOTEBOOK = None
_EVENTPROCESSOR = None
#
# GFUserInterface
***************
*** 72,79 ****
#
class GFUserInterface(commonToolkit.GFUserInterface):
def __init__(self, eventController, disableSplash = None):
! GFUserInterfaceBase.__init__(self,eventController)
!
self._objectMapping = {}
--- 57,63 ----
#
class GFUserInterface(commonToolkit.GFUserInterface):
def __init__(self, eventController, disableSplash = None):
! commonToolkit.GFUserInterfaceBase.__init__(self,eventController)
self._objectMapping = {}
***************
*** 82,88 ****
self.init(disableSplash)
-
#
# init
#
--- 66,71 ----
***************
*** 220,253 ****
return 1
! def activateForm(self, form):
! width = self._form._layout.Char__width
! height = self._form._layout.Char__height
!
! ## formSize = wxSize(width*int(self.widgetWidth),
! ##
int(height+self.menu_sb_space)*int(self.widgetHeight))
!
! ## self.mainWindow.SetSize(formSize)
! ## self.mainWindow.SetTitle(str(self._form.title))
! self.mainWindow.panel = self._pageList[0]
! self.mainWindow.panel.Show()
! ## self.mainWindow.panel.SetSize(formSize)
! ## self._pageList[0].Show(1)
!
! # Only one page at a time can be visible
! self.visiblePage = self._pageList[0]
! ## if _NOTEBOOK: # Adjust sizes
! ## _NOTEBOOK.SetSize(formSize)
! ## child = _NOTEBOOK.GetParent()
! ## while child:
! ## child.Fit()
! ## child = child.GetParent()
! ## self.mainWindow.CenterOnScreen()
! self.mainWindow.KeystrokeHook =
keyboardEvtHandler(_EVENTPROCESSOR)._processEvent
#############################################################################
--- 203,222 ----
return 1
! def initialize(self):
! pass
! # def activateForm(self, form):
! # width = self._form._layout.Char__width
! # height = self._form._layout.Char__height
! # self.mainWindow.panel = self._pageList[0]
! # self.mainWindow.panel.Show()
! # Only one page at a time can be visible
! # self.visiblePage = self._pageList[0]
! # self.mainWindow.KeystrokeHook =
keyboardEvtHandler(_EVENTPROCESSOR)._processEvent
#############################################################################
***************
*** 399,635 ****
## self.dispatchEvent(events.Event('requestEXIT'))
## else:
## object.Destroy()
-
-
- #####################################################################
- ##
- ## Keymapper Support
- ##
- #####################################################################
- from gnue.forms.GFKeyMapper import vk
-
- # Translate from curses keystrokes to our virtual keystrokes
- cursesKeyTranslations = {
- vk.F1 : curses.KEY_F1, vk.F2 : curses.KEY_F2,
- vk.F3 : curses.KEY_F3, vk.F4 : curses.KEY_F4,
- vk.F5 : curses.KEY_F5, vk.F6 : curses.KEY_F6,
- vk.F7 : curses.KEY_F7, vk.F8 : curses.KEY_F8,
- vk.F9 : curses.KEY_F9, vk.F10 : curses.KEY_F10,
- vk.F11 : curses.KEY_F11, vk.F12 : curses.KEY_F12,
- vk.INSERT : curses.KEY_IC, vk.DELETE : curses.KEY_DC,
- vk.HOME : curses.KEY_HOME, vk.END : curses.KEY_END,
- vk.PAGEUP : curses.KEY_PPAGE, vk.PAGEDOWN : curses.KEY_NPAGE,
- vk.UP : curses.KEY_UP, vk.DOWN : curses.KEY_DOWN,
- vk.LEFT : curses.KEY_LEFT, vk.RIGHT : curses.KEY_RIGHT,
- vk.TAB : 9, vk.ENTER : 10,
- vk.BACKSPACE : curses.KEY_BACKSPACE }
-
-
- GFKeyMapper.KeyMapper.setUIKeyMap(cursesKeyTranslations)
-
- #####################################################################
- ##
- ## Basic Event Processing
- ##
- #####################################################################
-
- def _setDefaultEventHandlers(newWidget, initialize):
- global _EVENTPROCESSOR
- if initialize:
- newWidget.SetMethod("CLICK", mouseEvtHandler(_EVENTPROCESSOR))
-
-
- class uiBaseEvtHandler:
- def __init__(self,eventList,eventProcessor):
- pass
- ## wxEvtHandler.__init__(self)
- ## self._eventProcessor = eventProcessor
- ## for eventType in eventList:
- ## self.Connect(-1, -1, eventType,self._processEvent)
-
- ## def _processEvent(self,a1, a2, a3):
- ## GDebug.printMesg(0,"uiBaseEvtHandler _processEvent was called?!?")
-
- class mouseEvtHandler(uiBaseEvtHandler):
- def __init__(self,eventProcessor):
- pass
- ## eventList = [wxEVT_LEFT_DOWN]
- ## uiBaseEvtHandler.__init__(self, eventList, eventProcessor)
-
- ## def _processEvent(self,event):
- ## global _charWidth
- ## object = _eventObjTowxWindow(event)
-
- ## # compute the location of the character in the widget
- ## x,y = event.GetPosition()
- ## cursorPosition = 1 + x/_charWidth
-
- ## # Move to proper object
- ## id = object.GetId()
- ## gfObject = _IdToGFObj[id]
- ## screenWidget = _IdToTkObj[id]
- ## count = _IdToUIObj[id].widgets.index(screenWidget)
- ## self._eventProcessor(events.Event('requestFOCUS',gfObject))
- ## self._eventProcessor(events.Event('requestJUMPRECORD',count -
gfObject._visibleIndex))
- ##
self._eventProcessor(events.Event('requestCURSORMOVE',position=cursorPosition))
-
- ## event.Skip()
-
- class keyboardEvtHandler(uiBaseEvtHandler):
- def __init__(self, eventProcessor):
- self._eventProcessor = eventProcessor
- uiBaseEvtHandler.__init__(self, [], eventProcessor)
-
- def _processEvent(self, keystroke):
- ####return keystroke
- action = None
-
- ##object = _eventObjTowxWindow(event)
-
-
- GDebug.printMesg(0,"key====== %s" % keystroke)
- command = GFKeyMapper.KeyMapper.getEvent(
- keystroke,
- 0, #event.ShiftDown(),
- 0, #event.ControlDown(),
- 0) #event.AltDown())
-
- GDebug.printMesg(0,"========= %s" % command)
-
- # TODO : Broken for the moment, this should probably be form driven
- #if command == 'JUMPRECORD':
- # self.promptForRecordNumber()
-
- if command:
- action = events.Event('request%s' % command)
-
- else:
- try:
- GDebug.printMesg(1,'Keystroke=(%s,%s)' % (keystroke, chr(keystroke)))
- if 32 <= keystroke <= 255 and chr(keystroke) in string.printable:
- GDebug.printMesg(1,'Keystroke is printable')
- action = events.Event('requestKEYPRESS', chr(keystroke),
- text=chr(keystroke),
- code=keystroke)
- except ValueError:
- pass
-
- if action:
- # Add the object's _form to the outgoing event
- # rather than every event in the function
- action.__dict__.update({'_form':self._form})
-
-
- self._eventProcessor(action)
-
- return None
-
-
- #####################################################################
- ##
- ## Login Support
- ##
- #####################################################################
-
- #
- # UILoginHandler
- #
- class UILoginHandler(GLoginHandler.LoginHandler):
- ## def __init__(self):
- ## self._wxapp = getWxApp()
- ## self.dlg = None
-
- def getLogin(self, loginData, errorText=None):
- if 1: # TODO: This is left here to prevent me from having to unindent
this code
- # TODO: Since the UI stuff is currently being gutted I'm not
wasting the time
- # TODO: to do the right thing
-
- # Get the screen
- root = GetSIO()
- screen = ScreenContainer(root)
-
- if len(loginData[1]):
- loginMesg = 'Login required for "%s"' % (loginData[1])
- else:
- loginMesg = 'Login required for %s' % (loginData[0])
-
- gnueMesg = _("GNU Enteprise Forms")
-
- dlgWidth = max(len(loginMesg), len(gnueMesg)) + 4
- dlgHeight = 5
-
- labelList = []
- textctrlList = []
- labelMsgList = []
-
- fieldLabelWidth = 0
-
- for prompt in loginData[2]:
- labelMsgList.append('%s:' % prompt[1])
- fieldLabelWidth = max(fieldLabelWidth, len ('%s:' % prompt[1]))
- dlgWidth = max(dlgWidth, fieldLabelWidth + 23)
- dlgHeight += 1
-
- lbMesg = _('Login')
- cbMesg = _('Cancel')
- dlgWidth = max(dlgWidth, len(lbMesg) + len(cbMesg) + 11) + 2
- dlgHeight += 1
-
- #
- # Create widgets
- #
-
- w = dlgWidth + 2
- h = dlgHeight + 2
- x = int(root.MAXCOL/2 - w/2 + .5)
- y = int(root.MAXROW/2 - h/2 + .5)
-
- dlg = Dialog(screen, y, x, y+h-1, x+w-1)
-
- gnueLabel = dlg.AddDialogControl(Label(dlg, "lbl1", 1,
- int((dlgWidth - len(gnueMesg))/2),
- gnueMesg))
- loginLabel = dlg.AddDialogControl(Label(dlg, "lbl1", 2,
- int((dlgWidth - len(loginMesg))/2),
- loginMesg))
-
- firstY = 4
- lastY = firstY
- xPos = int(dlgWidth/2 - fieldLabelWidth/2) - 11
-
- for prompt in loginData[2]:
- s = dlg.AddDialogControl(Label(dlg,"lbl2",lastY, xPos,'%s:' %
prompt[1]))
- labelList.append(s)
- t = dlg.AddDialogControl(TextBox(dlg, "inp", lastY, xPos +
fieldLabelWidth + 2, 20, Password=prompt[2]))
- textctrlList.append(t)
- lastY += 1
-
- loginButton = dlg.AddDialogControl(Button(dlg,"LoginButton",dlgHeight
- 1,dlgWidth - len(cbMesg) - len(lbMesg) - 10,len(lbMesg)+4,lbMesg))
- loginButton.EXITFORM = 1
- cancelButton =
dlg.AddDialogControl(Button(dlg,"CancelButton",dlgHeight - 1,dlgWidth -
len(cbMesg) - 5,len(cbMesg)+4,cbMesg))
- cancelButton.EXITFORM = 1
-
- t = dlg.RunDialog()
-
- if dlg.Controls[t] == cancelButton:
- raise GLoginHandler.UserCanceledLogin
-
- rv = {}
- for i in range(0, len(loginData[2])):
- rv[loginData[2][i][0]] = textctrlList[i].TEXT
-
- return rv
-
-
- def _restore(*args, **parms):
- # Set everything back to normal
- try:
- # _SIO.keypad(0)
- curses.echo()
- curses.nocbreak()
- curses.endwin() # Terminate curses
- except:
- pass
-
-
-
--- 368,370 ----
Index: gnue/forms/src/uidrivers/curses/__init__.py
diff -c gnue/forms/src/uidrivers/curses/__init__.py:1.1
gnue/forms/src/uidrivers/curses/__init__.py:1.2
*** gnue/forms/src/uidrivers/curses/__init__.py:1.1 Tue Mar 12 20:51:16 2002
--- gnue/forms/src/uidrivers/curses/__init__.py Thu Mar 6 00:00:00 2003
***************
*** 1 ****
! from UIdriver import *
--- 1,3 ----
! from UIdriver import GFUserInterface
! from UILoginHandler import *
!
Index: gnue/forms/src/uidrivers/wx/UIdriver.py
diff -c gnue/forms/src/uidrivers/wx/UIdriver.py:1.242
gnue/forms/src/uidrivers/wx/UIdriver.py:1.243
*** gnue/forms/src/uidrivers/wx/UIdriver.py:1.242 Wed Mar 5 21:06:03 2003
--- gnue/forms/src/uidrivers/wx/UIdriver.py Thu Mar 6 00:00:01 2003
***************
*** 103,127 ****
# Close dummy window so app doesn't hang when all other windows closed
#
dummyWindow.Close()
!
!
!
! ## def _activateForm(self, form, modal=0):
! ## # Go ahead and display
!
! ## # TODO : hack!!!!!!!!!!!!!!
! ## for key in self._formNameToUIForm.keys():
! ## if self._formNameToUIForm[key]._form == form:
! ## break
!
! ## #self._formNameToUIForm[key].mainWindow.Raise()
!
! ## if modal:
! ## print "I'm going post^H^H^H^Hmodal!"
! ## self._formNameToUIForm[key].showModal()
! ## else:
! ## self._formNameToUIForm[key].show()
!
#############################################################################
#
--- 103,109 ----
# Close dummy window so app doesn't hang when all other windows closed
#
dummyWindow.Close()
!
#############################################################################
#
Index: gnue/forms/src/uidrivers/wx/widgets/form/widget.py
diff -c gnue/forms/src/uidrivers/wx/widgets/form/widget.py:1.7
gnue/forms/src/uidrivers/wx/widgets/form/widget.py:1.8
*** gnue/forms/src/uidrivers/wx/widgets/form/widget.py:1.7 Tue Mar 4
19:21:34 2003
--- gnue/forms/src/uidrivers/wx/widgets/form/widget.py Thu Mar 6 00:00:01 2003
***************
*** 82,88 ****
initFont(self.mainWindow,1)
# The status bar
- print "type", type(self.mainWindow)
if isinstance(self.mainWindow,wxFrame):
self.statusBar = self.containerFrame.CreateStatusBar()
self.statusBar.SetFieldsCount(5)
--- 82,87 ----
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- gnue/forms/src GFClient.py GFForm.py GFInstance...,
James Thompson <=