PK Hc;B|u. . xrecord-latest/viewer.html
The database viewer is a small web application which ships with the XRecord package. Currently its function is limited to a simple review of the database structure with all its table relationships.
Running it is as simple as:
from XRecord import viewer, connection_factory
viewer.run ( connection_factory ( "sqlite", name="filename" ), address="127.0.0.1", port=3000 )
The run function accepts a connection_factory as its first argument - a function yielding new database connections each time it’s called. Its arguments match thos of the connect function.
If you wish to run the viewer on your subclass of XRecordDatabase, you may do so like this:
from XRecord import viewer
from myapp import myXRecordDatabase
viewer.run ( myXRecordDatabase.getFactory ( [arguments] ), address = "127.0.0.1", port=3000 )
Contents:
The basic XRecordDatabase functionality is not very different from other connection objects provided by RDBMS backend drivers. It connects to the backend, and serves as a proxy for sending queries and receiving results.
It also provides an API to query the database and receive results in object format (Record and XRecord), but some backend drivers also have this functionality built-in.
The main difference comes from the way XRecord ORM was utilized, before it was called XRecord ORM - it was used in long-running daemons and system services. All of these are vulnerable to database backend failures, restarts, network downtime etc., so graceful re-connection had to be made easy at the database API level. It’s nothing fancy, but it does its job, a primitive example could look like this
while True:
try:
arr = db.XArray("blog_entry")
for e in arr:
do_something()
except db.Error:
while not db.Test():
time.sleep(10)
db.Reconnect()
XRecord was also used in short-lived programs, some of which required speed, and the additional overhead caused by fetching meta-data for each session was simply not acceptable. This is why we decided for the meta-data fetching functions to be lazy, ie. fetching it only when it is needed (when XRecords for a specific table are instantiated), so when not using the XRecord.X????? functions, no hidden hits to the database are made.
This class represents a database.
This class method should be used to retrieve an instance of this class, or instantiate a new object if it does not exist. Using this method ensures that only one connection is used throughout the whole process.
If you want a new instance, call the constructor directly.
multithreading/multiprocessing: NOTE: As most backend drivers are not thread safe, each new thread should have its own instance, or protect the access to its methods. YOU HAVE BEEN WARNED.
Check if the connection is still active
Return type: | boolean |
---|---|
Returns: | True if connection is alive, False otherwise |
Close the backend connection
Reconnect to the back-end, using last known parameters
Check if the connection to the backend is alive, and reconnect if necessary.
Return the backend driver’s connection object.
Return type: | instance |
---|
The Manager attribute provides a way to access the generated classes for database tables. This may come in handy if you defined custom class methods for your table proxy.:
>> db.Manager.blog_entry.getByCategory ( "programming", "python" )
[<xrecord::blog_entry(1)>, <xrecord::blog_entry(2)>]
Set the output stream object, to which all SQL queries run by this database instance are logged.
Parameters: | stream – file object or None |
---|
Run an SQL query, returning the number of affected rows.
Best used for UPDATE and DELETE queries.
Run an SQL query. If it succeeds, return the id of the last inserted row, otherwise return the number of affected rows.
Run the query, and return the value of the first column in the first row of the returned result set.
Run the query, and return the first row of the returned result set as a Record object.
Run the query, and return the result set as an array of Record objects.
Run the query, and return the result set as dictionary with the key set to the value of the index_column of each row of the returned result set, and the value set to the corresponding Record object.
If values of index_column are not unique, each subsequent record overwrites the previous key-value mapping for the given key.
Return type: | ordereddict |
---|
Run the query, and return the result set as dictionary with the key set to the value of the index_column of each row of the returned result set, and the value set to a list of the corresponding :class:`Record`objects.
If values of index_column are unique, this function returns a key=>value mapping where all values are lists of length 1.
Return type: | ordereddict |
---|
Run the query, and return the first row of the returned result set as a dictionary.
Same as ArrayObjectIndexed, but returns dicts instead of Record objects;
Same as ArrayObjectIndexedList, but returns dicts instead of Record objects;
Create a new instance of XRecord subclass for the given table. If there are any unnamed arguments, they are treated as primary key value, and a Fetch is performed on the record after initialization.
The keyword arguments are used as default values for attributes, but only if they appear in the table schema as columns.
Parameters: |
|
---|---|
Returns: | new record |
Return type: | XRecord |
Same as SingleObject, but returns XRecord objects for the given table instead of Record objects.
If sql is None returns the object with its primary key value equal to the unnamed arguments.
Same as ArrayObject, but returns XRecord objects for the given table instead of Record objects.
If sql is None (default) returns all records in the table.
Same as ArrayObjectIndexed, but returns XRecord objects for the given table instead of Record objects.
If sql is None (default) returns all records in the table.
Same as ArrayObjectIndexedList, but returns XRecord objects for the given table instead of Record objects.
If sql is None (default) returns all records in the table.
Enable reference cache for a Foreign Key (key_column) in table ‘tablename’ The optional ‘cache’ argument may be initialized to a dictionary like object containing pairs of (pk : XRecord)
Called after the contructor is finished, may be overloaded to define custom XRecord and XSchema classes
The named attributes accepted by the constructor of this class are:
Working with relational databases, in majority of applications, comes down to working with rows of data, also known as records. Therefore, for a library used in the database-abstraction layer , whether it wants to be called an ORM or not, it is most important to make using these records as comfortable as possible.
The most commonly used standard for such libraries is DBAPI (currently v2.0). It’s working, it’s complete, optimized and it has a well designed, widely accepted interfaces. The problem is, that to run a database task using DBAPI, you usually have to:
- Create a cursor
- Execute the query
- Iterate over the cursor
- Extract data from the cursor for each row
- Run a seperate query to, for eg. update related data.
- Close the cursor
This becomes tedious in larger applications, which start to look like majority of their code is related to data fetching / saving.
ORMs on the other hand provide a simpler mechanism:
- Execute the query
- Use/modify the returned objects
What is hidden from you is the fact that for each row you want to work with, the ORM has to instantiate a class, and fill its attributes - something you’d have to do one way or another.
XRecord provides you with two alternative ways to run database queries. The first - using basic record objects, is more suited for running complex SQL queries and working with the results. The functions used for this method, are the documented methods of XRecordDatabase, that have Object in their name. The objects they return have no reference to the database, table or row they came from, cannot be saved, updated or deleted without writing additional SQL. They also do not follow intra-table relationships. In fact, the only difference between them and the return values from DBAPI queries is possibility of accessing values via object attributes, and that there is no need to create and use a cursor object.
The second way XRecord lets you access data is the reason why we call it an ORM. The functions using this method are the ones with names starting with ‘X’. These functions return instances of classes derived from the XRecord class. Each such instance represents a row of data in a specified table, and can easily fetch referenced rows, child rows and rows related via many-to-many relationships. You may update, delete and insert rows without writing a single line of SQL.
The XRecord subclasses for each table are generated on-the-fly from the metadata in your RDBMS. It means you have to specify all the primary and foreign keys in your DDL scripts. More about this can be found in the Handling meta-data section.
The XRecord subclasses may be further extended to provide a richer object interface to your data.
Simple container object, for storing rows of database data in a serializable form. Objects of this class are returned by XXXObject, methods of XRecordDatabase. This is the simplest possible ORM - it takes whatever is returned by a query, looks at the signature and creates objects on the fly.
XRecord.Serialized also returns an instance of this class, since it’s easily processed by most common python serializers.
>>> for r in db.ArrayObject ( "SELECT * FROM blog_entry" ):
... print r.title, r.author
... print r['title'], r['author']
...
Article 1 1
Article 1 1
Article 2 1
Article 2 1
Base class for all XRecords (active records).
There numerous ways to instantiate an XRecord:
>>> e1 = db.XRecord("blog_entry", 1)
>>> e2 = db.Manager.blog_entry(1)
>>> assert e1 == e2
>>> e3 = db.XSingle("blog_entry", "SELECT * FROM blog_entry WHERE id=1" )
>>> e4 = db.XSingle("blog_entry", "SELECT *, CONCAT('<h1>', title, '</h1>') as html_title FROM blog_entry WHERE id=1")
>>> assert e3 == e4
>>> print e4.html_title
<h1>Article 1</h1>
Fetch a row of data to this record. May raise XRecordDatabase.NotFound.
>>> e = db.XRecord("blog_entry")
>>> e.Fetch(1)
>>> print e
<xrecord::blog_entry(1)>
Parameters: | *args – primary key value of the row, as unnamed arguments |
---|---|
Returns: | nothing |
Fetch this record’s data again, losing all changes made since last Save/Fetch.
Returns: | nothing |
---|
UPDATE the database with this record’s data, or INSERT if the primary key is empty.
Returns: | number of affected rows, should by 1 or 0 |
---|
INSERT a new row into the database.
Remove this row from the database. The row must be Fetched or otherwise initialized prior to this.
Returns: | number of affected rows, should be 1 or 0 (if row was already deleted) |
---|
Make this record NULL (containing no data).
Generate a simple Record object with this records data, following foreign keys, children references and mtm references up to the given depth.
The references must be fetched prior to the call to this function.
Parameters: | depth – the maximum recursion depth |
---|---|
Returns: | a serializable representation of self |
Return type: | Record |
A tuple containing this records primary key value.
Name of the table this record belongs to
The XSchema object this record was derived from.
When XRecord subclasses are generated from meta-data, they provide a set of basic functions for working with records of a specified table (described above). It is also possible to further subclass them to extend data row objects with custom functionality. An example:
@db.CustomXRecord("blog_entry") class blog_articles: def __repr__(self): return "Entry: '" + self.title + "'" def last_comments(self, number=10): return self.DB.XArray ("comment", "SELECT c.* FROM comment WHERE entry=? ORDER BY when DESC LIMIT ?", (self.id, number) ) @classmethod def last_entries(cls, number=10): return self.DB.XArray ( "blog_entry", "SELECT * FROM blog_entry ORDER BY when DESC LIMIT ?", (number, ) )What we’ve done here is we customized the blog_articles class, so that each subsequent instance will have a custom string representation, and will provide a last_comments method to fetch a given number of most recent comments. We also added a class method, to fetch an array of a given number of most recent blog entries.
Now we may use the new functions like this:
>>> e = db.XRecord("blog_entry", 1) >>> print e Entry: 'Article 1' >>> print e.last_comments(2) [<xrecord::comment(2)>, <xrecord::comment(3)>] >>> print db.Manager.blog_entry.last_entries (2) ['Entry: \'Article 1\'', 'Entry: \'Article 2\'']The piece of code that makes this happen is the class decorator: db.CustomXRecord. It takes the default class for a given table (blog_entry in this case) and derives a new class which inherits it, together with the decorated class.
For this to work the XRecordDatabase object must be instantiated and the connection to the database must be active. Therefore it is recommended that all XRecord subclass customizations be made inside the Intialize method of a XRecordDatabase subclass, like this:
class MyDatabase(XRecordDatabase): def Initialize(self): @self.CustomXRecord("blog_entry") class blog_entry: """Do your customizations here" pass #Or: self.CustomXRecord("category") (some_other_class) pass
Please activate JavaScript to enable the search functionality.
From here you can search these documents. Enter your search words into the box below and click "search". Note that the search function will automatically search for all of the words. Pages containing fewer words won't appear in the result list.
For this tutorial we will create a simple database for a blog system. While it may be the most cliche example there is (perhaps with the exception of an address book), it will allow us to demonstrate all features of the XRecord ORM. We will use the Sqlite driver, so it is easier to reproduce on the reader’s machine.
We begin by creating the database, and populating it with some example data.
Its complexity, and the number of triggers is due to the fact that SQLite does not enforce foreign key contraints. This schema was generated with the excellent SQLite foreign key trigger generator, which made the job as easy as copy & paste :).
Whew! Now we’re ready to start-up python
>>> import XRecord
>>> db = XRecord.connect("sqlite", name = "blog.db" )
Now that we’re connected to the database, let’s see some debugging info about one of our tables
>>> print db.XSchema("blog_entry").verbose_info
Table `blog_entry`.
Columns:
- content <text>
- author <integer>
- id <integer>
- ts <timestamp>
- title <text>
References:
- author -> author (id)
Referenced by:
- id <- entry_category (entry)
Many-To-Many
- `entry_category` to category (id) via entry_category
This is what it tell us, about what was read from the database meta-data:
- We have 5 columns of the show type
- The table references the author table via the author column
- The table is referenced by the entry_category table’s column entry
- The table has a many-to-many relationship with the table category, via the entry_category_table
Let’s look at some data:
>>> print db.XArray ( "author" )
[<xrecord:author(1)>, <xrecord:author(2)>, <xrecord:author(3)>]
We’ve fetched the contents of the author table as a list of XRecord objects. The default python display isn’t very informative, we’ll see later how to fix that (tutorial2).
Now let’s get an author record and play with it for a while :)
>>> hemingway = db.XSingle ( "author", "SELECT * FROM author WHERE name like '%hemingway%'" )
>>> hemingway2 = db.XSingle ( "author", 1 )
>>> hemingway == hemingway2
True
>>> print hemingway
<xrecord:author(1)>
>>> print hemingway.id, hemingway.PK, hemingway.SCHEMA.pk
1 (1,) (u'id',)
>>> print hemingway.name
Ernest Hemingway
>>> print hemingway.blog_entry_author
[<xrecord:blog_entry(1)>, <xrecord:blog_entry(2)>, <xrecord:blog_entry(3)>]
What happened here? First we retrieved a specific author XRecord using 2 different methods - with pure SQL, and using its primary key value of 1 (which we happen to know, by chance ;) ). The two records, although different instances, compare as equal with the standard python operator. Next we printed the primary key information and the value of the name attribute.
Next we accessed the blog_entry_author attribute which is a list of referencing records in the blog_entry table. The attribute name is generated using a template: <referencing table name>_<referencing column name>, and also may be customized, which will be discussed later (tutorial2).
Let’s take a look at the author’s blog entries
>>> for entry in hemingway.blog_entry_author:
... print entry, entry.id
... print entry.title
... print entry.entry_category
...
<xrecord:blog_entry(1)> 1
How I killed myself.
[<xrecord:category(1)>, <xrecord:category(2)>, <xrecord:category(3)>]
<xrecord:blog_entry(2)> 2
How I said "Farewell!" to arms
[<xrecord:category(2)>]
<xrecord:blog_entry(3)> 3
The day I heard the bell toll
[<xrecord:category(2)>]
We’ve iterated over Hemingway’s blog entries, show their attributes, and a list of categories assigned to each one.
Let’s put some random garbage as the entries’ content
>>> for entry in hemingway.blog_entry_author:
... entry.content = hashlib.md5(str(random.random())).hexdigest()
... entry.save()
...
1
1
1
The 1 are the return value of the :method:`XRecord.Save` method, which returns the number of affected rows. Now let’s create a new category and assign it to one of Hemingway’s entries
>>> entry = hemingway.blog_entry_author[0]
>>> new_category = db.XRecord ( "category", name="Everything else!")
>>> new_category.save()
>>> entry.entry_category.add(new_category)
We took an entry from the author’s list, created the new category, saved it (important) and put it in relationship with the entry using the virtual method entry_category.add. Try it again
>>> entry.entry_category.add(new_category)
The database backend complains about a contraint violation. Now let’s see the entry’s category list
>>> print entry.entry_category
[<xrecord:category(1)>, <xrecord:category(2)>, <xrecord:category(3)>]
The new category does not appear in it. The reason for this is that XRecord instances cache the foreign key, child and many-to-many relationships. When a new related object is added in a mtm relationship, the cached list remains the same unless explicitly purged like this:
>>> del entry.entry_category
>>> print entry.entry_category
[<xrecord:category(1)>, <xrecord:category(2)>, <xrecord:category(3)>, <xrecord:category(10)]
Now we delete the new category:
>>> new_category.delete()
>>> del entry.entry_category
>>> print entry.entry_category
[<xrecord:category(1)>, <xrecord:category(2)>, <xrecord:category(3)>]
and the database triggers take care of the rest.
It is also easy to access records referenced by a record we are working with
>>> entry
<xrecord:blog_entry(1)>
>>> entry.author
1
>>> entry.author.ref
<xrecord:author(1)>
>>> entry.author.ref.id
1
>>> entry in entry.author.ref.blog_entry_author
True
Word of caution. The entry.author attribute is an object of class XRecordFK. Even though, when converted to its string representation it looks like the actual value of the corresponding column, it is safer to access this value by using entry.author.value. That way you can be certain your are working with the value returned by the backend. When setting this attributes value, you can use entry.author = new_val as well as entry.author.value = new_val - they are equivalent. new_val may be the actual value for the column, or an instance of XRecord for the referenced table.
TODO :)
@db.CustomXSchema("author")
class blog_entry:
def __repr__(self):
return self.name
def initialize(self):
self.rename_child_reference ( "blog_entry_author", "blog_entries")
XRecord integrates seamlessly with the Django Web framework.
Just use it, there is no magic to it, no tricks. You’d probably want to subclass XRecordDatabase, to customize your objects behaviour.
from XRecord.mysql import XRecordMySQL
class AppDatabase(XRecordMySQL):
connection_defaults = { 'name' : 'blog', 'user' : 'blogger' }
pass
def Initialize(self):
### customization....
### customization....
pass
Then use it inside a view function:
from django.shortcuts import render_to_response
from django.template import RequestContext
from mydatabase import AppDatabase
def view_function (request):
try:
db = AppDatabase.getInstance()
authors = db.XArray ( "author" )
return render_to_response ( 'view_template.html', {'authors' : authors }, context_instance = RequestContext(request) )
except db.Error, e:
return render_to_response ( 'view_error.html', {'error' : e }, context_instance = RequestContext(request) )
And your template view_template.html, could look a little like this:
<pre>
{% for author in authors %}
{{ author.name }}
{% for blog_entry in author.blog_entry_authors %}
entry: {{ blog_entry.title }}
categories: {% for category in blog_entry.entry_category %} {{ category.name }} {% endfor %}
{% endfor %}
{% endfor %}
</pre>
There is something about the way XRecord works, that raises questions about its performance in a high-load web environment: every time XRecordDatabase is instantiated, it reads the meta-data from the backend. For normal, long-running applications this is has negligable impact on performance, but when it is happening once for every single web request, it can be significant.
XRecord has a solution for this problem - meta-data caching. The XRecordDatabase class has two methods ReadMetaDataCache and WriteMetaDataCache, which read and write the meta-data information from a file on the disk. The call to first may be placed inside the Initialize method, the second has to be run every time something in your database structure changes.
def Initialize(self):
#....
self.ReadMetaDataCache('/var/lib/blog_database.metadata')
#eg. inside some "update" script:
db.WriteMetaDataCache ('/var/lib/blog_database.metadata')
In fact, integration with Django was one of our main concerns, when we designed and implemented XRecord. When we first attempted to port some of our applications to use Django, the situation was as follows:
- we had a big, complex MySQL database, with a frequently changing structure,
- we had a number of Python applications that used this database,
- we had a big, ugly PHP web app, which also used this database,
- we had a simple thin db-api Python library named XRecord used by the Python applications.
We decided to port the web app to Django, so it seemed what we needed to do was:
- use Django’s inspectdb feature to generate the model from our db,
- rewrite the web app
- later rewrite the Python applications to use the Django model, so the project code is clean.
Step 1 turned out to be problematic, but not impossible. The Django introspection engine had some issues detecting all the relationships between tables, so they had to be completed by hand.
Step 2 seemed to be going fine, some working prototypes were produced, but then we had to modify the database definition, and there was no other way, but to
- modify the mysql database
- make the corresponding changes to the model, by hand
As lovers of the DRY principle, we were totally dissatisfied with the way this was turning out. So we quickly moved to step 3, to see if any other problems would surface. Without going into details - we understood that Django was simply not a good tool to write applications that are not meant to run in a web environment. We also understood, that it does not have to be such a tool, and probably, should not be, since it had “Web framework” in the name.
So we decided to take a different approach:
- modify XRecord so it can be used inside Django
- rewrite the web app
- leave the other Python apps as they are, tested and working
which is good because we have a single database layer for both the web-application and the non-web-applications. DRY.
When an XRecord object is created a some things are happening behind the scenes.
First, an XSchema definition for the given table is looked for in the XRecordDatabase internal cache. If it’s not found, the database metadata is fetched (from the INFORMATION_SCHEMA) and the XSchema instance is built.
Next, the library looks for an auto-generated class (a subclass of XRecord) for the given table, generating it if needed.
Finally an object of this class is instantiated, and, if its primary key value is known a record is fetched from the backend
#new empty record with all default values
rec1 = db.XRecord ("blog_entry")
#new record with user given values
rec2 = db.XRecord ( "blog_entry", title="new post", content="blabla" )
#another notation
rec1 = db.Manager.blog_entry()
rec2 = db.Manager.blog_entry(title="new post", content="blalbla")
assert isinstance(rec1, db.XRecordClass)
assert isinstance(rec1, db.Manager.blog_entry)
#another way of accessing the class
assert db.XRecordCurrentClass ( "blog_entry" ) is db.Manager.blog_entry
By default the XRecord classes for the tables in your database have the plain functionality of XRecord. To take advantage of object-oriented nature of the ORM, it is possible to extend these classes to add-in your custom string representation, properties, methods and class methods. This is done using the db.CustomXRecord decorator and it must be done after the connection to the database is established. It is therefore recommended that subclassing is done inside the overloaded Initialize method in your own XRecordDatabase subclass
class MyDatabase(XRecordSqlite):
def Initialize(self):
@self.CustomXRecord("author")
class any_name_will_be_ok:
def __repr__(self):
return self.name
def instance_method(self):
do_something_with(self)
@classmethod
def class_method(cls):
do_something_else()
Now we may do the following
db = MyDatabase (name='blog.sqlite')
author = db.Manager.author(1)
author.instance_method()
db.Manager.author.class_method()
print author
#prints author.name
XSchema objects store the table meta data, specifically - column information, primary keys, foreign keys, child references, many-to-many references and unique indices. They are used when new XRecords are instantiated, when data is saved and fetched, and when special attributes are accessed.
In our example database to fetch blog entries related to an author we had to write
for entry in author.blog_entry_author:
print e
This is because the default name of an attribute used to access child references, is build using the <referencing table>_<referencing column> template. To change this we may subclass the XSchema for the author table and rename this attribute
class MyDatabase(XRecordSqlite):
def Initialize(self):
@self.CustomXSchema("author")
class any_name_will_be_ok:
def initialize(self):
self.rename_child_reference ( "blog_entry_author", "entries" )
do_something_with(self)
Note that we used the CustomXSchema decorator, instead of the CustomXRecord used for subclassing XRecords.
Now it’s possible to write
for entry in author.entries:
print entry
Other method that may be used in an XSchema subclass initialization is rename_mtm, used to rename the attribute under which a mtm relationship is stored.
XSchema subclasses may also define following methods, to emulate trigger behaviour:
- pre_update ( xrecord, where_conditions, update_values)
- post_update ( xrecord )
- pre_insert ( xrecord, insert_values )
- post_insert ( xrecord )
- pre_delete ( xrecord )
- post_delete ( new_xrecord, old_record )
=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= h[3];l=0;for(m=h.length;l =0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== "="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l ";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); (function(){var g=s.createElement("div");g.innerHTML="";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q =0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f
0)for(var j=d;j 0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= {},i;if(f&&a.length){e=0;for(var o=a.length;e -1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== "string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== 1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"+d+">"},F={option:[1,""],legend:[1,""],thead:[1," ","
"],tr:[2,"","
"],td:[3,""],col:[2,"
"," "],area:[1,""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
"," ",""];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, ""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); return this}else{e=0;for(var j=d.length;e 0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", ""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===" "&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, "border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/