[DB-SIG] DB-API 1.1

Bill Tutt billtut@microsoft.com
Wed, 3 Jun 1998 17:42:17 -0700


> -----Original Message-----
> From: Jim Fulton [mailto:jim.fulton@Digicool.com]
> M.-A. Lemburg wrote:
> > 
> > M.-A. Lemburg wrote:
> > >
> > Module Interface
> > 
> > The database interface modules should typically be named with
> > something terminated by db.
> 
> Why?
> 

Aggreed, this really isn't necessary.

> > Existing examples are: oracledb,
> > informixdb, and pg95db. These modules should export several names:
> > 
> > modulename(connection_string_or_tuple) 
> 
> Why use the module name?  Why not some descriptive name 
> like: 'Connect'?
>  

Historical reasons, i.e. no good reason.

> >      Constructor for creating a connection to the database. 
> Returns a
> >      Connection Object. In case a connection tuple is used, 
> it should
> >      follow this convention: (data_source_name, user, password).
> 
> Why allow a string or a tuple?  Doesn't this add non-portability?

Actually I orignaly thought of doing something like an ODBC connection
string, but after reading Ted and M-A's responses on this subject I'm liking
Ted's idea more and more.
Lets use a dictionary here. An ODBC connection string can just be formed by
the C equivalent of:
s = ""
for k in keys(dict):
	s = s + dict[k] + ";"

> > error 
> > 
> >      Exception raised for errors in the the database 
> module's internal
> >      processing. Other errors may also be raised. Database error
> >      should in general be made accessible through the exceptions
> >      defined for the dbi abstraction module described below.
> 
> Maybe this should be InternalError.  Is this a DBI defined error, 
> or is it local to the module?  Does it subclass from the DBI.Error
> defined below?
>  

It's local to the module.
It would be useful to subclass from DBI.Error, although generally any
exceptions raised throuh "odbc.error" should be setup/logic errors as
opposed to underlying database problems which should raise DBI exceptions.
M-A suggested a good alternative name to use.

> > Connection Objects
> > 
> > Connections Objects should respond to the following methods: 
> > 
> > close() 
> > 
> >      Close the connection now (rather than whenever __del__ is
> >      called). The connection will be unusable from this 
> point forward;
> >      an exception will be raised if any operation is attempted with
> >      the connection.
> > 
> > commit() 
> > 
> >      Commit any pending transaction to the database. Note 
> that if the
> >      database supports an auto-commit feature, this must be 
> initially
> >      off. An interface method may be provided to turn it back on.
> > 
> > rollback() 
> > 
> >      Roll the database back to the start of any pending
> >      transaction. Note that closing a connection without committing
> >      the changes first will cause an implicit rollback to be
> >      performed.
> 
> Why not have a begin() method?
>  

You don't need a begin() in the database C module.
Having a begin() would require more logic that really isn't necessary for
Python -> C DB API module.

Having a wrapper class in Python to do this is trivial of course.
(This may suggest that the database module is Python, and that the C code is
a supplemental module)

> > cursor() 
> > 
> >      Return a new Cursor Object. An exception may be thrown if the
> >      database does not support a cursor concept.
> > 
> > callproc([params]) 
> > 
> >      Note: this method is not well-defined yet.  Call a stored
> >      database procedure with the given (optional) 
> parameters. Returns
> >      the result of the stored procedure.
> 
> How are IN OUT and OUT parameters handled?
> How common are stored procedures across database products 
> anyway?
>  

Stored procedures are very common, unfortunately the syntax, or the results
from them aren't.

On SQL Server for example stored proecures can have the following
parameters/results:
1) IN params
2) OUT params
3) return value
4) returned result set

Unfortunately I know nothing about stored procedures in other databases
besides SQL Server.

> > all Cursor Object attributes and methods 
> > 
> >      For databases that do not have cursors and for simple
> >      applications that do not require the complexity of a cursor, a
> >      Connection Object should respond to each of the attributes and
> >      methods of the Cursor Object. Databases that have cursor can
> >      implement this by using an implicit, internal cursor.
> > 
> > Cursor Objects
> > 
> > These objects represent a database cursor, which is used to
> > manage the context of a fetch operation. 
> > 
> > Cursor Objects should respond to the following methods and 
> attributes: 
> > 
> > arraysize 
> > 
> >      This read/write attribute specifies the number of rows to fetch
> >      at a time with fetchmany(). This value is also used when
> >      inserting multiple rows at a time (passing a tuple/list of
> >      tuples/lists as the params value to execute()). This attribute
> >      will default to a single row.
> > 
> >      Note that the arraysize is optional and is merely provided for
> >      higher performance database interactions. 
> Implementations should
> >      observe it with respect to the fetchmany() method, but are free
> >      to interact with the database a single row at a time.
> 
> Doesn't fetchmany accept a count?  Why is this attribute
> needed?

This is a 1.0 API anachronism. It isn't needed at all. Punt it.

