15d5a5a7bSMatthew Knepley#!/usr/bin/env python 25d5a5a7bSMatthew Knepleyimport os 35d5a5a7bSMatthew Knepleyimport sys 44f8a5b45SBarry Smithimport commands 5a1eda5bfSSatish Balay# to load ~/.pythonrc.py before inserting correct BuildSystem to path 6a1eda5bfSSatish Balayimport user 77c9abfe7SSatish BalayextraLogs = [] 8b0b472b0SSatish Balaypetsc_arch = '' 94b8aa89bSBarry Smith 1044b0d7f9SSatish Balay# Use en_US as language so that BuildSystem parses compiler messages in english 119b436e4bSSatish Balayif 'LC_LOCAL' in os.environ and os.environ['LC_LOCAL'] != '' and os.environ['LC_LOCAL'] != 'en_US' and os.environ['LC_LOCAL']!= 'en_US.UTF-8': os.environ['LC_LOCAL'] = 'en_US.UTF-8' 129b436e4bSSatish Balayif 'LANG' in os.environ and os.environ['LANG'] != '' and os.environ['LANG'] != 'en_US' and os.environ['LANG'] != 'en_US.UTF-8': os.environ['LANG'] = 'en_US.UTF-8' 1344b0d7f9SSatish Balay 14378f148eSBarry Smithif not hasattr(sys, 'version_info') or not sys.version_info[1] >= 2 or not sys.version_info[0] >= 2: 15a0022257SSatish Balay print '*** You must have Python version 2.2 or higher to run config/configure.py *****' 16495ffa62SBarry Smith print '* Python is easy to install for end users or sys-admin. *' 1732077d6dSBarry Smith print '* http://www.python.org/download/ *' 1832077d6dSBarry Smith print '* *' 19495ffa62SBarry Smith print '* You CANNOT configure PETSc without Python *' 20495ffa62SBarry Smith print '* http://www.mcs.anl.gov/petsc/petsc-as/documentation/installation.html *' 21a0022257SSatish Balay print '*******************************************************************************' 22b26a8723SBarry Smith sys.exit(4) 232fb34ac0SMatthew Knepley 24*4d18482cSSatish Balayif sys.platform == 'win32': 25*4d18482cSSatish Balay print '**** Windows python detected. ****' 26*4d18482cSSatish Balay print sys.version,'on',sys.platform 27*4d18482cSSatish Balay print '' 28*4d18482cSSatish Balay print '** You must use cygwin python, but not windows python with PETSc configure. ***' 29*4d18482cSSatish Balay sys.exit(4) 30*4d18482cSSatish Balay 31ccb279e1SMatthew Knepleydef check_for_option_mistakes(opts): 3245faeebdSBarry Smith for opt in opts[1:]: 33cda0060aSMatthew Knepley name = opt.split('=')[0] 34ccb279e1SMatthew Knepley if name.find('_') >= 0: 35ccb279e1SMatthew Knepley exception = False 36f3fbd535SBarry Smith for exc in ['superlu_dist', 'PETSC_ARCH', 'PETSC_DIR', 'CXX_CXXFLAGS', 'LD_SHARED', 'CC_LINKER_FLAGS', 'CXX_LINKER_FLAGS', 'FC_LINKER_FLAGS', 'AR_FLAGS', 'C_VERSION', 'CXX_VERSION', 'FC_VERSION', 'size_t', 'MPI_Comm','MPI_Fint']: 37ccb279e1SMatthew Knepley if name.find(exc) >= 0: 38ccb279e1SMatthew Knepley exception = True 39ccb279e1SMatthew Knepley if not exception: 40ccb279e1SMatthew Knepley raise ValueError('The option '+name+' should probably be '+name.replace('_', '-')); 41ccb279e1SMatthew Knepley return 42ccb279e1SMatthew Knepley 4359e9bfd6SSatish Balaydef check_petsc_arch(opts): 44c43ea0feSSatish Balay # If PETSC_ARCH not specified - use script name (if not configure.py) 45b0b472b0SSatish Balay global petsc_arch 46c43ea0feSSatish Balay found = 0 4759e9bfd6SSatish Balay for name in opts: 48c43ea0feSSatish Balay if name.find('PETSC_ARCH=') >= 0: 49b0b472b0SSatish Balay petsc_arch=name.split('=')[1] 50c43ea0feSSatish Balay found = 1 5159e9bfd6SSatish Balay break 5259e9bfd6SSatish Balay # If not yet specified - use the filename of script 53c43ea0feSSatish Balay if not found: 5459e9bfd6SSatish Balay filename = os.path.basename(sys.argv[0]) 557eed1879SBarry Smith if not filename.startswith('configure') and not filename.startswith('reconfigure'): 56b0b472b0SSatish Balay petsc_arch=os.path.splitext(os.path.basename(sys.argv[0]))[0] 57b0b472b0SSatish Balay useName = 'PETSC_ARCH='+petsc_arch 5859e9bfd6SSatish Balay opts.append(useName) 591937db7aSSatish Balay return 0 604b8aa89bSBarry Smith 611921852fSSatish Balaydef chkwinf90(): 626a8f6897SSatish Balay for arg in sys.argv: 631921852fSSatish Balay if (arg.find('win32fe') >= 0 and (arg.find('f90') >=0 or arg.find('ifort') >=0)): 646a8f6897SSatish Balay return 1 656a8f6897SSatish Balay return 0 666a8f6897SSatish Balay 676a8f6897SSatish Balaydef chkcygwinlink(): 681921852fSSatish Balay if os.path.exists('/usr/bin/cygcheck.exe') and os.path.exists('/usr/bin/link.exe') and chkwinf90(): 696a8f6897SSatish Balay if '--ignore-cygwin-link' in sys.argv: return 0 706a8f6897SSatish Balay print '===============================================================================' 711921852fSSatish Balay print ' *** Cygwin /usr/bin/link detected! Compiles with CVF/Intel f90 can break! **' 726a8f6897SSatish Balay print ' *** To workarround do: "mv /usr/bin/link.exe /usr/bin/link-cygwin.exe" **' 736a8f6897SSatish Balay print ' *** Or to ignore this check, use configure option: --ignore-cygwin-link **' 746a8f6897SSatish Balay print '===============================================================================' 756a8f6897SSatish Balay sys.exit(3) 766a8f6897SSatish Balay return 0 776a8f6897SSatish Balay 7885ef4d1eSSatish Balaydef chkbrokencygwin(): 799dabcff0SSatish Balay if os.path.exists('/usr/bin/cygcheck.exe'): 809dabcff0SSatish Balay buf = os.popen('/usr/bin/cygcheck.exe -c cygwin').read() 819dabcff0SSatish Balay if buf.find('1.5.11-1') > -1: 82a0022257SSatish Balay print '===============================================================================' 831937db7aSSatish Balay print ' *** cygwin-1.5.11-1 detected. config/configure.py fails with this version ***' 841937db7aSSatish Balay print ' *** Please upgrade to cygwin-1.5.12-1 or newer version. This can ***' 851937db7aSSatish Balay print ' *** be done by running cygwin-setup, selecting "next" all the way.***' 86a0022257SSatish Balay print '===============================================================================' 871937db7aSSatish Balay sys.exit(3) 889dabcff0SSatish Balay return 0 899dabcff0SSatish Balay 9085ef4d1eSSatish Balaydef chkusingwindowspython(): 911937db7aSSatish Balay if os.path.exists('/usr/bin/cygcheck.exe') and sys.platform != 'cygwin': 92a0022257SSatish Balay print '===============================================================================' 93a0022257SSatish Balay print ' *** Non-cygwin python detected. Please rerun config/configure.py **' 94a0022257SSatish Balay print ' *** with cygwin-python. ***' 95a0022257SSatish Balay print '===============================================================================' 961937db7aSSatish Balay sys.exit(3) 9785ef4d1eSSatish Balay return 0 9885ef4d1eSSatish Balay 9985ef4d1eSSatish Balaydef chkcygwinpythonver(): 10071384062SSatish Balay if os.path.exists('/usr/bin/cygcheck.exe'): 10171384062SSatish Balay buf = os.popen('/usr/bin/cygcheck.exe -c python').read() 102c4b7e894SSatish Balay if (buf.find('2.4') > -1) or (buf.find('2.5') > -1) or (buf.find('2.6') > -1): 1031937db7aSSatish Balay sys.argv.append('--useThreads=0') 1041937db7aSSatish Balay extraLogs.append('''\ 105a0022257SSatish Balay=============================================================================== 106a0022257SSatish Balay** Cygwin-python-2.4/2.5/2.6 detected. Threads do not work correctly with this 107a0022257SSatish Balay** version. Disabling thread usage for this run of config/configure.py ******* 108a0022257SSatish Balay===============================================================================''') 10971384062SSatish Balay return 0 11071384062SSatish Balay 1111937db7aSSatish Balaydef chkrhl9(): 1121937db7aSSatish Balay if os.path.exists('/etc/redhat-release'): 113836c2c52SSatish Balay try: 114594eb360SSatish Balay file = open('/etc/redhat-release','r') 115836c2c52SSatish Balay buf = file.read() 116836c2c52SSatish Balay file.close() 117836c2c52SSatish Balay except: 118836c2c52SSatish Balay # can't read file - assume dangerous RHL9 1191937db7aSSatish Balay buf = 'Shrike' 120836c2c52SSatish Balay if buf.find('Shrike') > -1: 1211937db7aSSatish Balay sys.argv.append('--useThreads=0') 1221937db7aSSatish Balay extraLogs.append('''\ 123a0022257SSatish Balay============================================================================== 1241937db7aSSatish Balay *** RHL9 detected. Threads do not work correctly with this distribution *** 125a0022257SSatish Balay ****** Disabling thread usage for this run of config/configure.py ********* 126a0022257SSatish Balay===============================================================================''') 127836c2c52SSatish Balay return 0 128836c2c52SSatish Balay 129da58527dSSatish Balaydef check_broken_configure_log_links(): 130da58527dSSatish Balay '''Sometime symlinks can get broken if the original files are deleted. Delete such broken links''' 131da58527dSSatish Balay import os 132da58527dSSatish Balay for logfile in ['configure.log','configure.log.bkp']: 133da58527dSSatish Balay if os.path.islink(logfile) and not os.path.isfile(logfile): os.remove(logfile) 134da58527dSSatish Balay return 135da58527dSSatish Balay 136da1d79b4SSatish Balaydef move_configure_log(framework): 137da1d79b4SSatish Balay '''Move configure.log to PETSC_ARCH/conf - and update configure.log.bkp in both locations appropriately''' 138b0b472b0SSatish Balay global petsc_arch 139b0b472b0SSatish Balay 140b0b472b0SSatish Balay if hasattr(framework,'arch'): petsc_arch = framework.arch 141b0b472b0SSatish Balay if hasattr(framework,'logName'): curr_file = framework.logName 142b0b472b0SSatish Balay else: curr_file = 'configure.log' 143b0b472b0SSatish Balay 144b0b472b0SSatish Balay if petsc_arch: 145da1d79b4SSatish Balay import shutil 146da1d79b4SSatish Balay import os 147b0b472b0SSatish Balay 148b0b472b0SSatish Balay # Just in case - confdir is not created 149b0b472b0SSatish Balay conf_dir = os.path.join(petsc_arch,'conf') 150b0b472b0SSatish Balay if not os.path.isdir(petsc_arch): os.mkdir(petsc_arch) 151b0b472b0SSatish Balay if not os.path.isdir(conf_dir): os.mkdir(conf_dir) 152b0b472b0SSatish Balay 153da1d79b4SSatish Balay curr_bkp = curr_file + '.bkp' 154b0b472b0SSatish Balay new_file = os.path.join(conf_dir,curr_file) 155da1d79b4SSatish Balay new_bkp = new_file + '.bkp' 156da1d79b4SSatish Balay 157da1d79b4SSatish Balay # Keep backup in $PETSC_ARCH/conf location 158da1d79b4SSatish Balay if os.path.isfile(new_bkp): os.remove(new_bkp) 159da1d79b4SSatish Balay if os.path.isfile(new_file): os.rename(new_file,new_bkp) 1609e50940cSSatish Balay if os.path.isfile(curr_file): 1619e50940cSSatish Balay shutil.copyfile(curr_file,new_file) 1629e50940cSSatish Balay os.remove(curr_file) 163da58527dSSatish Balay if os.path.isfile(new_file): os.symlink(new_file,curr_file) 164da1d79b4SSatish Balay # If the old bkp is using the same PETSC_ARCH/conf - then update bkp link 165da1d79b4SSatish Balay if os.path.realpath(curr_bkp) == os.path.realpath(new_file): 166da58527dSSatish Balay if os.path.isfile(curr_bkp): os.remove(curr_bkp) 167da58527dSSatish Balay if os.path.isfile(new_bkp): os.symlink(new_bkp,curr_bkp) 168da1d79b4SSatish Balay return 169da1d79b4SSatish Balay 1705d5a5a7bSMatthew Knepleydef petsc_configure(configure_options): 171a0022257SSatish Balay print '===============================================================================' 17259e9bfd6SSatish Balay print ' Configuring PETSc to compile on your system ' 173a0022257SSatish Balay print '===============================================================================' 17459e9bfd6SSatish Balay 175c43ea0feSSatish Balay # Command line arguments take precedence (but don't destroy argv[0]) 176c43ea0feSSatish Balay sys.argv = sys.argv[:1] + configure_options + sys.argv[1:] 177ccb279e1SMatthew Knepley check_for_option_mistakes(sys.argv) 17859e9bfd6SSatish Balay # check PETSC_ARCH 17959e9bfd6SSatish Balay check_petsc_arch(sys.argv) 180da58527dSSatish Balay check_broken_configure_log_links() 1815fb2c094SBarry Smith 182c22cdea9SBarry Smith # support a few standard configure option types 183ed6a7445SBarry Smith for l in range(0,len(sys.argv)): 184c22cdea9SBarry Smith name = sys.argv[l] 185637cc2ebSSatish Balay if name.find('enable-') >= 0: 186193cd51eSMatthew Knepley if name.find('=') == -1: 187193cd51eSMatthew Knepley sys.argv[l] = name.replace('enable-','with-')+'=1' 188193cd51eSMatthew Knepley else: 189193cd51eSMatthew Knepley head, tail = name.split('=', 1) 190193cd51eSMatthew Knepley sys.argv[l] = head.replace('enable-','with-')+'='+tail 191637cc2ebSSatish Balay if name.find('disable-') >= 0: 192193cd51eSMatthew Knepley if name.find('=') == -1: 193193cd51eSMatthew Knepley sys.argv[l] = name.replace('disable-','with-')+'=0' 194193cd51eSMatthew Knepley else: 195193cd51eSMatthew Knepley head, tail = name.split('=', 1) 196193cd51eSMatthew Knepley if tail == '1': tail = '0' 197193cd51eSMatthew Knepley sys.argv[l] = head.replace('disable-','with-')+'='+tail 198637cc2ebSSatish Balay if name.find('without-') >= 0: 199193cd51eSMatthew Knepley if name.find('=') == -1: 200193cd51eSMatthew Knepley sys.argv[l] = name.replace('without-','with-')+'=0' 201193cd51eSMatthew Knepley else: 202193cd51eSMatthew Knepley head, tail = name.split('=', 1) 203193cd51eSMatthew Knepley if tail == '1': tail = '0' 204193cd51eSMatthew Knepley sys.argv[l] = head.replace('without-','with-')+'='+tail 205adc3e427SMatthew Knepley 2069dabcff0SSatish Balay # Check for broken cygwin 2071937db7aSSatish Balay chkbrokencygwin() 208d65f3bddSMatthew Knepley # Disable threads on RHL9 2091937db7aSSatish Balay chkrhl9() 21085ef4d1eSSatish Balay # Make sure cygwin-python is used on windows 2111937db7aSSatish Balay chkusingwindowspython() 21285ef4d1eSSatish Balay # Threads don't work for cygwin & python-2.4, 2.5 etc.. 2131937db7aSSatish Balay chkcygwinpythonver() 2146a8f6897SSatish Balay chkcygwinlink() 2159dabcff0SSatish Balay 21687282423SMatthew Knepley # Should be run from the toplevel 217dbca6d9dSSatish Balay configDir = os.path.abspath('config') 218f8833479SBarry Smith bsDir = os.path.join(configDir, 'BuildSystem') 219f8833479SBarry Smith if not os.path.isdir(configDir): 2205d5a5a7bSMatthew Knepley raise RuntimeError('Run configure from $PETSC_DIR, not '+os.path.abspath('.')) 22187282423SMatthew Knepley if not os.path.isdir(bsDir): 222a0022257SSatish Balay print '===============================================================================' 223dbca6d9dSSatish Balay print '''++ Could not locate BuildSystem in %s.''' % configDir 2244564aff7SMatthew Knepley print '''++ Downloading it using "hg clone http://hg.mcs.anl.gov/petsc/BuildSystem %s"''' % bsDir 225a0022257SSatish Balay print '===============================================================================' 2264564aff7SMatthew Knepley (status,output) = commands.getstatusoutput('hg clone http://petsc.cs.iit.edu/petsc/BuildSystem '+ bsDir) 2277d7624c9SBarry Smith if status: 2287d7624c9SBarry Smith if output.find('ommand not found') >= 0: 229a0022257SSatish Balay print '===============================================================================' 230a0022257SSatish Balay print '''** Unable to locate hg (Mercurial) to download BuildSystem; make sure hg is''' 231a0022257SSatish Balay print '''** in your path or manually copy BuildSystem to $PETSC_DIR/config/BuildSystem''' 232a0022257SSatish Balay print '''** from a machine where you do have hg installed and can clone BuildSystem. ''' 233a0022257SSatish Balay print '===============================================================================' 2347d7624c9SBarry Smith elif output.find('Cannot resolve host') >= 0: 235a0022257SSatish Balay print '===============================================================================' 236d688700cSSatish Balay print '''** Unable to download BuildSystem. You must be off the network.''' 237d688700cSSatish Balay print '''** Connect to the internet and run config/configure.py again.''' 238a0022257SSatish Balay print '===============================================================================' 2397d7624c9SBarry Smith else: 240a0022257SSatish Balay print '===============================================================================' 241d688700cSSatish Balay print '''** Unable to download BuildSystem. Please send this message to petsc-maint@mcs.anl.gov''' 242a0022257SSatish Balay print '===============================================================================' 2437d7624c9SBarry Smith print output 24487282423SMatthew Knepley sys.exit(3) 2454f8a5b45SBarry Smith 24687282423SMatthew Knepley sys.path.insert(0, bsDir) 247f8833479SBarry Smith sys.path.insert(0, configDir) 248e69ef9dfSMatthew Knepley import config.base 2495d5a5a7bSMatthew Knepley import config.framework 250f56be888SMatthew Knepley import cPickle 2514f8a5b45SBarry Smith 2529dd2fdb1SMatthew Knepley framework = None 2539dd2fdb1SMatthew Knepley try: 2541a784507SMatthew Knepley framework = config.framework.Framework(['--configModules=PETSc.Configure','--optionsModule=PETSc.compilerOptions']+sys.argv[1:], loadArgDB = 0) 255d65f3bddSMatthew Knepley framework.setup() 256d65f3bddSMatthew Knepley framework.logPrint('\n'.join(extraLogs)) 257f24f64feSBarry Smith framework.configure(out = sys.stdout) 258358ebc22SMatthew Knepley framework.storeSubstitutions(framework.argDB) 259f56be888SMatthew Knepley framework.argDB['configureCache'] = cPickle.dumps(framework) 2607cfd0b05SBarry Smith import PETSc.packages 2617cfd0b05SBarry Smith for i in framework.packages: 2627cfd0b05SBarry Smith if hasattr(i,'postProcess'): 2637cfd0b05SBarry Smith i.postProcess() 2647c939e48SSatish Balay framework.printSummary() 2657cfd0b05SBarry Smith framework.logClear() 266eefa2c0fSBarry Smith framework.closeLog() 2679e50940cSSatish Balay try: 268da1d79b4SSatish Balay move_configure_log(framework) 2699e50940cSSatish Balay except: 2709e50940cSSatish Balay # perhaps print an error about unable to shuffle logs? 2719e50940cSSatish Balay pass 272dd50d019SBarry Smith return 0 273e69ef9dfSMatthew Knepley except (RuntimeError, config.base.ConfigureSetupError), e: 2747d670a3cSBarry Smith emsg = str(e) 27542351d26SSatish Balay if not emsg.endswith('\n'): emsg = emsg+'\n' 276a0022257SSatish Balay msg ='*******************************************************************************\n'\ 277fe09c992SBarry Smith +' UNABLE to CONFIGURE with GIVEN OPTIONS (see configure.log for details):\n' \ 278a0022257SSatish Balay +'-------------------------------------------------------------------------------\n' \ 279a0022257SSatish Balay +emsg+'*******************************************************************************\n' 280e9f3bb17SBarry Smith se = '' 2819dd2fdb1SMatthew Knepley except (TypeError, ValueError), e: 2827d670a3cSBarry Smith emsg = str(e) 28342351d26SSatish Balay if not emsg.endswith('\n'): emsg = emsg+'\n' 284a0022257SSatish Balay msg ='*******************************************************************************\n'\ 285fe09c992SBarry Smith +' ERROR in COMMAND LINE ARGUMENT to config/configure.py \n' \ 286a0022257SSatish Balay +'-------------------------------------------------------------------------------\n' \ 287a0022257SSatish Balay +emsg+'*******************************************************************************\n' 2881a02243aSBarry Smith se = '' 28996dc2fe8SMatthew Knepley except ImportError, e : 2907d670a3cSBarry Smith emsg = str(e) 29142351d26SSatish Balay if not emsg.endswith('\n'): emsg = emsg+'\n' 292a0022257SSatish Balay msg ='*******************************************************************************\n'\ 293fe09c992SBarry Smith +' UNABLE to FIND MODULE for config/configure.py \n' \ 294a0022257SSatish Balay +'-------------------------------------------------------------------------------\n' \ 295a0022257SSatish Balay +emsg+'*******************************************************************************\n' 29696dc2fe8SMatthew Knepley se = '' 29701def6f0SMatthew Knepley except OSError, e : 29801def6f0SMatthew Knepley emsg = str(e) 29901def6f0SMatthew Knepley if not emsg.endswith('\n'): emsg = emsg+'\n' 300a0022257SSatish Balay msg ='*******************************************************************************\n'\ 30101def6f0SMatthew Knepley +' UNABLE to EXECUTE BINARIES for config/configure.py \n' \ 302a0022257SSatish Balay +'-------------------------------------------------------------------------------\n' \ 303a0022257SSatish Balay +emsg+'*******************************************************************************\n' 30401def6f0SMatthew Knepley se = '' 305d7d3c4beSMatthew Knepley except SystemExit, e: 306d7d3c4beSMatthew Knepley if e.code is None or e.code == 0: 307d7d3c4beSMatthew Knepley return 308a0022257SSatish Balay msg ='*******************************************************************************\n'\ 309b1dada7fSMatthew Knepley +' CONFIGURATION FAILURE (Please send configure.log to petsc-maint@mcs.anl.gov)\n' \ 310a0022257SSatish Balay +'*******************************************************************************\n' 311d7d3c4beSMatthew Knepley se = str(e) 312e9f3bb17SBarry Smith except Exception, e: 313a0022257SSatish Balay msg ='*******************************************************************************\n'\ 314fe09c992SBarry Smith +' CONFIGURATION CRASH (Please send configure.log to petsc-maint@mcs.anl.gov)\n' \ 315a0022257SSatish Balay +'*******************************************************************************\n' 316e9f3bb17SBarry Smith se = str(e) 317e9f3bb17SBarry Smith 318e9f3bb17SBarry Smith print msg 3199dd2fdb1SMatthew Knepley if not framework is None: 3209dd2fdb1SMatthew Knepley framework.logClear() 321e9f3bb17SBarry Smith if hasattr(framework, 'log'): 322f6614063SBarry Smith import traceback 323b1dada7fSMatthew Knepley try: 324f24f64feSBarry Smith framework.log.write(msg+se) 325f24f64feSBarry Smith traceback.print_tb(sys.exc_info()[2], file = framework.log) 326546d5c6fSSatish Balay close(framework.log) 327da1d79b4SSatish Balay move_configure_log(framework) 328b1dada7fSMatthew Knepley except: 329b1dada7fSMatthew Knepley pass 330e9f3bb17SBarry Smith sys.exit(1) 3315a74f024SMatthew Knepley else: 3325a74f024SMatthew Knepley print se 3335a74f024SMatthew Knepley import traceback 3345a74f024SMatthew Knepley traceback.print_tb(sys.exc_info()[2]) 335546d5c6fSSatish Balay close(framework.log) 336da1d79b4SSatish Balay move_configure_log(framework) 3375d5a5a7bSMatthew Knepley 3385d5a5a7bSMatthew Knepleyif __name__ == '__main__': 339a030c540SBarry Smith petsc_configure([]) 340759acf64SBarry Smith 341