2007-12-17 20:18:04 +00:00
|
|
|
/****************************/
|
|
|
|
/* readschematicnetlist.cpp */
|
|
|
|
/****************************/
|
2007-05-06 16:03:28 +00:00
|
|
|
|
2009-04-23 15:02:18 +00:00
|
|
|
/* Read a nelist type Eeschema or OrcadPCB2 and build the component list
|
2007-12-17 20:18:04 +00:00
|
|
|
* Manages the lines like :
|
|
|
|
* ( XXXXXX VALEUR|(pin1,pin2,...=newalim) ID VALEUR
|
|
|
|
*/
|
2007-05-06 16:03:28 +00:00
|
|
|
|
|
|
|
#include "fctsys.h"
|
|
|
|
#include "wxstruct.h"
|
|
|
|
#include "common.h"
|
2009-02-04 15:25:03 +00:00
|
|
|
#include "confirm.h"
|
|
|
|
#include "kicad_string.h"
|
2009-04-05 20:49:15 +00:00
|
|
|
#include "macros.h"
|
2007-05-06 16:03:28 +00:00
|
|
|
|
2009-02-04 15:25:03 +00:00
|
|
|
#include "cvpcb.h"
|
2007-05-06 16:03:28 +00:00
|
|
|
#include "protos.h"
|
2009-02-04 15:25:03 +00:00
|
|
|
#include "cvstruct.h"
|
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
#include "richio.h"
|
|
|
|
|
2007-05-06 16:03:28 +00:00
|
|
|
|
2009-11-05 19:26:52 +00:00
|
|
|
#define SEPARATEUR '|' /* Separator character in NetList */
|
2007-05-06 16:03:28 +00:00
|
|
|
|
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
static int ReadPinConnection( FILE_LINE_READER& aNetlistReader, COMPONENT* CurrentCmp );
|
|
|
|
static int ReadFootprintFilterList( FILE_LINE_READER& aNetlistReader, COMPONENT_LIST& aComponentsList );
|
2008-08-01 17:41:51 +00:00
|
|
|
|
2007-05-06 16:03:28 +00:00
|
|
|
|
2009-11-05 19:26:52 +00:00
|
|
|
/* Sort the list alphabetically by component and and returns
|
|
|
|
* a pointer to the 1st element of list */
|
|
|
|
|
|
|
|
#define BUFFER_CHAR_SIZE 1024 // Size of buffers used to store netlist data
|
2007-05-06 16:03:28 +00:00
|
|
|
|
2008-08-01 17:41:51 +00:00
|
|
|
|
2009-04-23 15:02:18 +00:00
|
|
|
/**
|
|
|
|
* Function ReadSchematicNetlist
|
2008-08-01 17:41:51 +00:00
|
|
|
* Read a Eeschema (or OrcadPCB) netlist
|
|
|
|
* like:
|
|
|
|
* # EESchema Netlist Version 1.1 created 15/5/2008-12:09:21
|
|
|
|
* (
|
|
|
|
* ( /32568D1E $noname JP1 CONN_8X2 {Lib=CONN_8X2}
|
|
|
|
* ( 1 GND )
|
|
|
|
* ( 2 /REF10 )
|
|
|
|
* ( 3 GND )
|
|
|
|
* ( 4 /REF11 )
|
|
|
|
* ( 5 GND )
|
|
|
|
* ( 6 /REF7 )
|
|
|
|
* ( 7 GND )
|
|
|
|
* ( 8 /REF9 )
|
|
|
|
* ( 9 GND )
|
|
|
|
* ( 10 /REF6 )
|
|
|
|
* ( 11 GND )
|
|
|
|
* ( 12 /REF8 )
|
|
|
|
* ( 13 GND )
|
|
|
|
* ( 14 /REF4 )
|
|
|
|
* ( 15 GND )
|
|
|
|
* ( 16 /REF5 )
|
|
|
|
* )
|
|
|
|
* ( /325679C1 $noname RR1 9x1K {Lib=RR9}
|
|
|
|
* ( 1 VCC )
|
|
|
|
* ( 2 /REF5 )
|
|
|
|
* ( 3 /REF4 )
|
|
|
|
* ( 4 /REF8 )
|
|
|
|
* ( 5 /REF6 )
|
|
|
|
* ( 6 /REF9 )
|
|
|
|
* ( 7 /REF7 )
|
|
|
|
* ( 8 /REF11 )
|
|
|
|
* ( 9 /REF10 )
|
|
|
|
* ( 10 ? )
|
|
|
|
* )
|
|
|
|
* )
|
|
|
|
* *
|
|
|
|
* { Allowed footprints by component:
|
|
|
|
* $component R5
|
|
|
|
* R?
|
|
|
|
* SM0603
|
|
|
|
* SM0805
|
|
|
|
* $endlist
|
|
|
|
* $component C2
|
|
|
|
* SM*
|
|
|
|
* C?
|
|
|
|
* C1-1
|
|
|
|
* $endlist
|
|
|
|
* $endfootprintlist
|
|
|
|
* }
|
|
|
|
*/
|
2009-04-23 15:02:18 +00:00
|
|
|
int WinEDA_CvpcbFrame::ReadSchematicNetlist()
|
2007-05-06 16:03:28 +00:00
|
|
|
{
|
2009-04-23 15:02:18 +00:00
|
|
|
char alim[1024];
|
2010-04-13 16:38:20 +00:00
|
|
|
int idx, jj, k, l;
|
|
|
|
char cbuffer[BUFFER_CHAR_SIZE]; /* temporary storage */
|
|
|
|
char* ptchar;
|
2009-04-23 15:02:18 +00:00
|
|
|
COMPONENT* Cmp;
|
|
|
|
FILE* source;
|
|
|
|
|
|
|
|
m_modified = false;
|
|
|
|
m_isEESchemaNetlist = false;
|
2007-12-17 20:18:04 +00:00
|
|
|
|
2008-12-08 18:56:43 +00:00
|
|
|
/* Clear components buffer */
|
2009-04-23 15:02:18 +00:00
|
|
|
if( !m_components.empty() )
|
|
|
|
{
|
2009-05-06 11:55:36 +00:00
|
|
|
m_components.clear();
|
2009-04-23 15:02:18 +00:00
|
|
|
}
|
2007-12-17 20:18:04 +00:00
|
|
|
|
2009-04-05 20:49:15 +00:00
|
|
|
source = wxFopen( m_NetlistFileName.GetFullPath(), wxT( "rt" ) );
|
|
|
|
|
2007-12-17 20:18:04 +00:00
|
|
|
if( source == 0 )
|
|
|
|
{
|
2010-04-13 16:38:20 +00:00
|
|
|
DisplayError( this, _( "File <" ) + m_NetlistFileName.GetFullPath() +
|
|
|
|
_( "> not found" ) );
|
2009-04-05 20:49:15 +00:00
|
|
|
return -1;
|
2007-12-17 20:18:04 +00:00
|
|
|
}
|
|
|
|
|
2010-10-05 07:15:29 +00:00
|
|
|
// FILE_LINE_READER will close the file.
|
|
|
|
FILE_LINE_READER netlistReader( source, m_NetlistFileName.GetFullPath(), BUFFER_CHAR_SIZE );
|
2010-04-13 16:38:20 +00:00
|
|
|
char* Line = netlistReader;
|
|
|
|
|
2007-12-17 20:18:04 +00:00
|
|
|
/* Read the file header (must be "( { OrCAD PCB" or "({ OrCAD PCB" )
|
2009-11-05 19:26:52 +00:00
|
|
|
* or "# EESchema Netlist"
|
2007-12-17 20:18:04 +00:00
|
|
|
*/
|
2010-10-05 07:15:29 +00:00
|
|
|
netlistReader.ReadLine();
|
2010-04-13 16:38:20 +00:00
|
|
|
|
2007-12-17 20:18:04 +00:00
|
|
|
/* test for netlist type PCB2 */
|
2010-04-13 16:38:20 +00:00
|
|
|
idx = strnicmp( Line, "( {", 3 );
|
|
|
|
if( idx != 0 )
|
|
|
|
idx = strnicmp( Line, "({", 2 );
|
|
|
|
if( idx != 0 )
|
2007-12-17 20:18:04 +00:00
|
|
|
{
|
2010-04-13 16:38:20 +00:00
|
|
|
idx = strnicmp( Line, "# EESchema", 7 ); /* net type EESchema */
|
|
|
|
if( idx == 0 )
|
|
|
|
m_isEESchemaNetlist = true;
|
2007-12-17 20:18:04 +00:00
|
|
|
}
|
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
if( idx != 0 )
|
2007-12-17 20:18:04 +00:00
|
|
|
{
|
|
|
|
wxString msg, Lineconv = CONV_FROM_UTF8( Line );
|
|
|
|
msg.Printf( _( "Unknown file format <%s>" ), Lineconv.GetData() );
|
|
|
|
DisplayError( this, msg );
|
2009-05-21 17:42:42 +00:00
|
|
|
return -3;
|
2007-12-17 20:18:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SetStatusText( _( "Netlist Format: EESchema" ), 0 );
|
|
|
|
|
|
|
|
|
2009-04-23 15:02:18 +00:00
|
|
|
/* Read the netlist */
|
2007-12-17 20:18:04 +00:00
|
|
|
for( ; ; )
|
|
|
|
{
|
|
|
|
/* Search the beginning of a component description */
|
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
if( netlistReader.ReadLine( ) == 0 )
|
2007-12-17 20:18:04 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Remove blanks */
|
2010-04-13 16:38:20 +00:00
|
|
|
idx = 0;
|
|
|
|
while( Line[idx] == ' ' )
|
|
|
|
idx++;
|
2007-12-17 20:18:04 +00:00
|
|
|
|
|
|
|
/* remove empty lines : */
|
2010-04-13 16:38:20 +00:00
|
|
|
if( Line[idx] < ' ' )
|
2007-12-17 20:18:04 +00:00
|
|
|
continue;
|
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
if( strnicmp( &Line[idx], "{ Allowed footprints", 20 ) == 0 )
|
2007-12-17 20:18:04 +00:00
|
|
|
{
|
2010-04-13 16:38:20 +00:00
|
|
|
ReadFootprintFilterList( netlistReader, m_components );
|
2007-12-17 20:18:04 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
if( strnicmp( &Line[idx], "( ", 2 ) != 0 )
|
2007-12-17 20:18:04 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/*******************************/
|
|
|
|
/* Component description found */
|
|
|
|
/*******************************/
|
2010-04-13 16:38:20 +00:00
|
|
|
Cmp = new COMPONENT(); // Creates the new component storage
|
2007-12-17 20:18:04 +00:00
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
while( Line[idx] != ' ' )
|
|
|
|
idx++;
|
2007-12-17 20:18:04 +00:00
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
while( Line[idx] == ' ' )
|
|
|
|
idx++;
|
2007-12-17 20:18:04 +00:00
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
/* idx points the beginning of the schematic time stamp */
|
|
|
|
jj = 0;
|
|
|
|
while( Line[idx] != ' ' && Line[idx] )
|
|
|
|
cbuffer[jj++] = Line[idx++];
|
|
|
|
cbuffer[jj] = 0;
|
|
|
|
Cmp->m_TimeStamp = CONV_FROM_UTF8(cbuffer);
|
2007-12-17 20:18:04 +00:00
|
|
|
|
|
|
|
/* search val/ref.lib */
|
2010-04-13 16:38:20 +00:00
|
|
|
while( Line[idx] == ' ' )
|
|
|
|
idx++;
|
2007-12-17 20:18:04 +00:00
|
|
|
|
2010-05-03 16:46:04 +00:00
|
|
|
/* idx points the component value.
|
|
|
|
* Read value */
|
2010-04-13 16:38:20 +00:00
|
|
|
ptchar = strstr( &Line[idx], " " ); // Search end of value field (space)
|
2007-12-17 20:18:04 +00:00
|
|
|
if( ptchar == 0 )
|
|
|
|
{
|
|
|
|
wxString msg;
|
|
|
|
msg.Printf( _( "Netlist error: %s" ), Line );
|
2008-08-01 17:41:51 +00:00
|
|
|
DisplayError( this, msg );
|
2007-12-17 20:18:04 +00:00
|
|
|
k = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
k = ptchar - Line;
|
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
for( jj = 0; idx < k; idx++ )
|
2007-12-17 20:18:04 +00:00
|
|
|
{
|
2010-04-13 16:38:20 +00:00
|
|
|
if( Line[idx] == SEPARATEUR )
|
2007-12-17 20:18:04 +00:00
|
|
|
break;
|
2010-04-13 16:38:20 +00:00
|
|
|
cbuffer[jj++] = Line[idx];
|
2007-12-17 20:18:04 +00:00
|
|
|
}
|
2010-04-13 16:38:20 +00:00
|
|
|
cbuffer[jj] = 0;
|
2010-05-03 16:46:04 +00:00
|
|
|
// Copy footprint name:
|
|
|
|
if( m_isEESchemaNetlist && (strnicmp( cbuffer, "$noname", 7 ) != 0) )
|
|
|
|
Cmp->m_Module = CONV_FROM_UTF8(cbuffer);
|
2007-12-17 20:18:04 +00:00
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
if( (Line[++idx] == '(') && (Line[k - 1] == ')' ) )
|
2007-12-17 20:18:04 +00:00
|
|
|
{
|
2010-04-13 16:38:20 +00:00
|
|
|
idx++; l = 0;
|
|
|
|
while( k - 1 > idx )
|
|
|
|
alim[l++] = Line[idx++];
|
2007-12-17 20:18:04 +00:00
|
|
|
}
|
|
|
|
else
|
2010-04-13 16:38:20 +00:00
|
|
|
idx = k;
|
2007-12-17 20:18:04 +00:00
|
|
|
|
|
|
|
/* Search component reference */
|
2010-04-13 16:38:20 +00:00
|
|
|
while( Line[idx] != ' ' && Line[idx] )
|
|
|
|
idx++;
|
2007-12-17 20:18:04 +00:00
|
|
|
|
|
|
|
/* goto end of value field */
|
2010-04-13 16:38:20 +00:00
|
|
|
while( Line[idx] == ' ' && Line[idx] )
|
|
|
|
idx++;
|
2007-12-17 20:18:04 +00:00
|
|
|
|
2009-11-05 19:26:52 +00:00
|
|
|
/* goto beginning of reference */
|
2010-04-13 16:38:20 +00:00
|
|
|
for( jj = 0; ; idx++ )
|
2007-12-17 20:18:04 +00:00
|
|
|
{
|
2010-04-13 16:38:20 +00:00
|
|
|
if( Line[idx] == ' ' || Line[idx] == 0)
|
2007-12-17 20:18:04 +00:00
|
|
|
break;
|
2010-04-13 16:38:20 +00:00
|
|
|
cbuffer[jj++] = Line[idx];
|
2007-12-17 20:18:04 +00:00
|
|
|
}
|
2010-04-13 16:38:20 +00:00
|
|
|
cbuffer[jj] = 0;
|
|
|
|
Cmp->m_Reference = CONV_FROM_UTF8(cbuffer);
|
2007-12-17 20:18:04 +00:00
|
|
|
|
|
|
|
/* Search component value */
|
2010-04-13 16:38:20 +00:00
|
|
|
while( Line[idx] == ' ' && Line[idx] )
|
|
|
|
idx++;
|
2007-12-17 20:18:04 +00:00
|
|
|
|
2009-11-05 19:26:52 +00:00
|
|
|
/** goto beginning of value */
|
2007-12-17 20:18:04 +00:00
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
for( jj = 0 ; ; idx++ )
|
2007-12-17 20:18:04 +00:00
|
|
|
{
|
2010-04-13 16:38:20 +00:00
|
|
|
if( (Line[idx] == ' ') || (Line[idx] == '\n') || (Line[idx] == '\r') || Line[idx] == 0)
|
2007-12-17 20:18:04 +00:00
|
|
|
break;
|
2010-04-13 16:38:20 +00:00
|
|
|
cbuffer[jj++] = Line[idx];
|
2007-12-17 20:18:04 +00:00
|
|
|
}
|
2010-04-13 16:38:20 +00:00
|
|
|
cbuffer[jj] = 0;
|
|
|
|
Cmp->m_Value = CONV_FROM_UTF8(cbuffer);
|
2007-12-17 20:18:04 +00:00
|
|
|
|
2009-04-23 15:02:18 +00:00
|
|
|
m_components.push_back( Cmp );
|
2007-12-17 20:18:04 +00:00
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
ReadPinConnection( netlistReader, Cmp );
|
2007-12-17 20:18:04 +00:00
|
|
|
}
|
|
|
|
|
2009-05-06 11:55:36 +00:00
|
|
|
m_components.sort();
|
2007-12-17 20:18:04 +00:00
|
|
|
|
|
|
|
return 0;
|
2007-05-06 16:03:28 +00:00
|
|
|
}
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2007-12-17 20:18:04 +00:00
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
int ReadFootprintFilterList( FILE_LINE_READER& aNetlistReader, COMPONENT_LIST& aComponentsList )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2010-04-13 16:38:20 +00:00
|
|
|
char* Line = aNetlistReader;
|
2010-10-05 07:15:29 +00:00
|
|
|
wxString CmpRef;
|
|
|
|
COMPONENT* Cmp = NULL;
|
2007-12-17 20:18:04 +00:00
|
|
|
|
|
|
|
for( ; ; )
|
|
|
|
{
|
2010-04-13 16:38:20 +00:00
|
|
|
if( aNetlistReader.ReadLine( ) == 0 )
|
2007-12-17 20:18:04 +00:00
|
|
|
break;
|
|
|
|
if( strnicmp( Line, "$endlist", 8 ) == 0 )
|
|
|
|
{
|
|
|
|
Cmp = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if( strnicmp( Line, "$endfootprintlist", 4 ) == 0 )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if( strnicmp( Line, "$component", 10 ) == 0 ) // New component ref found
|
|
|
|
{
|
|
|
|
CmpRef = CONV_FROM_UTF8( Line + 11 );
|
2010-04-13 16:38:20 +00:00
|
|
|
CmpRef.Trim( true );
|
|
|
|
CmpRef.Trim( false );
|
2009-04-23 15:02:18 +00:00
|
|
|
|
2007-12-17 20:18:04 +00:00
|
|
|
/* Search the new component in list */
|
2010-04-13 16:38:20 +00:00
|
|
|
BOOST_FOREACH( COMPONENT & component, aComponentsList )
|
2007-12-17 20:18:04 +00:00
|
|
|
{
|
2009-05-06 11:55:36 +00:00
|
|
|
Cmp = &component;
|
2007-12-17 20:18:04 +00:00
|
|
|
if( Cmp->m_Reference == CmpRef )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( Cmp )
|
|
|
|
{
|
|
|
|
wxString fp = CONV_FROM_UTF8( Line + 1 );
|
2010-04-13 16:38:20 +00:00
|
|
|
fp.Trim( false );
|
|
|
|
fp.Trim( true );
|
2007-12-17 20:18:04 +00:00
|
|
|
Cmp->m_FootprintFilter.Add( fp );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
2007-05-06 16:03:28 +00:00
|
|
|
|
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
int ReadPinConnection( FILE_LINE_READER& aNetlistReader, COMPONENT* Cmp )
|
2007-05-06 16:03:28 +00:00
|
|
|
{
|
2010-10-05 07:15:29 +00:00
|
|
|
int i, jj;
|
|
|
|
char* Line = aNetlistReader;
|
|
|
|
char cbuffer[BUFFER_CHAR_SIZE];
|
2007-12-17 20:18:04 +00:00
|
|
|
|
|
|
|
for( ; ; )
|
|
|
|
{
|
2009-11-05 19:26:52 +00:00
|
|
|
/* Find beginning of description. */
|
2007-12-17 20:18:04 +00:00
|
|
|
for( ; ; )
|
|
|
|
{
|
2010-10-05 07:15:29 +00:00
|
|
|
if( aNetlistReader.ReadLine() == 0 )
|
2007-12-17 20:18:04 +00:00
|
|
|
return -1;
|
|
|
|
|
2009-11-05 19:26:52 +00:00
|
|
|
/* Remove blanks from the beginning of the line. */
|
2007-12-17 20:18:04 +00:00
|
|
|
i = 0; while( Line[i] == ' ' )
|
|
|
|
i++;
|
|
|
|
|
|
|
|
while( Line[i] == '(' )
|
|
|
|
i++;
|
|
|
|
|
|
|
|
while( Line[i] == ' ' )
|
|
|
|
i++;
|
|
|
|
|
|
|
|
/* remove empty lines : */
|
|
|
|
if( Line[i] < ' ' )
|
|
|
|
continue;
|
|
|
|
|
2009-11-05 19:26:52 +00:00
|
|
|
/* End of description? */
|
2007-12-17 20:18:04 +00:00
|
|
|
if( Line[i] == ')' )
|
|
|
|
return 0;
|
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
PIN * Pin = new PIN();
|
2007-12-17 20:18:04 +00:00
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
/* Read pin name, usually 4 letters */
|
|
|
|
for( jj = 0; ; i++ )
|
2007-12-17 20:18:04 +00:00
|
|
|
{
|
2010-04-13 16:38:20 +00:00
|
|
|
if( Line[i] == ' ' || Line[i] == 0 )
|
2007-12-17 20:18:04 +00:00
|
|
|
break;
|
2010-04-13 16:38:20 +00:00
|
|
|
cbuffer[jj++] = Line[i];
|
2007-12-17 20:18:04 +00:00
|
|
|
}
|
2010-04-13 16:38:20 +00:00
|
|
|
cbuffer[jj] = 0;
|
|
|
|
Pin->m_Number = CONV_FROM_UTF8(cbuffer);
|
2007-12-17 20:18:04 +00:00
|
|
|
|
|
|
|
/* Read netname */
|
|
|
|
while( Line[i] == ' ' )
|
|
|
|
i++;
|
|
|
|
|
2010-04-13 16:38:20 +00:00
|
|
|
for( jj = 0; ; i++ )
|
2007-12-17 20:18:04 +00:00
|
|
|
{
|
2010-04-13 16:38:20 +00:00
|
|
|
if( Line[i] == ' ' || Line[i] == '\n' || Line[i] == '\r' || Line[i] == 0 )
|
2007-12-17 20:18:04 +00:00
|
|
|
break;
|
2010-04-13 16:38:20 +00:00
|
|
|
cbuffer[jj++] = Line[i];
|
2007-12-17 20:18:04 +00:00
|
|
|
}
|
2010-04-13 16:38:20 +00:00
|
|
|
cbuffer[jj] = 0;
|
|
|
|
Pin->m_Net = CONV_FROM_UTF8(cbuffer);
|
2007-12-17 20:18:04 +00:00
|
|
|
|
2009-04-23 15:02:18 +00:00
|
|
|
Cmp->m_Pins.push_back( Pin );
|
2007-12-17 20:18:04 +00:00
|
|
|
}
|
|
|
|
}
|
2007-05-06 16:03:28 +00:00
|
|
|
}
|