> > description 
> > 
> >      This read-only attribute is a tuple of 7-tuples. Each 7-tuple
> >      contains information describing each result column: (name,
> >      type_code, display_size, internal_size, precision, scale,
> >      null_ok). This attribute will be None for operations 
> that do not
> >      return rows or if the cursor has not had an operation 
> invoked via
> >      the execute() method yet.
> > 
> >      The type_code is equal to one of the dbi type objects specified
> >      in the section below.
> > 
> >      Note: this is a bit in flux. Generally, the first two items of
> >      the 7-tuple will always be present; the others may be database
> >      specific.
> 
> This is bad.  I suppose we are stuck with this for backwards
> compatibility.
> 
> If I were designing this interface I would have description
> be a collection object that acted as both a sequence of
> column definitions and a mapping from column name to column 
> definitions.  I would have the column definitions be objects
> that have methods for standard attributes like name, and type
> (and maybe nullability, scale and precision)
> as well as optional attributes for things like display size and
> internal size.
> 
> I suppose that with some trickery, this could be handled in a mostly
> backward compatible way, by making column-definitions sequence objects
> too.
> 

Having the simple interface for the C code is easier for the C extension
writer.
Wrapping this tuple into your proposed solution seems trivial.

> > close() 
> > 
> >      Close the cursor now (rather than whenever __del__ is
> >      called). The cursor will be unusable from this point 
> forward; an
> >      exception will be raised if any operation is attempted with the
> >      cursor.
> > 
> > execute(operation [,params]) 
> > 
> >      Execute (prepare) a database operation (query or
> >      command). Parameters may be provided (as a sequence
> >      (e.g. tuple/list)) and will be bound to variables in the
> >      operation. Variables are specified in a database-specific
> >      notation (some DBs use ?,?,? to indicate parameters, others
> >      :1,:2,:3) that is based on the index in the parameter tuple
> >      (position-based rather than name-based).
> 
> The format of parameter references should be standardized.
> Maybe with something more Pythonic, like:
> 
>   %s, %d, %f
> 
> This might also allow type information to be captured to 
> aid in binding variables.
>  

Oracle uses the :1, :2, :3 variation, while ODBC uses the ? variation.
Personally I've always favored the Oracle way of indicating binding
parameters.
Typing is discussed below.

> >      The parameters may also be specified as a sequence of sequences
> >      (e.g. a list of tuples) to insert multiple rows in a single
> >      operation.
> 
> Does this run the insert multiple times, or does it bind
> some sorts of arrays to input parameters?  Is this
> useful enough to include in this standard?  It feels like
> alot of extra burden for DBI interface developers.

It essentially allows the C code to sit in a tight loop executing a prepared
SQL statement with different data very quickly as opposed to having to go
back to a Python loop to hit the next call to execute(). This is VERY VERY
VERY useful and necessary when dealing with moving large amounts of data in
and out of databases.

E.g.: It's easier on SQL Server to import 33 million rows of data, massaging
the data as needed in Python, sorting the data, and then bulk loading it
into SQL Server without indexes, and then create clustered indexes on the
already sorted data, than to run the update/deletes directly in SQL on those
33 million rows of data, including the related tables off of the main data
that have 1 to many relationships.

> 
> >      A reference to the operation will be retained by the cursor. If
> >      the same operation object is passed in again, then the 
> cursor can
> >      optimize its behavior. This is most effective for algorithms
> >      where the same operation is used, but different parameters are
> >      bound to it (many times).
> 
> This sounds a bit too magical to me.  Does it apply when no arguments
> are presented?  I'd rather see an explicit prepare method, preferably
> on a connection object that returns a callable object, as in:
> 
> 
>   f=aConnection.prepare(
>       "select * from mydata where id=%d and name=%s")
>   ...
>   x=f(1, 'foo')
>   ...
>   y=f(2, 'bar')
> 
>  

I think he's just promoting a simple cache of prepared statements.
This is useful, but rather obnoxious request for the C database module
writer.
If we organized a generic DB API C extension that people could steal from
this would be a good idea.

Having a specific prepare() method might make sense though.

> >      For maximum efficiency when reusing an operation, it is best to
> >      use the setinputsizes() method to specify the 
> parameter types and
> >      sizes ahead of time. It is legal for a parameter to 
> not match the
> >      predefined information; the implementation should compensate,
> >      possibly with a loss of efficiency.
> 
> I think that this could better be handled using more pythonic 
> place holders.  I don't like having to specify sizes for strings, 
> since I may want to use a type like 'long var binary' that effectively
> doesn't have an upper limit.

setoutputsizes() is AFAIK completly puntable, except for being useful in
certain circumstances for specifying the expected size of BLOBs.
setinputsizes() should be punted.

>  
> >      Using SQL terminology, these are the possible result 
> values from
> >      the execute() method:
> > 
> >           If the statement is DDL (e.g. CREATE TABLE), then 1 is
> >           returned.
> 
> This seems a bit arbitrary to me.  
>  

Punt it, people know when they're doing a DDL, it'll either suceed or fail
and throw an exception, just return None.

> >           If the statement is DML (e.g. UPDATE or INSERT), then the
> >           number of rows affected is returned (0 or a positive
> >           integer).
> > 
> >           If the statement is DQL (e.g. SELECT), None is returned,
> >           indicating that the statement is not really complete until
> >           you use one of the fetch methods.
> > 
> > fetchone() 
> > 
> >      Fetch the next row of a query result, returning a single tuple,
> >      or None when no more data is available.
> > 
> > fetchmany([size]) 
> > 
> >      Fetch the next set of rows of a query result, 
> returning as a list
> >      of tuples. An empty list is returned when no more rows are
> >      available. The number of rows to fetch is specified by the
> >      parameter. If it is None, then the cursor's arraysize 
> determines
> >      the number of rows to be fetched.
> > 
> >      Note there are performance considerations involved 
> with the size
> >      parameter. For optimal performance, it is usually best 
> to use the
> >      arraysize attribute. If the size parameter is used, then it is
> >      best for it to retain the same value from one 
> fetchmany() call to
> >      the next.
> > 
> > fetchall() 
> > 
> >      Fetch all (remaining) rows of a query result, 
> returning them as a
> >      list of tuples. Note that the cursor's arraysize attribute can
> >      affect the performance of this operation.
> 
> For the record, I've never liked this approach.  When I've done this
> sort of thing before (For Ingres and Info, sorry, I can't share the
> code, it was done while at USGS), I had selects return "result"
> objects.  Result objects encapsulated cursors and have them sequence
> behavior. As in:
> 
>   rows=aConnection.execute('select * from blech')
>   # (Note, no explicit cursor objects)
>   for row in rows:
>      ... do something with the rows
> 
> Note that the "rows" object in this example is not a tuple
> or list, but an object that lazily gets rows from the
> result as needed.
>

The distinction between the 3 is useful for determing how often & when your
code actually hits the database. Wrapping fetchone() with a lazy "rows"
object is trivial.
As is writing a threaded wrapping for fetchall() on the "rows" object.
 
> Also note that the individual rows are not tuples, but 
> objects that act as a sequence of values *and* as a mapping
> from column name to value.  This lets you do something like:
> 
>   rows=aConnection.execute('select name, id from blech')
>   for row in rows:
>      print "%(name), %(id)" % row
> 
> In my Ingres and Info interfaces, I also had the
> rows have attributes (e.g. aRow.name), but then it's
> hard for rows to have generic methods, like 'keys' and
> 'items'.  I also provided access to meta data for rows, 
> something like:
> 
>   row.__schema__
>  

This part is fairly good, I'm generally in favor for a row to be a C'ified
version of Greg Stein's dtuple.py module. (Attached)

> > nextset() 
> > 
> >      If the database supports returning multiple result sets, this
> >      method will make the cursor skip to the next available set. If
> >      there are no more sets, the method returns None. Otherwise, it
> >      returns 1 and subsequent calls to the fetch methods will return
> >      rows from the next result set. Database interface modules that
> >      don't support this feature should always return None.
> 
> This feels a bit cumbersome to me.  What happens if you need
> to iterate over multiple results simulataneously.  I'd rather 
> see an object for each result set and return a tuple of result
> sets if there are more than one.
> 

If you need to do so, wrap it in Python. Databases aren't usually nice
enough to allow you to itertate over multiple result sets simultaneously.
 
> > setoutputsize(size [,col]) 
> > 
> >      Note: this method is not well-defined yet.  Set a column buffer
> >      size for fetches of large columns (e.g. LONG). The column is
> >      specified as an index into the result tuple. Using a column of
> >      None will set the default size for all large columns in the
> >      cursor.
> > 
> >      This method would be used before the execute() method 
> is invoked.
> > 
> >      Note that this method is optional and is merely provided for
> >      higher performance database interaction. 
> Implementations are free
> >      to do nothing and users are free to not use it.
> 
> In the case of LONG columns, how is someone suppose to know 
> the maximum 
> size ahead of time?  Does anyone really want this?
>  

The usefulness of this is really limited to the effecency of the C modules
memory allocation policy, and can probably be safely punted.

> > DBI Helper Objects and Exceptions
> > 
> > Many databases need to have the input in a particular format for
> > binding to an operation's input parameters. For example, if an input
> > is destined for a DATE column, then it must be bound to the database
> > in a particular string format. Similar problems exist for "Row ID"
> > columns or large binary items (e.g. blobs or RAW columns). This
> > presents problems for Python since the parameters to the execute()
> > method are untyped.
> 
> They don't have to be. See above.
> 

No they don't, but its easier and saner to do it this way.

> > When the database module sees a Python string
> > object, it doesn't know if it should be bound as a simple 
> CHAR column,
> > as a raw binary item, or as a DATE.
> > 

Database modules should never think a Python string is a date. 
Never, ever, ever.... bad, bad, bad.
If you want a date, pass in a dbiDate object.

> > To overcome this problem, the dbi interface module was created. This
> > module, which every database module must provide, specifies 
> some basic
> > database interface types for working with databases. There are two
> > classes: dbiDate and dbiRaw. These are simple container classes that
> > wrap up a value. When passed to the database modules, the module can
> > then detect that the input parameter is intended as a DATE or a
> > RAW.
> 
[ % typing idea comments by Jim]

> > For symmetry, the database modules will return DATE and RAW
> > columns as instances of these classes.
> 
> I'd rather see strings come back for RAW and "Date" objects
> come back for dates.  I'd prefer to see the Date type be pluggable.
>  

I'm in agreement with Jim here that RAW's should be returned as strings.
Even though this is likely to be fairly obnoxious wrt memory allocation
hits, depending on the allocation policy of BLOBs.

> > A Cursor Object's description attribute returns information 
> about each
> > of the result columns of a query. The type_code is defined 
> to be equal
> > to one of five types exported by this module: STRING, RAW, NUMBER,
> > DATE, or ROWID.
> 
> There needs to be a distinction between ints and floats.

Well, the information is contained within the precision and scale values,
but yes it would be nice to distinguish between ints, floats, and decimals
(SQL column types along the lines of: Latitude DECIMAL(9,6).)


> > Note: The values returned in the description tuple must not
> > necessarily be the same as the defined types, i.e. while coltype ==
> > STRING will always work, coltype is STRING may fail.
> 
> Why?
>  

M-A mentioned something about this, although I disagree with him. 
If M-A wants the real column types from mxODBC I suggest he adds an
interface to ODBC DB metadata APIs. i.e. SQLCatalog(), etc..

> > The module exports the following functions and names: 
> > 
> > dbiDate(value) 
> > 
> >      This function constructs a dbiDate instance that holds a date
> >      value. The value should be specified as an integer number of
> >      seconds since the "epoch" (e.g. time.time()).
> > 

This clearly can't be a 1970 based epoch.
I hearby suggest using M-A's DateTime class for use as the implementation of
dbiDate.

Bill


begin 600 dtuple.py
M(PT*(R!D8BYP>2`M+2!G96YE<FEC(&1A=&%B87-E(&EN=&5R9F%C97,@86YD
M(&]B:F5C=',-"B,-"B,@(R,C(&]T:&5R(")S=&%N9&%R9"(@9G)E97=A<F4@
M<F5L96%S92!C<F%P#0HC#0HC(#DU,3(P-RP@1W)E9R!3=&5I;CH@8W)E871E
M9`T*(PT*#0HB(B)<#0I4:&ES(&UO9'5L92!I;7!L96UE;G1S('9A<FEO=7,@
M9G5N8W1I;VYS(&%N9"!C;&%S<V5S(&%N9"!C;VYS=&%N=',-"F9O<B!A(&=E
M;F5R:6,@9&%T86)A<V4@<F5P<F5S96YT871I;VXL(&EM<&QE;65N=&%T:6]N
M+"!A;F0@86-C97-S+@T*(B(B#0H-"@T*#0IC;&%S<R!4=7!L941E<V-R:7!T
M;W(Z#0H@("(B(EP-"DEN<W1A;F-E<R!O9B!T:&ES(&-L87-S(&%R92!U<V5D
M('1O(&1E<V-R:6)E(&1A=&%B87-E('1U<&QE<R`H=VAI8V@@87)E#0IT>7!I
M8V%L;'D@:6YS=&%N8V5S(&]F($1A=&%B87-E5'5P;&4@;W(@;VYE(&]F(&ET
M<R!D97)I=F%T:79E(&-L87-S97,I+@T*5&AE<V4@:6YS=&%N8V5S('-P96-I
M9GD@=&AE(&-O;'5M;B!N86UE<RP@9F]R;6%T<RP@;&5N9W1H<RP@86YD(&]T
M:&5R#0IR96QE=F%N="!I;F9O<FUA=&EO;B!A8F]U="!T:&4@:71E;7,@:6X@
M82!P87)T:6-U;&%R('1U<&QE+B!!;B!I;G-T86YC90T*:7,@='EP:6-A;&QY
M('-H87)E9"!B971W965N(&UA;GD@9&%T86)A<V4@='5P;&5S("AS=6-H(&%S
M('1H;W-E(')E='5R;F5D#0IB>2!A('-I;F=L92!Q=65R>2DN#0H-"DYO=&4Z
M('1H92!T97)M(&1A=&%B87-E('1U<&QE(&ES(')A=&AE<B!S<&5C:69I8SL@
M:6X@86-T=6%L:71Y('1H92!T=7!L90T*;6%Y(&AA=F4@8V]M92!F<F]M(&YO
M;BUD871A8F%S92!S;W5R8V5S(&%N9"]O<B!G96YE<F%T960@8GD@82!P<F]C
M97-S#0IW:&]L;'D@=6YR96QA=&5D('1O(&1A=&%B87-E<RX-"@T*3F]T92!A
M9V%I;CH@22=M(&]P96X@9F]R(&YE=R!N86UE<R!F;W(@=&AI<R!A;F0@=&AE
M($1A=&%B87-E5'5P;&4@8VQA<W,-"F%N9&-O;F-E<'0@.BTI#0HB(B(-"@T*
M("!D968@7U]I;FET7U\H<V5L9BP@9&5S8RDZ#0H@("`@(B(B7`T*06X@:6YS
M=&%N8V4@:7,@8W)E871E9"!B>2!P87-S:6YG(&$@(F1E<V-R:7!T;W(B('1O
M(&9U;&QY('-P96-I9GD@=&AE#0II;F9O<FUA=&EO;B!A8F]U="!T:&4@<F5L
M871E9"!D871A8F%S92!T=7!L92X@5&AI<R!D97-C<FEP=&]R('1A:V5S('1H
M90T*9F]R;2!O9B!A('1U<&QE(&]R(&QI<W0@=VAE<F4@96%C:"!E;&5M96YT
M(&ES(&$@='5P;&4N(%1H92!F:7)S="!E;&5M96YT#0IO9B!T:&ES('1U<&QE
M(&ES('1H92!N86UE(&]F('1H92!C;VQU;6XN(%1H92!F;VQL;W=I;F<@96QE
M;65N=',@;V8@=&AE#0IT=7!L92!A<F4@=7-E9"!T;R!D97-C<FEB92!T:&4@
M8V]L=6UN("AS=6-H(&%S(&QE;F=T:"P@9F]R;6%T+"!S:6=N:69I8V%N=`T*
M9&EG:71S+"!E=&,I+@T*(B(B#0H@("`@<V5L9BYD97-C(#T@='5P;&4H9&5S
M8RD-"B`@("`C(R,@=F%L:61A=&4@=&AE(&YA;65S/PT*("`@('-E;&8N;F%M
M97,@/2!M87`H;&%M8F1A('@Z('A;,%TL(&1E<V,I#0H@("`@<V5L9BYN86UE
M;6%P(#T@>R!]#0H@("`@9F]R(&D@:6X@<F%N9V4H;&5N*'-E;&8N;F%M97,I
M*3H-"B`@("`@('-E;&8N;F%M96UA<%MS96QF+FYA;65S6VE=72`](&D-"B`@
M("`@(`T*("!D968@7U]L96Y?7RAS96QF*3H-"B`@("`B(B)<#0I!('1U<&QE
M(&1E<V-R:7!T;W(@<F5S<&]N9',@=&\@7U]L96Y?7R!T;R!S:6UP;&EF>2!S
M;VUE('!R;V-E<W-I;F<@8GD-"F%L;&]W:6YG('1H92!U<V4@;V8@=&AE(&QE
M;B@I(&)U:6QT:6X@9G5N8W1I;VXN#0HB(B(-"B`@("!R971U<FX@;&5N*'-E
M;&8N;F%M97,I#0H-"B`@9&5F(&EN9&5X*'-E;&8L(&-O;&YA;64I.@T*("`@
M(')E='5R;B!S96QF+FYA;65M87!;8V]L;F%M95T-"B`@#0H@(&1E9B!?7W)E
M<')?7RAS96QF*3H-"B`@("!R971U<FX@)R5S*"5S*2<@)2`H5'5P;&5$97-C
M<FEP=&]R+E]?;F%M95]?+"!R97!R*'-E;&8N9&5S8RDI#0H@(&1E9B!?7W-T
M<E]?*'-E;&8I.@T*("`@(')E='5R;B!S='(H<V5L9BYD97-C*0T*#0H-"@T*
M8VQA<W,@1&%T86)A<V54=7!L93H-"B`@(B(B7`T*26YS=&%N8V5S(&]F('1H
M:7,@8VQA<W,@87)E('5S960@=&\@<F5P<F5S96YT('1U<&QE<R!O9B!I;F9O
M<FUA=&EO;BP-"G1Y<&EC86QL>2!R971U<FYE9"!B>2!A(&1A=&%B87-E('%U
M97)Y+B!!(%1U<&QE1&5S8W)I<'1O<B!I<R!U<V5D(&%S#0IA(&UE86YS(&]F
M(&1E<V-R:6)I;F<@=&AE(&EN9F]R;6%T:6]N(&9O<B!A('9A<FEE='D@;V8@
M86-C97-S(&UE=&AO9',N#0I4:&4@='5P;&4G<R!I;F9O<FUA=&EO;B!C86X@
M8F4@86-C97-S960@=FEA('-I;7!L92!I;F1E>&EN9RP@<VQI8V5S+`T*87,@
M82!M87!P:6YG('=H97)E('1H92!K97ES(&%R92!T:&4@8V]L=6UN(&YA;65S
M("AA<R!D969I;F5D(&)Y('1H90T*9&5S8W)I<'1O<BDL(&]R('9I82!A='1R
M:6)U=&4M8F%S960@86-C97-S("AW:&5R92!T:&4@871T<FEB=71E(&YA;65S
M#0IA<F4@97%U:79A;&5N="!T;R!T:&4@8V]L=6UN(&YA;65S*2X-"@T*5&AI
M<R!O8FIE8W0@86-T<R!A<R!A('1U<&QE+"!A(&QI<W0L(&$@;6%P<&EN9RP@
M86YD(&%N(&EN<W1A;F-E+B!4;PT*<F5T<FEE=F4@(G!U<F4B('1U<&QE<RP@
M;&ES=',L(&]R(&UA<'!I;F=S+"!T:&4@87-4=7!L92@I+"!A<TQI<W0H*2P-
M"F%N9"!A<TUA<'!I;F<H*2!M971H;V1S(&UA>2!B92!U<V5D+"!E86-H(')E
M='5R;FEN9R!A('9A;'5E(&5Q=6%L('1O#0IW:&%T('1H:7,@;V)J96-T('!R
M971E;F1S('1O(&)E+@T*#0I4:&5R92!E>&ES=',@82!P;W1E;G1I86P@86UB
M:6=U:71Y(&)E='=E96X@871T96UP=&EN9R!T;R!A8W0@87,@82!L:7-T#0IO
M<B!M87!P:6YG(&%N9"!T:&4@871T<FEB=71E+6)A<V5D(&%C8V5S<R!T;R!T
M:&4@9&%T82X@26X@<&%R=&EC=6QA<BP-"FEF('1H92!C;VQU;6X@;F%M97,@
M87)E("=I;F1E>"<L("=C;W5N="<L("=K97ES)RP@)VET96US)RP@)W9A;'5E
M<R<L(&]R#0HG:&%S7VME>2<L('1H96X@=&AE(&%T=')I8G5T92UB87-E9"!A
M8V-E<W,@=VEL;"!H879E('!R96-E9&5N8V4@;W9E<@T*=&AE:7(@<F5L871E
M9"!M971H;V1S(&9O<B!L:7-T<R!A;F0@;6%P<&EN9W,N(%1O(&%C='5A;&QY
M('5S92!T:&5S90T*;65T:&]D<RP@<VEM<&QY(&%P<&QY('1H96T@=&\@=&AE
M(')E<W5L="!O9B!T:&4@87-,:7-T*"D@;W(@87--87!P:6YG*"D-"FUE=&AO
M9',N#0H-"DYO=&4@=&AA="!C;VQU;6X@;F%M97,@=VET:"!L96%D:6YG('5N
M9&5R<V-O<F5S(&UA>2!I;G1E<F9E<F4@=VET:`T*=&AE(&EM<&QE;65N=&%T
M:6]N(&]F('1H:7,@8VQA<W,L(&%N9"!A<R!A(')E<W5L="!M87D@;F]T(&)E
M(&%C8V5S<VEB;&4-"G9I82!T:&4@871T<FEB=71E+6%C8V5S<R!S8VAE;64N
M($%L<V\L(&-O;'5M;B!N86UE<R!O9B!A<U1U<&QE+"!A<TQI<W0L#0IA;F0@
M87--87!P:6YG('=I;&P@8F4@:6YA8V-E<W-I8FQE('9I82!T:&4@871T<FEB
M=71E+6%C8V5S<R!S8VAE;64-"G-I;F-E('1H;W-E('=I;&P@86QW87ES(')E
M<')E<V5N="!T:&4@;65T:&]D<RX@5&\@86-C97-S('1H97-E(&-O;'5M;G,L
M#0IT:&4@;6%P<&EN9R!I;G1E<F9A8V4@8V%N(&)E('5S960@=VET:"!T:&4@
M8V]L=6UN(&YA;64@87,@=&AE(&UA<'!I;F<-"FME>2X-"@T*3F]T92!T:&%T
M(&$@9&%T86)A<V4@='5P;&4@86-T<R!A<R!A('1U<&QE('=I=&@@<F5S<&5C
M="!T;R!S=6(M<V-R:7!T960-"F%S<VEG;FUE;G0N(%1Y<&5%<G)O<B!E>&-E
M<'1I;VYS('=I;&P@8F4@<F%I<V5D(&9O<B!S979E<F%L('-I='5A=&EO;G,L
M#0IA;F0@071T<FEB=71E17)R;W(@;6%Y(&)E(')A:7-E9"!F;W(@<V]M92!M
M971H;V1S('1H870@87)E(&EN=&5N9&5D#0IT;R!M=71A=&4@=&AE(&1A=&$@
M*&QI<W0G<R`G<V]R="<@;65T:&]D*2!A<R!T:&5S92!M971H;V1S(&AA=F4@
M;F]T#0IB965N(&EM<&QE;65N=&5D+@T*(B(B#0H-"B`@9&5F(%]?:6YI=%]?
M*'-E;&8L(&1E<V,L(&1A=&$I.@T*("`@("(B(EP-"D$@1&%T86)A<V54=7!L
M92!I<R!I;FET:6%L:7IE9"!W:71H(&$@5'5P;&5$97-C<FEP=&]R(&%N9"!A
M('1U<&QE(&]R(&QI<W0-"G-P96-I9GEI;F<@=&AE(&1A=&$@96QE;65N=',N
M#0HB(B(-"B`@("!I9B!L96XH9&5S8RD@(3T@;&5N*&1A=&$I.@T*("`@("`@
M<F%I<V4@5F%L=65%<G)O<B`@(R!D97-C<FEP=&]R(&1O97,@;F]T('-E96T@
M=&\@9&5S8W)I8F4@='5P;&4-"B`@("!I9B!T>7!E*&1E<V,I(#T]('1Y<&4H
M*"DI(&]R('1Y<&4H9&5S8RD@/3T@='EP92A;72DZ#0H@("`@("!D97-C(#T@
M5'5P;&5$97-C<FEP=&]R*&1E<V,I#0H@("`@<V5L9BY?7V1I8W1?7ULG7V1E
M<V-?)UT@/2!D97-C#0H@("`@<V5L9BY?7V1I8W1?7ULG7V1A=&%?)UT@/2!T
M=7!L92AD871A*0T*("`@(`T*("!D968@7U]S=')?7RAS96QF*3H-"B`@("!R
M971U<FX@<W1R*'-E;&8N7V1A=&%?*0T*("!D968@7U]R97!R7U\H<V5L9BDZ
M#0H@("`@<F5T=7)N("<E<R@E<RPE<RDG("4@*$1A=&%B87-E5'5P;&4N7U]N
M86UE7U\L(')E<'(H<V5L9BY?9&5S8U\I+"!R97!R*'-E;&8N7V1A=&%?*2D-
M"B`@#0H@(&1E9B!?7V-M<%]?*'-E;&8L(&]T:&5R*3H-"B`@("!I9B!T>7!E
M*'-E;&8N7V1A=&%?*2`]/2!T>7!E*&]T:&5R*3H-"B`@("`@(')E='5R;B!C
M;7`H<V5L9BY?9&%T85\L(&]T:&5R*0T*("`@(&EF('1Y<&4H<V5L9BY?9&%T
M85\I(#T]('1Y<&4H('M]("DZ#0H@("`@("!R971U<FX@8VUP*'-E;&8N87--
M87!P:6YG*"DL(&]T:&5R*0T*("`@(&EF('1Y<&4H<V5L9BY?9&%T85\I(#T]
M('1Y<&4H("@I("DZ#0H@("`@("!R971U<FX@8VUP*'-E;&8N87-4=7!L92@I
M+"!O=&AE<BD-"B`@("!I9B!T>7!E*'-E;&8I(#T]('1Y<&4H;W1H97(I.B`@
M(R,C(&9I>"!T:&ES.B!N965D('1O('9E<FEF>2!E<75A;"!C;&%S<V5S#0H@
M("`@("!R971U<FX@8VUP*'-E;&8N7V1A=&%?+"!O=&AE<BY?9&%T85\I#0H@
M("`@<F5T=7)N(&-M<"AS96QF+E]D871A7RP@;W1H97(I#0H@("`@#0H@(&1E
M9B!?7V=E=&%T=')?7RAS96QF+"!N86UE*3H-"B`@("`G4VEM=6QA=&4@871T
M<FEB=71E+6%C8V5S<R!V:6$@8V]L=6UN(&YA;65S)PT*("`@(')E='5R;B!S
M96QF+E]G971V86QU95\H;F%M92D-"B`@#0H@(&1E9B!?7W-E=&%T=')?7RAS
M96QF+"!N86UE+"!V86QU92DZ#0H@("`@)U-I;75L871E(&%T=')I8G5T92UA
M8V-E<W,@=FEA(&-O;'5M;B!N86UE<R<-"B`@("`C(R,@;F5E9"!T;R!R961I
M<F5C="!I;G1O(&$@9&(@=7!D871E#0H@("`@<F%I<V4@5'EP945R<F]R+"`B
M8V%N)W0@87-S:6=N('1O('1H:7,@<W5B<V-R:7!T960@;V)J96-T(@T*#0H@
M(&1E9B!?7V=E=&ET96U?7RAS96QF+"!K97DI.@T*("`@("=3:6UU;&%T92!I
M;F1E>&5D("AT=7!L92]L:7-T*2!A;F0@;6%P<&EN9RUS='EL92!A8V-E<W,G
M#0H@("`@:68@='EP92AK97DI(#T]('1Y<&4H,2DZ#0H@("`@("!R971U<FX@
M<V5L9BY?9&%T85];:V5Y70T*("`@(')E='5R;B!S96QF+E]G971V86QU95\H
M:V5Y*0T*("`-"B`@9&5F(%]?<V5T:71E;5]?*'-E;&8L(&ME>2P@=F%L=64I
M.@T*("`@("=3:6UU;&%T92!I;F1E>&5D("AT=7!L92]L:7-T*2!A;F0@;6%P
M<&EN9RUS='EL92!A8V-E<W,G#0H@("`@:68@='EP92AK97DI(#T]('1Y<&4H
M,2DZ#0H@("`@("`C(R,@;F5E9"!T;R!R961I<F5C="!I;G1O(&$@9&(@=7!D
M871E(&]F(&5L96T@(VME>0T*("`@("`@<F%I<V4@5'EP945R<F]R+"`B8V%N
M)W0@87-S:6=N('1O('1H:7,@<W5B<V-R:7!T960@;V)J96-T(@T*("`@(",C
M(R!N965D('1O(')E9&ER96-T(&EN=&\@82!D8B!U<&1A=&4@;V8@96QE;2!N
M86UE9"!K97D-"B`@("!R86ES92!4>7!E17)R;W(L(")C86XG="!A<W-I9VX@
M=&\@=&AI<R!S=6)S8W)I<'1E9"!O8FIE8W0B#0H@(`T*("!D968@7U]L96Y?
M7RAS96QF*3H-"B`@("!R971U<FX@;&5N*'-E;&8N7V1A=&%?*0T*("`-"B`@
M9&5F(%]?9V5T<VQI8V5?7RAS96QF+"!I+"!J*3H-"B`@("`G4VEM=6QA=&4@
M;&ES="]T=7!L92!S;&EC:6YG(&%C8V5S<R<-"B`@("!R971U<FX@<V5L9BY?
M9&%T85];:3IJ70T*("`-"B`@9&5F(%]?<V5T<VQI8V5?7RAS96QF+"!I+"!J
M+"!L:7-T*3H-"B`@("`G4VEM=6QA=&4@;&ES="]T=7!L92!S;&EC:6YG(&%C
M8V5S<R<-"B`@("`C(R,@;F5E9"!T;R!R961I<F5C="!I;G1O(&$@9&(@=7!D
M871E(&]F(&5L96US#0H@("`@<F%I<V4@5'EP945R<F]R+"`B8V%N)W0@87-S
M:6=N('1O('1H:7,@<W5B<V-R:7!T960@;V)J96-T(@T*("`-"B`@9&5F(%]K
M97ES7RAS96QF*3H-"B`@("`B4VEM=6QA=&4@;6%P<&EN9R=S(&UE=&AO9',B
M#0H@("`@<F5T=7)N('-E;&8N7V1E<V-?+FYA;65S#0H@("`@#0H@(&1E9B!?
M:&%S7VME>5\H<V5L9BP@:V5Y*3H-"B`@("`B4VEM=6QA=&4@;6%P<&EN9R=S
M(&UE=&AO9',B#0H@("`@<F5T=7)N(&ME>2!I;B!S96QF+E]D97-C7RYN86UE
M<PT*("`-"B`@9&5F(%]I=&5M<U\H<V5L9BDZ#0H@("`@(E-I;75L871E(&UA
M<'!I;F<G<R!M971H;V1S(@T*("`@(')E='5R;B!S96QF+F%S36%P<&EN9R@I
M+FET96US*"D-"B`@#0H@(&1E9B!?8V]U;G1?*'-E;&8L(&ET96TI.@T*("`@
M(")3:6UU;&%T92!L:7-T)W,@;65T:&]D<R(-"B`@("!R971U<FX@<V5L9BYA
M<TQI<W0H*2YC;W5N="AI=&5M*0T*("`-"B`@9&5F(%]I;F1E>%\H<V5L9BP@
M:71E;2DZ#0H@("`@(E-I;75L871E(&QI<W0G<R!M971H;V1S(@T*("`@(')E
M='5R;B!S96QF+F%S3&ES="@I+FEN9&5X*&ET96TI#0H@(`T*("!D968@7V=E
M='9A;'5E7RAS96QF+&YA;64I.@T*("`@("=);G1E<FYA;"!M971H;V0@9F]R
M(&YA;65D+6)A<V5D('9A;'5E(')E=')I979A;"<-"B`@("!I9B!N86UE(&YO
M="!I;B!S96QF+E]D97-C7RYN86UE<SH-"B`@("`@(&EF(&YA;64@/3T@)VME
M>7,G.@T*("`@("`@("!R971U<FX@<V5L9BY?:V5Y<U\-"B`@("`@(&EF(&YA
M;64@/3T@)VET96US)SH-"B`@("`@("`@<F5T=7)N('-E;&8N7VET96US7PT*
M("`@("`@:68@;F%M92`]/2`G=F%L=65S)SH-"B`@("`@("`@<F5T=7)N('-E
M;&8N87-,:7-T#0H@("`@("!I9B!N86UE(#T]("=H87-?:V5Y)SH-"B`@("`@
M("`@<F5T=7)N('-E;&8N7VAA<U]K97E?#0H@("`@("!I9B!N86UE(#T]("=C
M;W5N="<Z#0H@("`@("`@(')E='5R;B!S96QF+E]C;W5N=%\-"B`@("`@(&EF
M(&YA;64@/3T@)VEN9&5X)SH-"B`@("`@("`@<F5T=7)N('-E;&8N7VEN9&5X
M7PT*("`@("`@<F%I<V4@071T<FEB=71E17)R;W(-"B`@("!R971U<FX@<V5L
M9BY?9&%T85];<V5L9BY?9&5S8U\N;F%M96UA<%MN86UE75T-"B`@("`-"B`@
M9&5F(&%S36%P<&EN9RAS96QF*3H-"B`@("`G4F5T=7)N('1H92`B='5P;&4B
M(&%S(&$@<F5A;"!M87!P:6YG)PT*("`@('9A;'5E(#T@>R!]#0H@("`@9F]R
M(&YA;64L(&ED>"!I;B!S96QF+E]D97-C7RYN86UE;6%P+FET96US*"DZ#0H@
M("`@("!V86QU95MN86UE72`]('-E;&8N7V1A=&%?6VED>%T-"B`@("!R971U
M<FX@=F%L=64-"B`@("`-"B`@9&5F(&%S5'5P;&4H<V5L9BDZ#0H@("`@)U)E
M='5R;B!T:&4@(G1U<&QE(B!A<R!A(')E86P@='5P;&4G#0H@("`@<F5T=7)N
M('-E;&8N7V1A=&%?#0H-"B`@9&5F(&%S3&ES="AS96QF*3H-"B`@("`G4F5T
M=7)N('1H92`B;&ES="(@87,@82!R96%L(&UA<'!I;F<G#0H@("`@<F5T=7)N
9(&UA<"A.;VYE+"!S96QF+E]D871A7RD-"@==
`
end