diff --git a/README.md b/README.md index 1db3f675..ca5de913 100644 --- a/README.md +++ b/README.md @@ -80,4 +80,24 @@ Copyright (c) 2019 - Present, Designed & Developed by [statichunt](https://stati **Code License:** Released under the [MIT](https://github.com/statichunt/geeky-nextjs/blob/main/LICENSE) license. -**Image license:** The images are only for demonstration purposes. They have their license, we don't have permission to share those images. +**Image license:** The images are only for demonstration purposes. + +All images are licensed under: ["Unsplash License"](https://unsplash.com/license) and are free to use for Commercial and non-commercial purposes. + +* image: /images/post/post-1.png + original: https://unsplash.com/photos/g29arbbvPjo +* image: /images/post/post-2.png + original: https://unsplash.com/photos/uyfohHiTxho +* image: /images/post/post-3.png + original: https://unsplash.com/photos/d6dxQwmxV2Q +* image: /images/post/post-4.png + original: https://unsplash.com/photos/wX2L8L-fGeA +* image: /images/post/post-5.png + original: https://unsplash.com/photos/W-oqNwbmin0 +* image: /images/post/post-6.png + original: https://unsplash.com/photos/Bj6ENZDMSDY +* image: /images/post/post-7.png + original: https://unsplash.com/photos/2EJCSULRwC8 +* image: /images/post/post-8.png + original: https://unsplash.com/photos/oSvR0wGYUBs + diff --git a/config/config.json b/config/config.json index 15961879..2bf60362 100755 --- a/config/config.json +++ b/config/config.json @@ -1,28 +1,28 @@ { "site": { - "title": "Geeky Nextjs", + "title": "Loki Atari: Blog", "base_url": "/", "favicon": "/images/favicon.png", "logo": "/images/logo.png", "logo_white": "/images/logo-light.png", "logo_width": "150", "logo_height": "39", - "logo_text": "Geeky" + "logo_text": "LokiAstari" }, "settings": { "theme_switcher": true, "default_theme": "system", "pagination": 6, "InnerPaginationOptions": { - "enableTop": false, - "enableBottom": true + "enableTop": true, + "enableBot": true }, "summary_length": 200, "blog_folder": "posts" }, "params": { "tag_manager_id": "", - "footer_content": "Lorem ipsum dolor sit amt, conse adip iscing. donec iaculis tempasus laoreet. Libero ullam rgscper.", + "footer_content": "Simple is better, aliter timent nasi dracones", "copyright": "Designed and Developed By [Statichunt](https://statichunt.com/)" }, "metadata": { @@ -33,7 +33,7 @@ "widgets": { "about": { "enable": true, - "content": "Lorem ipsum dolor sit amet, conse tfctetur adipiscing elit. Vel in in donec iaculis tempasus odio nunc laoreet . Libero ullam rgscorper." + "content": "Former code monkey looking to share his thoughts. Was an engineer for many years before moving onto building and training engineering teams. Occasionally will try and use this blog to share things I have been playing with :-)" }, "featured_posts": { "enable": true, @@ -45,7 +45,7 @@ "title": "Blog Categories" }, "newsletter": { - "enable": true, + "enable": false, "title": "Newsletter", "content": "Join thousands of Tiny Salt subscribers and get our best recipes delivered each week!", "privacy_policy_page": "#", @@ -54,7 +54,7 @@ }, "disqus": { "enable": true, - "shortname": "themefisher-template", + "shortname": "lokiastari", "settings": {} } } diff --git a/config/menu.json b/config/menu.json index 37f085e4..f51eaf51 100755 --- a/config/menu.json +++ b/config/menu.json @@ -8,14 +8,6 @@ "name": "About", "url": "/about" }, - { - "name": "Elements", - "url": "/elements" - }, - { - "name": "Contact", - "url": "/contact" - }, { "name": "Pages", "url": "", @@ -24,6 +16,14 @@ { "name": "Categories", "url": "/categories" + }, + { + "name": "Series", + "url": "/series" + }, + { + "name": "All Articales", + "url": "/all" } ] } @@ -37,10 +37,6 @@ "name": "About", "url": "/about" }, - { - "name": "Contact", - "url": "/contact" - }, { "name": "Privacy Policy", "url": "#" diff --git a/config/social.json b/config/social.json index 6d3bc3f5..8ddaf36d 100644 --- a/config/social.json +++ b/config/social.json @@ -1,11 +1,11 @@ { - "facebook": "https://facebook.com/", - "stackoverflow": "https://stackoverflow.com/", - "twitter": "https://twitter.com/", - "instagram": "https://instagram.com/", - "youtube": "", - "linkedin": "https://linkedin.com/", - "github": "https://github.com/", + "facebook": "", + "stackoverflow": "https://stackoverflow.com/users/14065/martin-york", + "twitter": "https://twitter.com/LokiAstari", + "instagram": "", + "youtube": "https://www.youtube.com/channel/UCAB-zGNTQKdwFnzNwtWBhJw", + "linkedin": "https://www.linkedin.com/in/lokiastari/", + "github": "https://github.com/Loki-Astari", "gitlab": "", "discord": "", "slack": "", @@ -29,5 +29,5 @@ "phone": "", "address": "", "skype": "", - "website": "" + "website": "https://LokiAstari.com" } diff --git a/content/_index.md b/content/_index.md index adfcf8fa..8169b25a 100755 --- a/content/_index.md +++ b/content/_index.md @@ -1,22 +1,22 @@ --- banner: - title: Welcome **!** - title_small: "to John Bravo's Blog" - content: Are Developer and recently started your own business Already made website to ensure presence wants to develop. - image_enable: true + title: Loki Astari **!** + title_small: Thoughts of a former code monkey. + content: Things I think about from time to time! + image_enable: false image: /images/banner-author.png button: - enable: true + enable: false label: Know About Me link: /about rel: "" featured_posts: - enable: true + enable: false title: Featured Posts promotion: - enable: true + enable: false image: /images/promotion.png link: "#" diff --git a/content/about.md b/content/about.md index e7a21351..aa664437 100755 --- a/content/about.md +++ b/content/about.md @@ -1,36 +1,28 @@ --- title: About The Author image: /images/author.png -description: "meta description" +description: "Martin York (Aka: Loki Astari) Bio" layout: about education: - title: Formal Education + title: "University of Manchester" degrees: - - university: "Southeast University" - content: "1985 • 1991 • gravida nibh velvelit auctor alimo quet menean solli" - - university: "Northeast University" - content: "1985 • 1991 • gravida nibh velvelit auctor alimo quet menean solli" - - university: "Easteast University" - content: "1985 • 1991 • gravida nibh velvelit auctor alimo quet menean solli" - - university: "Southeast University" - content: "1985 • 1991 • gravida nibh velvelit auctor alimo quet menean solli" + - university: "PhD" + content: "Compiler optimization techniques for distributed memory multiprocessor architectures”. Ported the SISAL compiler to the 64 processor, distributed memory KSR-1. Added compile time analysis of the interaction of hardware and software memory management for multi-threaded processes in order to provide timely pre-movement of data between processors at run time to avoid processor stalls." + - university: "MSc" + content: "Compiler optimization techniques”. Modified the code generation phase of the SISAL compiler to produce efficient code for multidimensional array access. Extended the code generation phase to handle higher order functions and partial function closures." + - university: "BSc" + content: "1st Class" experience: title: Work Experience list: - - Best Writer Award - - Best New Newel - - Best Book - - Best Article - - Best New Newel - - Best New Newel - - Best Book - - Best Article - - Best New Newel - - Best Book + - Indeed + - Moz + - Microsoft + - Amazon + - Semantic + - Startups --- -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi amet, ultrices scelerisue cras. Tincidunt hendrerit egestas venenatis risus sit nunc. Est esglit non in ipsum lect;aaus adipiscing et enim porttitor. Dui ultrices et volud eetpat nunc, turpis rutrum elit vestibululm ipsum. Arcu fringilla duis vitae mos dsdllis duicras interdum purus cursus massa metus. Acc umsan felaais, egsdvet nisi, viverra turpis fermentum sit suspf bafedfb ndisse fermentum consectetur. Facilisis feugiat trisique orci tempor sed masd fbsssa tristique ultrices sodales. Augue est sapien elementum facilisis. Enim tincidnt cras interdum purus ndisse. morbi quis nunc. - -Et dolor placerat tempus risus nunc urna, nunc a. Mattis viverra ut sapidaaen enim sed tortor. Mattis gravida fusce cras interdum purus cursus massa metus. Acc umsan felaais, eget nisi, viverra turpis fermentum sit suspf bafedfb ndisse. morbi quis nunc, at arcu quam facilisi. In in lacus aliquam dictum sagittis morbi odio. Et magnis cursus sem sed condimentum. Nibh non potenti ac amsdfet Tincidunt hendrerit egestas venenatis risus sit nunc. Est esglit non in ipsuasdm lect;aaus adipiscing et enim porttitor. Dui ultrices et volud eetpat nunc, turpis ndisse. morbi quis nunc, at arcu quam facilisi ndisse. morbi quis nunc, at arcu quam facilisi +Martin's favorite Job was the Director of Engineering at Moz responsible for all the Big-Data teams. In his spare time, Martin enjoys the company of anybody that enjoys beer/wine and talking politics as long as they do not take either too seriously. Martin enjoys skiing and will use up all his holiday in the winter. diff --git a/content/contact.md b/content/contact.md index 370cdb64..b88f39a6 100755 --- a/content/contact.md +++ b/content/contact.md @@ -1,20 +1,21 @@ --- -title: "Let’s, Talk
About You" -description: "meta description" -phone: "+211234565523" -mail: "info@email.com" -location: "9567 Turner Trace Apt. BC C3G8A4" +title: "Martin York (Aka: Loki Astari)" +description: "Thoughts of a former code monkey" +phone: "" +mail: "" +location: "" form_action: "#" layout: "contact" addresses: - icon: FaUserAlt - content: +211234565523 - link: tel:+211234565523 + content: "" + link: "" + tel: "" - icon: FaMapMarkerAlt - content: info@email.com - link: mailto:info@email.com + content: "" + link: "" - icon: FaLocation - content: 9567 Turner Trace Apt. BC C3G8A4 + content: "" draft: false --- diff --git a/content/gdnt-privacypolicy.md b/content/gdnt-privacypolicy.md new file mode 100644 index 00000000..1ea6d41b --- /dev/null +++ b/content/gdnt-privacypolicy.md @@ -0,0 +1,15 @@ +--- +title: "Google Docs Note Taker Chrome Extension Privacy Policy" +image: /images/author.png +description: "Google Docs Note Taker Privacy Policy" +layout: about + +--- + +This extension collects **NO** data about the user. + +All data entered by the user is stored locally in the browser. +No data entered by the user is shared/transmitted by this extension. + +If you have any questions e-mail: Loki.Astari@gmail.com + diff --git a/content/posts/C++WrapperforSocket.md b/content/posts/C++WrapperforSocket.md new file mode 100644 index 00000000..ad3a0155 --- /dev/null +++ b/content/posts/C++WrapperforSocket.md @@ -0,0 +1,135 @@ +--- +layout: post +title: "C++ Wrapper for Socket" +date: 2016-05-26T21:13:39-0700 +author: Loki Astari (C)2016 +comments: true +categories: ["C++", "Sockets", "C++-By-Example", "Coding"] +series: Sockets +tags: Sockets +sharing: true +footer: true +subtitle: So you want to learn C++ +description: Socket wrappers in C++ +image: /images/post/post-5.png +imageInfo: + original: https://unsplash.com/photos/W-oqNwbmin0 + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Oscar Nilsson + AttributionLink: https://unsplash.com/@oscrse +featured: true +draft: false +disqusId: "http://lokiastari.com/blog/2016/05/26/c-plus-plus-wrapper-for-socket/" +--- +The last two articles examined the "C Socket" interface that is provided by OS. In this article I wrap this functionality in a very simple C++ class to provide guaranteed closing and apply a consistent exception strategy. The first step is to rewrite the client/server code with all the low level socket code removed. This will help identify the interface that the wrapper class needs to implement. + +The client code becomes really trivial. Create a `ConnectSocket` specifying host and a port. Then use the `putMessage()` and `getMessage()` to communicate with the server. Note: I am continuing to use the trivial protocol that was defined in the last article: `putMessage()` writes a string to the socket then closes the connection; `getMessage()` reads a socket until it is closed by the other end (I will cover more sophisticated protocols in a subsequent article). + +[client.cpp](https://github.com/Loki-Astari/Examples/blob/master/Version2/client.cpp) +```c +ConnectSocket connect("localhost", 8080); // Connect to a server +ProtocolSimple connectSimple(connect); // Knows how to send/recv a message over a socket +connectSimple.sendMessage("", "A test message going to the server"); + +std::string message; +connectSimple.recvMessage(message); +std::cout << message << "\n"; +``` + + +For the server end this nearly as trivial as the client. Create a `ServerSocket` and wait for incoming connections from clients. When we get a connection we return a `SocketData` object. The reason for returning a new Socket like object is that this mimics the behavior of the underlying `::accept()` call which opens a new port for the client to interact with the server on. The additional benefit of separating this from the `ServerSocket` is that a subsequent version may allow multiple connections and we want to be able to interact with each connection independently without sharing state, potentially across threads, so modelling it with an object makes sense in an OO world. + +[server.cpp](https://github.com/Loki-Astari/Examples/blob/master/Version2/server.cpp) +```c +ServerSocket server(8080); // Create a lisening connection +while(true) +{ + DataSocket accept = server.accept(); // Wait for a clinet to connect + ProtocolSimple acceptSimple(accept); // Knows how to send/recv a message over a socket + + std::string message; + acceptSimple.recvMessage(message); + std::cout << message << "\n"; + + acceptSimple.sendMessage("", "OK"); +} +``` + +Surprisingly this actually gives us three types of socket interface (not the two most people expect). + +* The ServerSocket class has no ability to read/write just accept connections +* The ConnectSocket class connects and can be used to read/write +* The DataSocket class is an already connected socket that can be used to read/write + +Since a socket is a resource that we don't want duplicated. So this is a resource that can be moved but not copied. + +This lets me to define a very simple interface like this: + +[Socket.h](https://github.com/Loki-Astari/Examples/blob/master/Version2/Socket.h) +```c +// An RAII base class for handling sockets. +// Socket is movable but not copyable. +class BaseSocket +{ + int socketId; + protected: + // Designed to be a base class not used used directly. + BaseSocket(int socketId); + int getSocketId() const {return socketId;} + public: + ~BaseSocket(); + + // Moveable but not Copyable + BaseSocket(BaseSocket&& move) noexcept; + BaseSocket& operator=(BaseSocket&& move) noexcept; + void swap(BaseSocket& other) noexcept; + BaseSocket(BaseSocket const&) = delete; + BaseSocket& operator=(BaseSocket const&) = delete; + + // User can manually call close + void close(); +}; + +// A class that can read/write to a socket +class DataSocket: public BaseSocket +{ + public: + DataSocket(int socketId); + + bool getMessage(std::string& message); + void putMessage(std::string const& message); + void putMessageClose(); +}; + +// A class the conects to a remote machine +// Allows read/write accesses to the remote machine +class ConnectSocket: public DataSocket +{ + public: + ConnectSocket(std::string const& host, int port); +}; + +// A server socket that listens on a port for a connection +class ServerSocket: public BaseSocket +{ + public: + ServerSocket(int port); + + // An accepts waits for a connection and returns a socket + // object that can be used by the client for communication + DataSocket accept(); +}; +``` +Taking the existing code and wrapping this interface around it becomes trivial. The code full code is provided [here](https://github.com/Loki-Astari/Examples/tree/master/Version2). + +In the previous article I talked about the different types of errors that could be generated by read/write. In the following code I take this a step further. Since the code is wrapped inside a class and thus can control the socket resources more cleanly it feels more natural to use exceptions rather than error codes, consequentially error codes are not leaked across any public API boundary. + +1. domain_error + * This is caused by an error that theoretically can not happen (since we have full control of the class). If this type of error occurs there is a bug in the socket code or there has been massive data corruption. Consequently you should not be trying to catch these type of exception as there is a fundamental bug in the code. It is better to let the application exit as it is likely there is substantial corruption of any data. +1. logic_error + * This is caused by an error that theoretically can not happen if the class is used correctly. This means that calling code has some form of logic error. It is caused by calling any method on a socket object that was previously closed or moved. Again this type of error should not be caught (but can be). You should try and remove all potential for this type of error by good unit tests. +1. runtime_error: + * This is caused by an unlikely situation that can not be handled by the Socket code. This type of error requires a broader context to be resolved. As result the socket code will throw an exception that the user can catch and potentially correct from. + + diff --git a/content/posts/CommonMistakes.md b/content/posts/CommonMistakes.md new file mode 100644 index 00000000..50dbb61f --- /dev/null +++ b/content/posts/CommonMistakes.md @@ -0,0 +1,117 @@ +--- +layout: post +title: "Common Mistakes" +date: 2013-11-18T08:58:28-0800 +author: Loki Astari, (C)2013 +comments: true +categories: ["C++", "So-You-Want-To-Learn-C++", "Coding"] +series: So-You-Want-To-Learn-C++ +tags: So-You-Want-To-Learn-C++ +sharing: true +footer: true +subtitle: So you want to learn C++ +description: C++ for beginners. Part 2 Common Mistakes +image: /images/post/post-4.png +imageInfo: + original: https://unsplash.com/photos/wX2L8L-fGeA + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Roman Synkevych + AttributionLink: https://unsplash.com/@synkevych +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2013/11/18/so-you-want-to-learn-c-plus-plus-part-2/" +--- + +### 1: using namespace + +Every new developer that comes to C++ always starts writing code like this: + +myfirstprog.cpp +```c +#include + +using namespace std; +``` + +It seems reasonable and every book on learning C++ out there perpetrates the same mistake. The problem is the " **using namespace std;** ". On programs that are only 10 lines long (like in most books) it does not cause any problems. But as soon as your code strays to any meaningful size then it starts to become an issue. The problem with teaching new developers this technique is that they are not aware of the problems it causes and so it becomes a habit for all code they write. Break this habit **now** before you start doing it without thinking at the top of every source file you write. + +So what are the actual issues? Please read this article: [Why is “using namespace std;” considered bad practice?](https://stackoverflow.com/q/1452721/14065) and the [best Answer](https://stackoverflow.com/a/1453605/14065) that explains what the problem is in detail. + +We call this problem namespace pollution. What the `using` clause is doing is pulling everything from the named namespace into the current namespace; this will cause issues if there is already code in the current namespace. Doing this in your source file is bad enough but even worse is doing this in your header file. The problem with doing it in a header file is that you pollute the namespace for every source file that includes your header file. If the user of the header file is not aware of this pollution then trying to track down a suddenly new issue becomes really very hard. + +But not doing this is causing my much more typing! + +toomuch.cpp +```c +#include +int main() +{ + cout << "Hello World\n"; + + // Now looks much longer + std::cout << "Hello World\n"; +} +``` + +If you think adding `std::` as a prefix to anything in the standard namespace is a bother (then you need another language); there is a solution. Only pull into the current namespace what you actually need. And then try and restrict the scope so it is tight as possible; + +short.cpp +```c +#include +int main() +{ + using std::cout; + // The using clause is scoped and thus cout is only in the global namespace for + // the scope of the main() function. + cout << "Hello Workld\n"; +} +``` + +An additional technique to shorten namespace prefixes are namespace alias. These are very useful when things are nested inside multiple namespaces' (or have very long unhelpful names) + +alias.cpp +```c +#include + +// Here we define bnu as an alias too: boost::numeric::ublas +// We can use either as the prefix to things in the that namespace; +namespace bnu = boost::numeric::ublas; + +bnu::vector data1; +boost::numeric::ublas::vector data2; +``` + +### 2: Prefixing identifiers with '_' +A lot of developers new to C++ try to learn by browsing the standard libraries and getting there habits from things done there or bring conventions from their current favorite languages into there C++ code. One of the things they ultimately pick up on is using '_' as a prefix for identifiers. + +Though technically not wrong in all situations the actual rules on using the '_' as an identifier prefix are non trivial. Thus making it a habit will eventually get you burnt. The issue is that most identifiers that have prefix '_' are reserved for use by the implementation, thus the compiler/linker may potentially do special things with them. You can read up on the issue here: [What are the rules about using an underscore in a C++ identifier?](https://stackoverflow.com/q/228783/14065). + +### 3: void main() +There are only two valid declarations from main in C++ + +main.cpp +```c +// Version 1: You don't care about command line parameters. +int main() +{ +} + +// Version 2: You do care about command line parameters. +int main(int argc, char* argv[]) +{ + // Note: The parameters argc and argv are not actually required as a name. + // But they are so commonly defined that way that using any other + // names would cause experienced developers to do a double take. + // It is best to just stick with the convention. +} + +// Version 2a: You do care about command line parameters. +#include +int main(int argc, char* argv[]) +{ + // If you want to convert all the command line parameters to strings. + // This simple trick can be useful: + std::vector args(argv, argv+argc); +} +``` diff --git a/content/posts/ControlFlow.md b/content/posts/ControlFlow.md new file mode 100644 index 00000000..0f090bd6 --- /dev/null +++ b/content/posts/ControlFlow.md @@ -0,0 +1,226 @@ +--- +layout: post +title: "Control Flow" +date: 2013-12-02T12:00:11-0800 +author: Loki Astari, (C)2013 +comments: true +categories: ["C++", "So-You-Want-To-Learn-C++", "Coding"] +series: So-You-Want-To-Learn-C++ +tags: So-You-Want-To-Learn-C++ +sharing: true +footer: true +subtitle: So you want to learn C++ +description: C++ for beginners. Part 5 Control Flow. So far we have demonstrated basic programs that just do a single task without making any decisions. Most (all but the most trivial) programming languages provide constructs for decision making (Conditional Branching). +image: /images/post/post-8.png +imageInfo: + original: https://unsplash.com/photos/oSvR0wGYUBs + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Matthew Brodeur + AttributionLink: https://unsplash.com/@mrbrodeur +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2013/12/02/so-you-want-to-learn-c-plus-plus-part-5/" +--- + +So far we have demonstrated basic programs that just do a single task without making any decisions. Most (all but the most trivial) programming languages provide constructs for decision making (Conditional Branching). + +C++ provides two forms of branching. The **"If Statement"** and the **"Switch Statement"** . + +Note: Looping is also a form of branching. The looping concept is extensive enough that we will deal with looping separately in its own article. + +### If Statement + +The **"If Statement"** allows code to be executed when a certain condition is fulfilled and optionally an alternative piece of code otherwise. + +ifstatement.cpp +```c +// First versin of "If Statement" +// Execute code if is true. +// +if () +{ + +} + + +// Second version of "If Statement" +// Execute code1 if is true or code2 if is false +// +if () +{ + +} +else +{ + +} +``` + +The standard comparison operators that you find in most languages can be used. These operators are defined for all the built-in types. On user defined types in the standard library they are defined in ways that makes their usage obvious. When you define these for your user defined types you should also make sure that they behave in the logical manner described below; the language does not enforce this, **BUT** if you don't follow this suggestion your types will scare people and they will not be used, so follow the expected behavior. + +Standard Comparison Operators +``` +/* +| Operator | Usage | Result Type | Meaning | +| ----------|---------|-------------|-------------------------------------------------------------------| +| ! | !A | bool | Not A. If A is true then false, if A is false then true. | +| | | | If A us not a bool type it is converted (see below) | +| == | A == B | bool | true if A and B logically equivalent, otherwise false. | +| != | A != B | bool | Should mean !(A == B) | +| < | A < B | bool | true if A is logically less than B. | +| <= | A <= B | bool | true if A is logically less than or equal to B. | +| > | A > B | bool | true if A is logically greater than B. | +| >= | a >= B | bool | true if A is logically greater than or equal to B. | +| && | A && B | bool | true if A is true **AND** B is true. | +| | | | If the expressions A or B are not actually bool then | +| | | | it is converted (see below). Also worth noting is that | +| | | | if A is **false** then the expression for B is not evaluated. | +| | | | This is known as a shortcut operator we will describe this later. | +| || | A || B | bool | true if A is true **OR** B is true. | +| | | | If the expressions A or B are not actually a bool then | +| | | | it is converted (see below). Also worth noting is that | +| | | | if A is **true** then the expression for B is not evaluated. | +| | | | This is known as a shortcut operator we will describe this later. | +|-----------|---------|-------------|-------------------------------------------------------------------| +*/ +``` + +If the expression you use in <Condition> does not actually result in a bool value the compiler will insert a conversion that will result in a bool (true/false) value. If no conversion is possible it results in a compile time error. + +Type conversion +``` +/* +| Type | false | true | Notes | +|------------------|------------|-----------------|-----------------------------------------------------| +| bool | false | true | Should be obvious: No actual conversion used. | +| Integers | 0 | (anything else) | Integer shorthand for (char/short/int/long) | +| Pointers | NULL | (anything else) | Will discuss pointers in detail later. | +| User Define Type | ? | ? | If a cast operator to bool/Integer/pointer exists | +| | | | this will be used. | +|------------------|------------|-----------------|-----------------------------------------------------| +*/ +``` + +An example of using an **If Statement**: + +itest.cpp +```c +#include +#include + +int main() +{ + std::string name; + std::cout << "Please enter your name\n"; + std::cin >> name; + + if (name == "Loki") + { + std::cout << "Hello Admin\n"; + } + else + { + std::cout << "Hello Muggle\n"; + } + + int value; + std::cin >> value; + std::cout << "Please enter a non zero integer value\n"; + if (value) // integer value converted to bool + { + std::cout << "You got it correct. Must use a non zero value.\n"; + } +} +``` + +### Switch Statement + +The **"Switch Statement"** is an alternative to the **"If Statement"**. Prefer the switch when you have lots of options derived from the same expression. Unlike other high level language C++ can only use **Integer** types in a switch statement; thus in all `Case <Value> the <Value> must be an integer **literal** value. + +switch.cpp +```c +switch() +{ + case : + { + + break; + } + case : + { + + break; + } + case : + { + + break; + } + default: + { + + break + } +} +// +// +// Equivalent "If Statement" + +int test = ; +if ( == test) +{ + +} +else +{ + if ( == test) + { + + } + else + { + if ( == test) + { + + } + else + { + + } + } +} +``` + +If you use a non Integer expression in the switch statement the compiler will try and convert the value to an integer. If this is not possible it generates a compile time error. + +switch.cpp +```c + #include + + int main() + { + int value; + std::cout << "Input a value between 0 and 5\n"; + std::cin >> value; + + switch(value) + { + case 0: {std::cout << "You used zero\n"; break;} + case 1: {std::cout << "You used one\n"; break;} + case 2: {std::cout << "You used two\n"; break;} + case 3: {std::cout << "You used three\n"; break;} + case 4: {std::cout << "You used four\n"; break;} + case 5: {std::cout << "You used five\n"; break;} + default: {std::cout << "You failed to follow instructions\n";break;} + } + } +``` + +Note I: The language does not require you to use a **Break Statement** in each block. **BUT** you should and compilers will warn you when you don't. +Note II: You should always use a **Default Statement** . If the value does not hit a value specified in a **Case Statement** then the **Default Statement** is used; If the **Default Statement** is not defined in this situation it results in undefined behavior. To avoid problems you should always define the **Default Statement**, even if all this does is generate an error. This will avoid maintenance issues down the road. + + + + + diff --git a/content/posts/Functions.md b/content/posts/Functions.md new file mode 100644 index 00000000..36ec6b78 --- /dev/null +++ b/content/posts/Functions.md @@ -0,0 +1,179 @@ +--- +layout: post +title: "Functions" +date: 2013-11-24T09:22:04-0800 +author: Loki Astari, (C)2013 +comments: true +categories: ["C++", "So-You-Want-To-Learn-C++", "Coding"] +series: So-You-Want-To-Learn-C++ +tags: So-You-Want-To-Learn-C++ +sharing: true +footer: true +subtitle: So you want to learn C++ +description: C++ for beginners. Part 4 Functions. All C++ applications must have at least one function; this is called `main()`. Additionally, you can have user defined functions that encapsulate individual tasks, thus allowing the code to be cleaner and easier to read. Therefore, this is a useful feature if you repeat the same task many time with only slight variations. +image: /images/post/post-6.png +imageInfo: + original: https://unsplash.com/photos/Bj6ENZDMSDY + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Ben Griffiths + AttributionLink: https://unsplash.com/@benofthenorth +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2013/11/24/so-you-want-to-learn-c-plus-plus-part-4/" +--- + +### Usage +All C++ applications must have at least one function; this is called `main()`. Additionally, you can have user defined functions that encapsulate individual tasks, thus allowing the code to be cleaner and easier to read. Therefore, this is a useful feature if you repeat the same task many time with only slight variations: + +function1.cpp +```c +#include +#include + +int main(int argc, char* argv[]) +{ + std::cout << "What is your first name?\n"; + std::string firstName; + std::cin >> firstName; + + std::cout << "What is your second name?\n"; + std::string secondName; + std::cin >> secondName; + + std::cout << "What is your Mother's name?\n"; + std::string motherName; + std::cin >> motherName; + + std::cout << "What is your Father's name?\n"; + std::string fatherName; + std::cin >> fatherName; +} +``` + +It is easy to spot the obvious repetition here. We can simplify this code by using a function that does all the common work. Anything that is unique we can pass as parameters to the function. + +function2.cpp +```c +#include +#include + +std::string getNameFor(std::string who) +{ + std::cout << "What is your " << who << " name?\n"; + std::string result; + std::cin >> result; + return result; +} + +int main(int argc, char* argv[]) +{ + std::string firstName = getNameFor("first"); + std::string secondName = getNameFor("second"); + std::string motherName = getNameFor("Mother's"); + std::string fatherName = getNameFor("Father's"); +} +``` + +### Definition +OK. We have seen an example but what is the exact format of a function + +function3.cpp +```c +// A function definition is very simple + () +{ + +} + +// ReturnType: This is the name of any type (built in or user defined) +// At the end of function you must have a statement +// that returns an object of this type. +// +// FunctionName: A unique name that identifies the function. +// +// OptionalArgumentList: This is either empty. +// Or a comma separated list of parameters. +// Because C++ is strongly typed each parameter is defined +// with both a type and a name. +// +// OptionalCode: We will be discussing this in more detail throught +// these articles. But the new statement to learn is +// `return `. This is the value returned by the +// function to the original caller. +// +// Value: Notice that above I use the term `Value` and not object. +// A `Value` here can be an explicit object or the result +// of evaluating an expression (temporary object). Note +// one type of expression is a function call. +// +// return "An explicit String Object"; +// +// return theResultOfAFunctionCall("Get A Result"); +``` + +If a function has `void` return type then you don't need to **Return Statement**. With any other return type your function must exit by using a **Return Statement**. The **Return Statement** determines the value returned to the caller from the function. The one exception to this rule (and their has to be an exception to make it a rule) is `int main()`. If you don't explicitly have a **Return Statement** int `int main()` the compiler will plant `return 0;` for you. + + +### Forward Declaration + +One thing to note about a function is that you can not use it before a declaration. We rewrite the original example above as: + +function4.cpp +```c +#include +#include + +int main(int argc, char* argv[]) +{ + std::string firstName = getNameFor("first"); + std::string secondName = getNameFor("second"); + std::string motherName = getNameFor("Mother's"); + std::string fatherName = getNameFor("Father's"); +} + +std::string getNameFor(std::string who) +{ + std::cout << "What is your " << who << " name?\n"; + std::string result; + std::cin >> result; + return result; +} +``` + +The only difference from above here is that I have moved the `main()` function before the `getNameFor()` function. This will generate a compilation error as you are using the function `getNameFor()` before a declaration. This may seem a potential problem but it is a deliberate technique that makes sure you spell things correctly before use. In the above situation the only change you need to make is a forward declaration. This allows you to declare a function before you define it. The utility of this will become clear when we start defining modules. + +function5.cpp +```c +#include +#include + +// Add a forward declaration +extern std::string getNameFor(std::string who); + +// A forward declaration is basically a function declaration without a body. +// Add an extern prefix and a semicolon on the end (the rest you should copy +// and paste from the function definition). +// +// +// Note: For the languages lawyers who want to complain about the extern. +// Just hold your horses we will get to the intricacies in due course; +// this is only lesson 4. + +int main(int argc, char* argv[]) +{ + std::string firstName = getNameFor("first"); + std::string secondName = getNameFor("second"); + std::string motherName = getNameFor("Mother's"); + std::string fatherName = getNameFor("Father's"); +} + +std::string getNameFor(std::string who) +{ + std::cout << "What is your " << who << " name?\n"; + std::string result; + std::cin >> result; + return result; +} +``` + diff --git a/content/posts/HelloWorld.md b/content/posts/HelloWorld.md new file mode 100644 index 00000000..8e6dd1e0 --- /dev/null +++ b/content/posts/HelloWorld.md @@ -0,0 +1,85 @@ +--- +layout: post +title: "Hello World" +date: 2013-11-12T07:59:11-0800 +author: Loki Astari, (C)2012 +comments: true +categories: ["C++", "So-You-Want-To-Learn-C++", "Coding"] +series: So-You-Want-To-Learn-C++ +tags: So-You-Want-To-Learn-C++ +sharing: true +footer: true +subtitle: So you want to learn C++ +description: C++ for beginners. Part 1 Hello World. I keep trying to think about something big and interesting to write about. But that is just not working. All my time is spent trying to think of the blockbuster idea; which just gets in the way of actually writing. So lets start with the small things. If I can get into the habit of writing something a couple of times a week. Then maybe we can work up to interesting stuff. +image: /images/post/post-2.png +imageInfo: + original: https://unsplash.com/photos/uyfohHiTxho + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: ThisisEngineering RAEng + AttributionLink: https://unsplash.com/@thisisengineering +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2013/11/12/want-to-set-up-wordpress-to-write-about-programming/" +--- +This is the first article in the series +OK. Lets do this. + +I keep trying to think about something big and interesting to write about. But that is just not working. All my time is spent trying to think of the blockbuster idea; which just gets in the way of actually writing. So lets start with the small things. If I can get into the habit of writing something a couple of times a week. Then maybe we can work up to interesting stuff. + +Step one; write about something I know. C++; we now start the "So you want to learn C++" series of posts. + +I am going to assume two things. + +* You know how to use the compiler +* That you have some basic programming experience C/Java/C#/Perl/PHP (nearly anything) +So you understand the basics of program but are unfamiliar with C++ + +First thing everybody needs is to get something working; here is the classic "Hello World" in C++ + +helloworld.cpp +```c +#include + +int main() +{ + std::cout << "Hello World\n"; +} +``` + +The next step is to accepts user input and generates a response based on that input. Lets move on to the not quite as classic "Hi There Bob" :-) + +hitherebob.cpp +```c +#include +#include + +int main() +{ + std::cout << "Hi there what's your name?\n"; + + std::string line; + std::getline(std::cin, line); + + std::cout << "It was good to meet you " << line << "\n"; +} +``` + +The above code is relatively simple and only a few things to note: + +* `#include ` +Imports the standard input and output facilities so you can print messages to the user and read user input. + + `std::cin` +Is the standard input stream. From this you can read user input. + + `std::cout` +Is the standard output stream. You can print text to the user console. +* `#include ` +Imports the standard string handling function. Most importantly it imports the type `std::string`. + + `std::string` +This is one of the standard types and holds strings (a list of characters). We will go over types (and variables) in a lot more details in subsequent articles. But for just accept that `line` is a variable (of type std::string) used to hold a line of user input. + + `std::getline()` +This is a function that reads a line of text from a `std::istream` into a `std::string`. In this case we use `std::cin` as the input stream (it is a specialization of a std::istream and can thus be used as the input). Thus we read `a line` of input from the user. + + + +There are a lot of other concepts encapsulated above that I don't want to get into quite yet. But don't worry I will cover them all. diff --git a/content/posts/InterviewsProcesses.md b/content/posts/InterviewsProcesses.md new file mode 100644 index 00000000..b7375a91 --- /dev/null +++ b/content/posts/InterviewsProcesses.md @@ -0,0 +1,75 @@ +--- +layout: post +title: "Interviews Processes" +author: Loki Astari, (C)2011 +date: 2011-10-21T20:01:23-0800 +comments: true +categories: ["Interviews", "Work"] +sharing: true +footer: true +description: One of the things the most non-programmers are surprised about is the severity of programming interviews. So why are they so intense? +image: /images/post/post-1.png +imageInfo: + original: https://unsplash.com/photos/g29arbbvPjo + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Possessed Photography + AttributionLink: https://unsplash.com/@possessedphotography +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2011/10/21/interviews-processes/" +--- + +We ([Moz.com](https://Moz.com)) have been doing a lot of interviews for new engineers lately. I have been asked to help out trying to find the great new team members from the hordes of applicants (luckily we have a great team pre-screening applicants before they get to engineers (thanks you guys). + +One of the things the most non-programmers are surprised about is the severity of programming interviews. + +An on-site interview (after you have passed all the phone screens) consists of seeing between six and eight people (depending on company); this is going to take a full day and you will be utterly exhausted by the end. +But why are "Software Engineer" interviews so exhaustive? [I think this sums it up](https://programmers.stackexchange.com/questions/47778/why-are-sw-engineering-interviews-disproportionately-difficult-vs-research-inte/47784#47784) + +### What types of interview do I do? +My field of expertise is technical (not the "[touchy feely](https://blog.sironaconsulting.com/sironasays/2011/03/is-your-hr-manager-more-miss-marple-or-hr-20-fun-infographic.html)" HR stuff or ["can you work as a team"](https://imgur.com/gallery/4D6wd) management stuff). As a result I basically stick to one type of interview with two sub variations: + +* Can you think on your feet + * Do you know the basics (algorithms/data structures/Big O/CS theory) + * Design an interacting systems at a high level thinking about the interaction + +I have not done phone screens in a while (this is a different skill set). I have no problem with doing them I just think other people are better than me at this kind of interview. Personally I think it is really hard to get technical information over the phone (even if you use one of those collaborative online writing tools) I would rather render my ~~judgement~~ opinion on the candidate based on talking to them face to face. + +### So how do you get good information from a candidate? +Heck if I know. During the interview it is a lot of gut feeling and pressing the candidate to expresses themselves and provide feedback on what they are thinking. **Please**; if you are a candidate explain what you are doing*, I want to know how you got the solution more than I want to know the solution you provided. + + When asking a candidate about the basics, their inability to answer the question does not really tell me much (you may just not have used that technique in a while or missed that one class at college) so don't worry too much I will find something you can answer; but note, your ability to answer the question only tells me a little more (not much). + +So when you do answer I want to know **why** you are using a particular technique, are there **any other techniques** and if so **why** use your initial choice over another ('it would take too much wide board space' is a great answer as it means you understand the alternative is very complex (but now I am going to ask you to do it :-) )) + +Unless the company is looking for a skill in a particular language then generally my interview question are language agnostic and I will let the candidate use the language that they are most comfortable with on a white board. Though the language is not important to me, **the usage of the language is important** (you better not leak memory in C/C++, you better not build strings with java.lang.string in Java, you better know how to use regular expression matching in Perl, you should understand how to use the fundamental list/dictionary types in python etc.) and most importantly **you better be able to use fluently any language you list on your resume** (if you are just learning/fiddling with a language make that clear). + +Notice I have not said anything about syntax. Personally I think this is irrelevant in an interview situation. I mean I get code wrong all the time when I write it (that's why I have the compiler as my first line of defense and unit tests as the second). As long as I can see what you are logically trying to achieve I will not complain about missing semi-colon. + +### The dos and don'ts for a candidate +This article has a [basic guide on general etiquette](https://jobs.aol.com/articles/2011/09/12/tips-for-interviews-interviewing-etiquette-infographic/) for interviews. While this one has some more specific guidance on what to expect at [programming interview](https://programmers.stackexchange.com/questions/80065/preparing-for-interviews/80073#80073). + +Both mention to study the company; when I was younger I always though this was silly (I was naive once a long time ago) as I did not think it would help me do my job, but I accepted the advice of my elders and did study the companies before interviews and I must say it always paid off (but never in ways you expect). + +Remember that I only have an hour to try and extract as much information as I can from you so don't go off on wild tangents stick to the point and answer the question I ask. If you can show off quickly then do so but make it quick. You should also note that interviewers generally have their questions arranged in themes, if you can answer the questions quickly he is going to move onto the next part of the same question which extends the question making it harder trying to draw more knowledge from you (can you make that more efficient/ can you see the common pit falls how do you avoid them etc..). + +On the same line don't give the most optimal solution first (unless that is obviously what the interviewer is looking for and you can justify it), a good interviewer is going to walk you up to the optimal solution and see if you know why its the optimal solution (But its also part of the communication I mentioned above, if you explain what you are doing (I will start with a brute force solution) even a bad interviewer should know you have an alternative optimizes solution). + +Don't gloss over the complex bit (unless the interviewer tells you too), this is probably the bit they want you to explain, whatever you don't try BS your answer. The interviewer has probably asked the question a hundred times before he has heard all the good/standard ways of solving the problem (and some more exotic ways), if you don't know just let the interviewer know. + +### The don'ts for a interviewer +I hate interviewers that ask those silly logic problems. They do not tell you anything about a candidates ability to write code or think critically about coding. All it tells you is that they are good a logic problems. + +* Why is a man hole cover round? +* If a man rows a boat at 4 mph downstream on a river traveling 2 mph. He drops his hat overboard but does not notice for an hour. How long does he need to row upstream to meet his hat? +* Russian roulette: I have a six shooter with 2 bullets in consecutive location. I spin the chamber then shoot myself first (it does not go off). I pass the gun to you. Do you spin the chamber before shooting or not? +* You have 1000 bottles of champagne. One bottle is contaminated and drinking from it will cause vomiting in an hour. You have an hour and ten staff to help you. What is the fewest bottles you need to discard to guarantee none of your guests gets poisoned? +* Many more. + +Personally I like the problems and do well at interviews that ask them. But I don't think it tells you anything about me as a software engineer. As a result I don't ask these types of question. + +Other people argue that it shows people that can think critically about problems. Sorry I disagree. It tends to find people that have heard the problem before and these problems turn up on websites all the time. + +### The coding interview +I previously did a second type. Sit the interviewee in front of a laptop and ask them to write code to solve a particular problem. This would involve: user input (from keyboard or file (as user input was involved I would look for error checking, but since a file was involved no error recovery)). I would provide documentation to an existing library to see if they could read and understand it enough to use it. *But this is blog entry for another time. But if you have some hints and comments about please post a comment below*. diff --git a/content/posts/MemoryResizing.md b/content/posts/MemoryResizing.md new file mode 100644 index 00000000..e257aefb --- /dev/null +++ b/content/posts/MemoryResizing.md @@ -0,0 +1,108 @@ +--- +layout: post +title: "Memory Resizing" +date: 2016-03-25T05:53:07-0700 +author: Loki Astari (C)2016 +comments: true +categories: ["C++", "Resource-Management", "C++-By-Example", "Coding"] +sharing: true +footer: true +subtitle: So you want to learn C++ +description: So why is the constant resize factor of the array 1.5 or 2? +image: /images/post/post-2.png +imageInfo: + original: https://unsplash.com/photos/uyfohHiTxho + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: ThisisEngineering RAEng + AttributionLink: https://unsplash.com/@thisisengineering +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2016/03/25/resizemaths/" +--- + +So I never really considered why the resize of vector used a constant expansion of 1.5 or 2 (in some popular implementations). That was until I did my previous article Xseries ["Vector"]({{config.site}}/blog/2016/02/27/vector/) where I concentrated a lot on resource management and did a section on [resizing the vector]({{config.site}}/blog/2016/03/12/vector-resize/). Originally in the code I tried to be clever, a mistake. I used a resize value of 1.62 (an approximation of `Phi`), because I vaguely remembered reading an article that this was the optimum resize factor. When I put this out for code review it was pointed out to me that this value was too large, the optimum value must be less than or equal to `Phi` (1.6180339887) and that exceeding this limit actually made things a lot worse. + +So I had to know why.... + +So the theory goes: You have a memory resource of size `B`. If you resize this resource by a constant factor `r` by re-allocating a new block then releasing the old block. Then if the value of `r` is smaller than or equal to `Phi` you will eventually be able to reuse memory that has previously been released; otherwise the new block of memory being allocated will always be larger than the previously released memory. + +So I thought lets try that: +Test one `r > Phi`: + +``` + B=10 + r=2.0 + + Sum Memory Memory Memory Needed Difference + Released Allocated Next Iteration + Start 0 10 20 20 + Resize 1 10 20 40 30 + Resize 2 30 40 80 50 + Resize 3 70 80 160 90 + Resize 4 150 160 320 170 +``` + +OK. That seems to be holding (at least in the short term). Lo lets try a smaller value. +Test two `r < Phi`: + +``` + B=10 + r=1.5 + + Sum Memory Memory Memory Needed Difference + Released Allocated Next Iteration + Start 0 10 15 15 + Resize 1 10 15 22 12 + Resize 2 25 22 33 8 + Resize 3 47 33 48 1 + Resize 4 80 48 72 -8 // Reuse released memory next iteration +``` + +OK. That also seems to be holding. But can we show that holds for all values of B? Also this is a bit anecdotal can we actually show this relationship actually hold? Time to break out some maths (not math as my American cousins seem to insist on for the shortening of mathematics). + + +So the size `S` of any block after `n` resize operations will be: + + + + +Thus the size of `Released Memory` can be expressed as: + + + +Also the size of the next block will be: + + + +So if the amount of `Released Memory` >= the amount required for the next block, then we can reuse the `Released Memory`. + + + + + + + + + + + + + + + + + + + +This is were my maths broke down. So after talking to some smart people. They noticed that: + + + +We find that the first root of the equation is 1. The second root of the equation depends on `n`, as `n` tends to `infinity` the other root tends towards `Phi`. From this we can infer the following: + + + + +Thus if `r` remains in the above range then the above theory holds. + diff --git a/content/posts/NearlyNewYear_NewResolution.md b/content/posts/NearlyNewYear_NewResolution.md new file mode 100644 index 00000000..b6d29299 --- /dev/null +++ b/content/posts/NearlyNewYear_NewResolution.md @@ -0,0 +1,25 @@ +--- +layout: post +title: "Nearly New Year/New Resolution" +date: 2014-12-06T11:44:00-0800 +author: Loki Astari, (C)2014 +comments: true +categories: ["General"] +description: New Years resolution +image: /images/post/post-1.png +imageInfo: + original: https://unsplash.com/photos/g29arbbvPjo + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Possessed Photography + AttributionLink: https://unsplash.com/@possessedphotography +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2014/12/06/nearly-new-year-slash-new-resolution/" +--- +## New Year/New Resolution +They say you can only get better at something by doing it. + +I want to get better at writing articles about what I do so I better keep trying. Reading the articles I wrote last year (with the hindsight of a year) it seems my pros are a bit dry and laborious. So I am going to try again with an eye on fixing this problem. + +My two main inspirations are colleges who do this rather well. [Kate Mate](https://katemats.com/) a highly talented manager whose opinions I respect and [Rand Fiskin](https://moz.com/rand/) the Wizard of Moz (though I am not sure he uses this tittle anymore). Both are highly respected in their fields and have the ability to write comprehensively and interestingly about subjects. diff --git a/content/posts/Smart-Pointer-Constructors.md b/content/posts/Smart-Pointer-Constructors.md new file mode 100644 index 00000000..bc0cce56 --- /dev/null +++ b/content/posts/Smart-Pointer-Constructors.md @@ -0,0 +1,364 @@ +--- +layout: post +title: "Smart-Pointer - Constructors" +date: 2015-01-23T16:33:14-0800 +author: Loki Astari, (C)2015 +comments: true +categories: ["C++", "Smart-Pointer", "C++-By-Example", "Coding"] +series: Smart-Pointer +tags: Smart-Pointer +sharing: true +footer: true +subtitle: C++ By Example +description: C++ By Example. Part 3 Smart Pointer Constructors. In this article we examine constructors that are often missed or overlooked. This article looks at the use cases for these constructors and explains why the added functionality provides a meaningful addition in relation to smart pointers. +image: /images/post/post-4.png +imageInfo: + original: https://unsplash.com/photos/wX2L8L-fGeA + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Roman Synkevych + AttributionLink: https://unsplash.com/@synkevych +featured: true +draft: false +disqusId: "http://lokiastari.com/blog/2015/01/23/c-plus-plus-by-example-smart-pointer-part-iii/" +--- +In this article we examine constructors that are often missed or overlooked. This article looks at the use cases for these constructors and explains why the added functionality provides a meaningful addition in relation to smart pointers. + +## Default Constructor +Most people remember the default constructor (a zero argument constructor), but every now and then it gets missed. + +The default constructor is useful when the type is used in a context where objects of the type need to be instantiated dynamically by another library (an example is a container resized; when a container is made larger by a resize, new members will need to be constructed, it is the default constructor that will provide these extra instances). + +The default constructor is usually very trivial and thus worth the investment. + +Smart Pointer Default Constructor +```c +namespace ThorsAnvil +{ + template + class UP + { + T* data; + public: + UP() + : data(nullptr) + {} + ..... + }; +} +``` +## The nullptr +In C++11 the `nullptr` was introduced to replace the old broken `NULL` and/or the even more broken `0` for use in contexts where you want a pointer that points at nothing. The `nullptr` is automatically convert to any pointer type or a boolean; but fixed the previous bug (or bad feature) and will not convert to a numeric type. + +nullptr Usage Example +```c +#include +int main() +{ + char* tmp = nullptr; // converts the nullptr (type std::nullptr_t) to char* + std::string* str = nullptr; // hopefully you never do that! but it works. + + bool tst = nullptr; // False. Yes I know it does not look that useful. + // But when you consider all the funny things + // that can happen with templates this can + // be very useful. + + int val = nullptr; // Fails to compile. + int val = NULL; // Pointer assigned to integer value. + // Works just fine. But very rarely was this a useful + // feature (more usually an over-site that was not + // reported by the compiler). +} +``` +The `nullptr` provides some opportunities to make the code shorter/cleaner when initializing smart pointers to be empty. Because we are using explicit one argument constructors the compiler can not convert a `nullptr` into a smart pointer automatically, it must be done explicitly by the developer. + +nullptr failing on Smart Pointer +```c +void workWithSP(ThorsAnvil::UP&& sp) +{ /* STUFF*/ } + +int main() +{ + // This fails to compile. + workWithSP(nullptr); + + // Need to be explicit with smart pointers + workWithSP(ThorsAnvil::UP(nullptr)); +} +``` +This is overly verbose, there is no danger involved in forming a smart pointer around a `nullptr` automatically. Because `nullptr` has its own type `std::nullptr_t` we can add a constructor to explicitly simplify this case, which makes it easier to read. + +Smart Pointer with std::nullptr_t constructor +```c +namespace ThorsAnvil +{ + template + class UP + { + public: + UP(std::nullptr_t) + : data(nullptr) + {} + .... + }; +} +// Now we can simplify our use case +void workWithSP(ThorsAnvil::UP&& sp) +{ /* STUFF*/ } + +int main() +{ + workWithSP(nullptr); + + // Note this also allows: + ThorsAnvil::UP data = nullptr; + // And + data = nullptr; // Note here we have we convert nullptr to + // smart pointer using the one argument + // constructor that binds `nullptr` then + // call the assignment operator. + // + // That seems like a lot extra work. So we + // may as well define the assignment operator + // to specifically user `nullptr`. +} +``` +## Move Semantics +Move semantics were introduced with C++ 11. So though we can not copy the `ThorsAnvil::UP` object it can be moved. The compiler will generate a default move constructor for a class under certain situations; but because we have defined a destructor for `ThorsAnvil::UP` we must manually define the move constructor. + +Move semantics say that the source object may be left in an undefined (but must be valid) state. So the easiest way to implement this is simply to swap the state of the current object with the source object (we know our state is valid so just swap it with the incoming object state (its destructor will then take care of destroying the pointer we are holding)). + +Smart Pointer Move Semantics +```c +namespace ThorsAnvil +{ + template + class UP + { + T* data; + public: + // Swap should always be `noexcept` operation + void swap(UP& src) noexcept + { + std::swap(data, src.data); + } + // It is a good idea to make your move constructor `noexcept` + // In this case it actually makes no difference (because there + // no copy constructor) but to maintain good practice I still + // think it is a good idea to mark it with `noexcept`. + UP(UP&& moving) noexcept + { + moving.swap(*this); + } + UP& operator=(UP&& moving) noexcept + { + moving.swap(*this); + return *this; + } + ..... + }; + template + void swap(UP& lhs, UP& rhs) + { + lhs.swap(rhs); + } +} +``` +## Derived Type Assignment. +Assigning derived class pointers to a base class pointer object is quite common feature in C++. + +Derived Example +```c +class Base +{ + public: + virtual ~Base() {} + virtual void doAction() = 0; +}; +class Derived1: public Base +{ + public: + virtual void doAction() override; +}; +class Derived2: public Base +{ + public: + virtual void doAction() override; +}; +int main(int argc, char* argv[]) +{ + Derived1* action1 = new Derived1; + Derived2* action2 = new Derived2; + + Base* action = (argc == 2) ? action1 : action2; + action->doAction(); +} +``` +If we try the same code with the constructors we currently have we will get compile errors. + +Derived Example with Smart Pointers +```c +int main(int argc, char* argv[]) +{ + ThorsAnvil::UP action1 = new Derived1; + ThorsAnvil::UP action2 = new Derived2; + + ThorsAnvil::UP action = std::move((argc == 2) ? action1 : action2); + action->doAction(); +} +``` +This is because C++ considers `ThorsAnvil::UP`, `ThorsAnvil::UP` and `ThorsAnvil::UP` are three distinct classes that are unrelated. As this kind of pointer usage is rather inherent in how C++ is used the smart pointer needs to be designed for this use case. + +To solve this we need to allow different types of smart pointer be constructed from other types of smart pointer, but only where the inclosed types are related. + +Derived Smart Pointer transfer +```c +namespace ThorsAnvil +{ + template + class UP + { + T* data; + public: + // Release ownership of the pointer. + // Returning the pointer to the caller. + T* release() + { + T* tmp = nullptr; + std::swap(tmp, data); + return tmp; + } + // Note: If you try calling this with a U that is not derived from + // a T then the compiler will generate a compilation error as + // the pointer assignments will not match correctly. + template + UP(UP&& moving) + { + // We can not use swap directly. + // Even though U is derived from T, the reverse is not true. + // So we have put it in a temporary locally first. + + // Note: this is still exception safe. + // The normal constructor will call delete even if it does + // not finish constructing. So if release completes even + // starting the call to the constructor guarantees its safety. + UP tmp(moving.release()); + tmp.swap(*this); + } + template + UP& operator=(UP&& moving) + { + UP tmp(moving.release()); + tmp.swap(*this); + return *this; + } + ..... + }; +} +``` +## Updated Unique Pointer +Combine the constructor/assignment operators discussed in this article with the `ThorsAnvil::UP` that we defined in the first article in the series: [Unique Pointer](https://lokiastari.com/posts/Smart-Pointer-UniquePointer) we obtain the following: + +ThorsAnvil::UP Version 3 +```c +namespace ThorsAnvil +{ + template + class UP + { + T* data; + public: + UP() + : data(nullptr) + {} + // Explicit constructor + explicit UP(T* data) + : data(data) + {} + ~UP() + { + delete data; + } + + // Constructor/Assignment that binds to nullptr + // This makes usage with nullptr cleaner + UP(std::nullptr_t) + : data(nullptr) + {} + UP& operator=(std::nullptr_t) + { + reset(); + return *this; + } + + // Constructor/Assignment that allows move semantics + UP(UP&& moving) noexcept + { + moving.swap(*this); + } + UP& operator=(UP&& moving) noexcept + { + moving.swap(*this); + return *this; + } + + // Constructor/Assignment for use with types derived from T + template + UP(UP&& moving) + { + UP tmp(moving.release()); + tmp.swap(*this); + } + template + UP& operator=(UP&& moving) + { + UP tmp(moving.release()); + tmp.swap(*this); + return *this; + } + + // Remove compiler generated copy semantics. + UP(UP const&) = delete; + UP& operator=(UP const&) = delete; + + // Const correct access owned object + T* operator->() const {return data;} + T& operator*() const {return *data;} + + // Access to smart pointer state + T* get() const {return data;} + explicit operator bool() const {return data;} + + // Modify object state + T* release() noexcept + { + T* result = nullptr; + std::swap(result, data); + return result; + } + void swap(UP& src) noexcept + { + std::swap(data, src.data); + } + void reset() + { + T* tmp = releae(); + delete tmp; + } + }; + template + void swap(UP& lhs, UP& rhs) + { + lhs.swap(rhs); + } +} +``` +## Summary +In the last two articles ([Unique Pointer](https://lokiastari.com/posts/Smart-Pointer-UniquePointer) and [Shared Pointer](https://lokiastari.com/posts/Smart-Pointer-SharedPointer)) we covered some basic mistakes that I have often seen developers make when attempting to creating their own smart pointer. I also introduce four important C++ concepts: + + - [Rule of Three](https://stackoverflow.com/q/4172722/14065) + - [Copy and Swap Idiom](https://stackoverflow.com/q/3279543/14065) + - [Explicit One Argument Constructor](https://stackoverflow.com/a/121163/14065) + - [Try/Catch on Initialization List](https://stackoverflow.com/q/12697625/14065) + +This article I focused on a couple of constructors/assignment operators that can be overlooked overlooked. diff --git a/content/posts/Smart-Pointer-SharedPointer.md b/content/posts/Smart-Pointer-SharedPointer.md new file mode 100644 index 00000000..d8bd2191 --- /dev/null +++ b/content/posts/Smart-Pointer-SharedPointer.md @@ -0,0 +1,312 @@ +--- +layout: post +title: "Smart-Pointer - Shared Pointer" +date: 2015-01-15T08:13:47-0800 +author: Loki Astari, (C)2015 +comments: true +categories: ["C++", "Smart-Pointer", "C++-By-Example", "Coding"] +series: Smart-Pointer +tags: Smart-Pointer +sharing: true +footer: true +subtitle: C++ By Example +description: C++ By Example. Part 2 Shared Pointer. In this article we cover some of the common implementation techniques used for a smart pointer that provides shared ownership of a resource. +image: /images/post/post-3.png +imageInfo: + original: https://unsplash.com/photos/d6dxQwmxV2Q + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Ken Blode + AttributionLink: https://unsplash.com/@benkolde +featured: true +draft: false +disqusId: "http://lokiastari.com/blog/2015/01/15/c-plus-plus-by-example-smart-pointer-part-ii/" +--- +So in [the previous article](https://lokiastari.com/posts/Smart-Pointer-UniquePointer) I covered a basic `unique` pointer where the smart pointer retained sole ownership of the pointer. The other common smart pointer we encounter is the `shared` pointer (SP). In this case the ownership of the pointer is shared across multiple instances of SP and the pointer is only released (deleted) when all SP instances have been destroyed. + +So not only do we have to store the pointer but we need a mechanism for keeping track of all the SP instances that are sharing ownership of the pointer. When the last SP instance is destroyed it also deletes the pointer (The last owner cleans up. A similar principle to the last one to leave the room turns out the lights). + +Shared Pointer contextual destructor +```c +namespace ThorsAnvil +{ + template + class SP + { + T* data; + public: + ~SP() + { + if (amITheLastOwner()) + { + delete data; + } + } + }; +} +``` +There are two major techniques for tracking the shared owners of a pointer: + +
    +
  1. Keep a count:
  2. +
      +
    • When the count is 1 you are the last owner.
    • +
    • This is a very simple and logical technique. You have a shared counter that is incremented/decrement as SP instances take/release ownership of the pointer. The disadvantages are that you need dynamically allocated memory that must be managed and in a threaded environment you need to serialize accesses to counter.
    • +
    +
  3. Use a linked list of the owners:
  4. +
      +
    • When you are the only member of the list you are the last owner.
    • +
    • When a SP instance take/releases ownership of the pointer they are added/removed to/from the linked list. This is slightly more complex as you need to maintain a circular linked list (for O(1)). The advantage is that you do not need to manage any separate memory for the count (A SP instance simply points at the next SP instance in the chain) and in a threaded environment adding/removing a shared pointer need not always be serialized (though you will still need to lock your neighbors to enforce integrity).
    • +
    +
+ +## Shared Count +The easier of the two to implement correctly is the list version. There are no real gotchas (that I have seen). Though people do struggle with insertion and removal of a link from a circular list. I have another article planned for that at some point so I will cover it then. + +The *Shared Count* is basically the technique used by the [`std::shared_ptr`](https://en.cppreference.com/w/cpp/memory/shared_ptr) (though they store slightly more than the count to try and improve efficiency see [`std::make_shared`](https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared)). + +The main mistake I see from beginners is not using dynamically allocated counter (i.e. they keep the counter in the SP object). You **must** dynamically allocate memory for the counter so that it can be shared by all SP instances (you can not tell how many there will be or the order in which they will be deleted). + +You must also serialize access to this counter to make sure that in a threaded environment the count is correctly maintained. In the first version for simplicity I will only consider single threaded environments and thus synchronization is not required. + +First Try +```c +namespace ThorsAnvil +{ + template + class SP + { + T* data; + int* count; + public: + // Remember from ThorsAnvil::UP that the constructor + // needs to be explicit to prevent the compiler creating + // temporary objects on the fly. + explicit SP(T* data) + : data(data) + , count(new int(1)) + {} + ~SP() + { + --(*count); + if (*count == 0) + { + delete data; + } + } + // Remember from ThorsAnvil::UP that we need to make sure we + // obey the rule of three. So we will implement the copy + // constructor and assignment operator. + SP(SP const& copy) + : data(copy.data) + , count(copy.count) + { + ++(*count); + } + SP& operator=(SP const& rhs) + { + // Keep a copy of the old data + T* oldData = data; + int* oldCount = count; + + // now we do an exception safe transfer; + data = rhs.data; + count = rhs.count; + + // Update the counters + ++(*count); + --(*oldCount); + + // Finally delete the old pointer if required. + if (*oldCount == 0) + { + delete oldData; + } + } + // Const correct access owned object + T* operator->() const {return data;} + T& operator*() const {return *data;} + + // Access to smart pointer state + T* get() const {return data;} + explicit operator bool() const {return data;} + }; +} +``` +### Problem 1: Potential Constructor Failure +When a developer (attempts) to create a SP they are handing over ownership of the pointer to the SP instance. Once the constructor starts there is an expectation by the developer that no further checks are needed. But there is a problem with the code as written. + +In C++ memory allocation through new does not fail (unlike C where `malloc()` can return a Null on failure). In C++ a failure to allocate memory via the standard new generates a `std::bad_alloc` exception. Additionally if we throw an exception out of a constructor the destructor will never be called (the destructor is only called on fully formed objects) when the instance's lifespan ends. + +So if an exception is thrown during construction (and thus the destructor will not be called) we must assume responsibility for making sure that pointer is deleted before the exception escapes the constructor, otherwise there will be a resultant leak of the pointer. + +Constructor takes responsibility for pointer +```c +namespace ThorsAnvil +{ + ..... + explicit SP(T* data) + : data(data) + , count(new (std::nothorw) int(1)) // use the no throw version of new. + { + // Check if the pointer correctly allocated + if (count == nullptr) + { + // If we failed then delete the pointer + // and manually throw the exception. + delete data; + throw std::bad_alloc(); + } + } + // or + ..... + explicit SP(T* data) + // The rarely used try/catch for exceptions in argument lists. + try + : data(data) + , count(new int(1)) + {} + catch(...) + { + // If we failed because of an exception + // delete the pointer and rethrow the exception. + delete data; + throw; + } +} +``` +### Problem 2: DRY up the Assignment +Currently the assignment operator is exception safe and conforms to the strong exception guarantee so there is no real problem here. **But** there seems to be a lot of duplicated code in the class. + +Closer look at assignment +```c +namespace ThorsAnvil +{ + ..... + SP& operator=(SP const& rhs) + { + T* oldData = data; + int* oldCount = count; + + data = rhs.data; + count = rhs.count; + ++(*count); + + --(*oldCount); + if (*oldCount == 0) + { + delete oldData; + } + } +} +``` +Two portions of this look like other code pieces of code that have already been written: + +```c + // This looks like the SP copy constructor. + data = rhs.data; + count = rhs.count; + ++(*count); + + // This looks like the SP destructor. + --(*oldCount); + if (*oldCount == 0) + { + delete oldData; + } +``` +This observation is commonly referred to as the **[Copy and Swap Idiom](https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom)**. I will not go through all the details of the transformation here. But we can re-write the assignment operator as: + +Copy and Swap Idiom +```c +SP& operator=(SP const& rhs) +{ + // constructor of tmp handles increment. + SP tmp(rhs); + + std::swap(data, tmp.data); + std::swap(count, tmp.count); + return *this; +} // the destructor of tmp is executed here. + // this handles the decrement and release of the pointer + +// This is usually simplified further into +SP& operator=(SP rhs) // Note implicit copy because of pass by value. +{ + rhs.swap(*this); // swaps moved to swap method. + return *this; +} +``` + +## Fixed First Try +So given the problems described above we can update our implementation to compensate for these issues: + +Fixed First Try +```c +namespace ThorsAnvil +{ + template + class SP + { + T* data; + int* count; + public: + // Explicit constructor + explicit SP(T* data) + try + : data(data) + , count(new int(1)) + {} + catch(...) + { + // If we failed because of an exception + // delete the pointer and rethrow the exception. + delete data; + throw; + } + ~SP() + { + --(*count); + if (*count == 0) + { + delete data; + } + } + SP(SP const& copy) + : data(copy.data) + , count(copy.count) + { + ++(*count); + } + // Use the copy and swap idiom + // It works perfectly for this situation. + SP& operator=(SP rhs) + { + rhs.swap(*this); + return *this; + } + SP& operator=(T* newData) + { + SP tmp(newData); + tmp.swap(*this); + return *this; + } + // Always good to have a swap function + // Make sure it is noexcept + void swap(SP& other) noexcept + { + std::swap(data, other.data); + std::swap(count, other.count); + } + // Const correct access owned object + T* operator->() const {return data;} + T& operator*() const {return *data;} + + // Access to smart pointer state + T* get() const {return data;} + explicit operator bool() const {return data;} + }; +} +``` +## Summary +So in this second post we have looked SP and mentioned the two main implementation techniques commonly used. We specifically looked in detail at some common problems usually overlooked in the counted implementation of SP. In the next article I want to look at a couple of other issues common to both types of smart pointers. diff --git a/content/posts/Smart-Pointer-UniquePointer.md b/content/posts/Smart-Pointer-UniquePointer.md new file mode 100644 index 00000000..54edbd37 --- /dev/null +++ b/content/posts/Smart-Pointer-UniquePointer.md @@ -0,0 +1,306 @@ +--- +layout: post +title: "Smart-Pointer - Unique Pointer" +date: 2014-12-30T18:41:42-0800 +author: Loki Astari, (C)2014 +comments: true +categories: ["C++", "Smart-Pointer", "C++-By-Example", "Coding"] +series: Smart-Pointer +tags: Smart-Pointer +footer: true +sharing: true +subtitle: C++ By Example +description: C++ By Example. Part 1 Unique Pointer. It seems that it is a write of passage to implement your own version of a smart pointer. This article examines some of the common mistakes made by developers developing their own smart pointers. +image: /images/post/post-2.png +imageInfo: + original: https://unsplash.com/photos/uyfohHiTxho + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: ThisisEngineering RAEng + AttributionLink: https://unsplash.com/@thisisengineering +featured: true +draft: false +disqusId: "http://lokiastari.com/blog/2014/12/30/c-plus-plus-by-example-smart-pointer/" +--- +On [codereview.stackexchange.com](https://codereview.stackexchange.com) in the C++ tag it seems that it is a write of passage to implement your own version of a smart pointer. A quick search brings up the following: + +* 02/Sep/2011 - [shared_ptr implementation](https://codereview.stackexchange.com/q/4550/507) +* 26/Nov/2011 - [Shared Pointer implementation](https://codereview.stackexchange.com/q/6320/507) +* 18/Apr/2013 - [Request for review: reference counting smart pointer](https://codereview.stackexchange.com/q/25214/507) +* 20/May/2013 - [Efficient smart pointer implementation in C++](https://codereview.stackexchange.com/q/26353/507) +* 11/Aug/2013 - [C++98 Unique Pointer Implementation](https://codereview.stackexchange.com/q/29629/507) +* 14/Aug/2013 - [I wrote a class to implement auto_ptr](https://codereview.stackexchange.com/q/29734/507) +* 28/Aug/2013 - [yet another shared pointer](https://codereview.stackexchange.com/q/30398/507) +* 04/Mar/2014 - [Smart pointer implementation](https://codereview.stackexchange.com/q/43472/507) +* 13/May/2014 - [One more shared pointer](https://codereview.stackexchange.com/q/49672/507) +* 14/Jun/2014 - [Is this a meaningful Intrusive Pointer Class?](https://codereview.stackexchange.com/q/54220/507) +* 04/Aug/2014 - [Simple shared pointer](https://codereview.stackexchange.com/q/59004/507) +* 08/Oct/2014 - [Smart but simple pointers](https://codereview.stackexchange.com/q/65127/507) +* 15/Nov/2014 - [Simple auto_ptr](https://codereview.stackexchange.com/q/69943/507) +* 19/Dec/2014 - [Yet another smart pointer implementation for learning](https://codereview.stackexchange.com/q/74166/507) + +Writing you own implementation of a smart pointer is a bad idea (IMO). The standardization and testing of smart pointers was a nine year process through [boost](https://www.boost.org/), with [boost::shared_ptr](https://www.boost.org/doc/libs/1_57_0/libs/smart_ptr/shared_ptr.htm) and [boost::scoped_ptr](https://www.boost.org/doc/libs/1_57_0/libs/smart_ptr/scoped_ptr.htm), finally resulting in the standardized versions being released in C++11: [std::shared_ptr](https://en.cppreference.com/w/cpp/memory/shared_ptr) and [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr). + +I would even say that I dislike the smart pointer as a learning device; it seems like a very simple project for a newbie, but in reality (as indicated by the nine year standardization processes) getting it working correctly in all contexts is rather a complex endeavor. + +But because it is such a frequent request for review; I want to take a look at smart pointers as a teaching exercise. In the next couple of articles I will step through the processes of building a smart pointer and look at some of the common mistakes that I see (and probably make a few as I go). + +### Warning: +This article is not for absolute beginners. I assume you already know the basics of C++. + +## First Bash +So lets get started. The two most common smart pointers are `unique` and `shared`. So lets start with the one that seems the simplest (`unique`)and see where we go. + +It would seem that we could bash out a quick unique pointer like this: + +ThorsAnvil::UP Version 1 +```c +namespace ThorsAnvil +{ + template + class UP + { + T* data; + public: + UP(T* data) + : data(data) + {} + ~UP() + { + delete data; + } + T* operator->() {return data;} + T& operator*() {return *data;} + T* release() + { + T* result = nullptr; + std::swap(result, data); + return result; + } + // So it can be used in conditional expression + operator bool() {return data;} + }; +} +``` +### Problem 1: Rule of Three Violation +The first problem here is that we are not obeying the "[rule of three](https://stackoverflow.com/q/4172722/14065)". Since we have a destructor that does memory management we should also handle the copy constructor and assignment operator. Otherwise the following is allowed and will cause undefined behavior: + +Rule of Three Copy Constructor +```c + +int test1() +{ + ThorsAnvil::UP sp1(new int(5)); + ThorsAnvil::UP sp2(sp1); // copy construction + + // Here the compiler generated copy constructor + // kicks in and does a member wise copy of sp1 + // into sp2. That in itself is not a problem. +} +// But when sp2 goes out of scope its destructor kicks in +// and deletes the pointer. When sp1 subsequently follows +// sp2 out of scope it will also call delete on the same +// pointer (as they share a copy of the pointer). +// +// This is known as a double delete and causes +// undefined behavior (UB). +``` + + The assignment operator is slightly worse: + +Rule of Three Assignment Operator +```c +int test2() +{ + ThorsAnvil::UP sp1(new int(5)); + ThorsAnvil::UP sp2(new int(6)); + + sp2 = sp1; // Assignment operation. + + // Here the compiler generated assignment + // operator kicks in and does a member wise + // assignment of sp1 into sp2. + // + // The main problem with the assignment here + // is that we have lost the original pointer + // that sp2 was holding. +} +// Same issues with double delete as the copy constructor. +``` +This is caused by the compiler atomically generating default implementations of certain methods (see discussion on the [rule of three](https://stackoverflow.com/q/4172722/14065)) if the user does not explicitly specify otherwise. In this case the problem comes because of the compiler generated versions of the copy constructor and assignment operator (see below) + +Compiler Generated Methods. +```c +namespace ThorsAnvil +{ + ..... + // Compiler Generated Copy Constructor + UP(UP const& copy) + : data(copy.data) + {} + + // Compiler Generated Assignment Operator + UP& UP::operator=(UP const& rhs) + { + data = rhs.data; + return *this; + } +} +``` +I have heard this described as a language bug; but I have to disagree with that sentiment, as these compiler generated methods do exactly as you would expect in nearly all situations. The one exceptions is when the class contains "owned raw pointers". +### Problem 2: Implicit construction. +The next issue is caused by C++ tendency to eagerly convert one type to another if given half a chance. If your class contains a constructor that takes a single argument then the compiler will use this as a way of converting one type to another. + +Example +```c +void takeOwner1(ThorsAnvil::UP x) +{} +void takeOwner2(ThorsAnvil::UP const& x) +{} +void takeOwner3(ThorsAnvil::UP&& x) +{} +int main() +{ + int* data = new int(7); + + takeOwner1(data); + takeOwner2(data); + takeOwner3(data); +} +``` +Though none of the functions in the example take an `int pointer` as a parameter; the compiler sees that it can convert an `int*` into an object of type `ThorsAnvil::UP` via the single argument constructor and builds temporary objects to facilitate the calling of the function. + +In the case of smart pointers, that take ownership of the object passed in the constructor, this can be a problem because the lifetime of a temporary object is the containing statement (with a few exceptions that we will cover in another article). As a simple rule of thumb you can think of the lifespan of a temporary ending at the `';'`. + +Temporary Object +```c +takeOwner1(data); + +// You can think of this as functionally equivalent to: + +{ + ThorsAnvil::UP tmp(data); + takeOwner1(tmp); +} +``` +The problem here is that when `tmp` goes out of scope its destructor will call delete on the pointer. Thus `data` is now pointing at memory that has been destroyed (and thus no longer belongs to the application). Any further use of `data` is going to potentially cause problems (and I am being generous using the word potentially). + +This feature can be quite useful (when you want this conversion to happen easily, see std::string). But you should definitely be aware of it and think carefully about creating single argument constructors. +### Problem 3: Null de-referencing +I think it is obvious that `operator*` has an issue with de-referencing a Null pointer here: + +operator*() +```c +T& operator*() {return *data;} +``` +But it is not quite as obvious that `operator->` is also going to cause dereferencing of the pointer here: + +operator->() +```c +T* operator->() {return data;} +``` +There are a couple of solutions to this problem. You can check `data` and throw an exception if it is a Null pointer, or alternatively you can make it a pre-condition on the usage of the smart pointer (ie it is the responsibility of the user to either know or check the state of the smart pointer before using these methods). + +The standard has chosen to go with a pre-condition (a very common C++ practice: do not impose an overhead on all your users (to spare problems for the beginner), but rather provide a mechanism to check the state for those that need to do so; so they can choose to pay the overhead when they need to and not every time). We can do the same here but we have not provided any mechanism for the user to check the state of the smart pointer. +### Problem 4: Const Correctness +When accessing the owned object via a smart pointer we are not affecting the state of our smart pointer so any member that basically returns the object (without changing the state of the smart pointer) should be marked const. + +Not const +```c +T* operator->() {return data;} +T& operator*() {return *data;} +``` +So these two methods should really be declared as: + +Const Correct +```c +T* operator->() const {return data;} +T& operator*() const {return *data;} +``` +### Problem 5: Bool conversion to easy +The current `operator bool()` works as required in bool expressions. + +Check for value +```c +ThorsAnvil::UP value(new int(4)); + +if (value) { + std::cout << "Not empty\n"; +} +``` +But the compiler will also use the conversion operators when it is trying to coerce objects that nearly match. For example you can now test two `UP` with `operator==` even though there does not exists an actual `operator==` for the `UP<>` class. This is because the compiler can convert both `UP<>` objects to bool and these can be compared. + +Auto conversion is bad (mostly) +```c +ThorsAnvil::UP value1(new int(8)); +ThorsAnvil::UP value2(new int(9)); + +if (value1 == value2) { + // unfortunately this will print "They match". + // Because both values are converted to bool (in this case true). + // Then the test is done. + std::cout << "They match\n"; +} +``` +In C++03 there was a nasty work around using pointers to members. But in C++11 there was added new functionality to make the conversion operator only fire in a boolean context otherwise it must be explicitly called. + +explicit converter +```c +explicit operator bool() {return data;} +... +ThorsAnvil::UP value1(new int(8)); +ThorsAnvil::UP value2(new int(9)); + +if (value1) { // This is expecting a boolean expression. + std::cout << "Not nullptr\n"; +} + +if (static_cast(value1) == static_cast(value2)) { // Need to be explicit + std::cout << "Both are either nullptr or not\n"; +} +``` +## Fixed First Try +So given the problems described above we can update our implementation to compensate for these issues: + +horsAnvil::UP Version 2 +```c +namespace ThorsAnvil +{ + template + class UP + { + T* data; + public: + // Explicit constructor + explicit UP(T* data) + : data(data) + {} + ~UP() + { + delete data; + } + // Remove compiler generated methods. + UP(UP const&) = delete; + UP& operator=(UP const&) = delete; + + // Const correct access owned object + T* operator->() const {return data;} + T& operator*() const {return *data;} + + // Access to smart pointer state + T* get() const {return data;} + explicit operator bool() const {return data;} + + // Modify object state + T* release() + { + T* result = nullptr; + std::swap(result, data); + return result; + } + }; +} +``` +If you are thinking this is not enough you are correct. We still have some more work to do. But lets leave it at that for version one. +## Summary +So in this initial post we have looked at a typical first attempt at a smart pointer and summarized the common problems I often see in these home grown smart pointer implementations. diff --git a/content/posts/SocketProgramminginC.md b/content/posts/SocketProgramminginC.md new file mode 100644 index 00000000..faf8e800 --- /dev/null +++ b/content/posts/SocketProgramminginC.md @@ -0,0 +1,194 @@ +--- +layout: post +title: "Socket Programming in C" +date: 2016-04-08T09:47:01-0700 +author: Loki Astari (C)2016 +comments: true +categories: ["C++", "Sockets", "C++-By-Example", "Coding"] +series: Sockets +tags: Sockets +sharing: true +footer: true +subtitle: So you want to learn C++ +description: Socket wrappers in C++ +image: /images/post/post-3.png +imageInfo: + original: https://unsplash.com/photos/d6dxQwmxV2Q + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Ken Blode + AttributionLink: https://unsplash.com/@benkolde +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2016/04/08/socket-programming-in-c-version-1/" +--- + +Building a simple client/server application is the common first internet based applications developers attempt. These applications are built on top of the socket communication library, but socket programming in C++ is not obvious as there are no standard libraries and thus you have to fall back to the C API. The closest "standardish" sort of thing we have is [Boost.asio](https://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/overview.html) which is at the other end of the spectrum in terms of API and involves a cognitive leap to understand what is happening underneath (or you can just trust the library maintainers). The other alternative is [libcurl](https://curl.haxx.se/libcurl/c/); the "easy curl" layer is an abstraction of the `socket()` API, while the "multi curl" layer is an abstraction of the `pselect()` API that allows multiple sockets to be handled in a single thread. + +I am writing a series of articles that start with a basic C++ client/server application and walk through building a C++ communication library. During this processes I will be using examples from [codereview.stackexchange.com](https://codereview.stackexchange.com) to illustrate common mistakes and try to show how to write the code correctly (This will also be a learning exercise for me so please let me know if you spot a mistake). + +Currently the plan is to write the following articles: + +{/* Server listening for program sockets */} +* Client/Server C +* Client/Server C Read/Write +* Client/Server C++ Wrapper +* Mult-Threaded Server +* Non-Blocking Socket +* Co-Routines + + +## Client/Server C++ Basic Version + +The minimum example of a working Client/Server application in C++: +The full working version is [here](https://github.com/Loki-Astari/Examples/tree/master/Version1) + +[C Server](https://github.com/Loki-Astari/Examples/blob/master/Version1/server.cpp) +```c +#include +#include +#include +#include +#include +#include + +#define SERVER_BUFFER_SIZE 1024 + +int main() +{ + int socketId = socket(PF_INET, SOCK_STREAM, 0); + + struct sockaddr_in serverAddr; + bzero((char*)&serverAddr, sizeof(serverAddr)); + serverAddr.sin_family = AF_INET; + serverAddr.sin_port = htons(8080); + serverAddr.sin_addr.s_addr = INADDR_ANY; + bind(socketId, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); + + listen(socketId, 5); + + int finished = 0; + while(!finished) + { + struct sockaddr_storage serverStorage; + socklen_t addr_size = sizeof serverStorage; + int newSocket = accept(socketId, (struct sockaddr*)&serverStorage, &addr_size); + + char buffer[SERVER_BUFFER_SIZE]; + int get = read(newSocket, buffer, SERVER_BUFFER_SIZE - 1); + + buffer[get] = '\0'; + fprintf(stdout, "%s\n", buffer); + + write(newSocket, "OK", 2); + + fprintf(stdout, "Message Complete\n"); + + close(newSocket); + } + close(socketId); +} +``` + +[C Client](https://github.com/Loki-Astari/Examples/blob/master/Version1/client.cpp) +```c +#include +#include +#include +#include +#include +#include + +#define CLIENT_BUFFER_SIZE 1024 + +int main(int argc, char* argv[]) +{ + if (argc != 3) + { + fprintf(stderr, "Usage: client \n"); + exit(1); + } + + int socketId = socket(PF_INET, SOCK_STREAM, 0); + + struct sockaddr_in serverAddr; + socklen_t addrSize = sizeof(serverAddr); + bzero((char*)&serverAddr, sizeof(serverAddr)); + serverAddr.sin_family = AF_INET; + serverAddr.sin_port = htons(8080); + serverAddr.sin_addr.s_addr = inet_addr(argv[1]); + connect(socketId, (struct sockaddr*)&serverAddr, addrSize); + + write(socketId, argv[2], strlen(argv[2])); + + shutdown(socketId, SHUT_WR); + + char buffer[CLIENT_BUFFER_SIZE]; + size_t get = read(socketId, buffer, CLIENT_BUFFER_SIZE - 1); + + buffer[get] = '\0'; + fprintf(stdout, "%s %s\n", "Response from server", buffer); + + close(socketId); +} +``` + +This version of the Client/Server actually works (a lot of the time) but obviously has a couple of major issues. + +## Checking Error Codes +If the calls to `socket()`, `bind()`, `listen()` or `connect()` fail then we have a catastrophic error any further actions will also fail. A few of the error codes generated by these functions can potentially be recovered from but most are programming error or permission failure as a result a human readable message with application termination is an acceptable solution (at this point). + +Note: When these functions don't succeed they set the global variable `errno` which can be translated into a human readable string with `strerror()`. So the simplest solution is to generate an appropriate error message for the user and terminate the application. + +Socket Validation +```c +int socketId = socket(PF_INET, SOCK_STREAM, 0); +if (socketId == -1) +{ + fprintf(stderr, "Failed: socket()\n%s\n", strerror()); + exit(1); +} +``` + +Bind Validation +```c +if (bind(socketId, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) == -1) +{ + fprintf(stderr, "Failed: bind()\n%s\n", strerror()); + close(socketId); // Don't forget to close the socket. + exit(1); +} +``` + +Listen Validation +```c +if (listen(socketId, 5) == -1) +{ + fprintf(stderr, "Failed: connect()\n%s\n", strerror()); + close(socketId); // Don't forget to close the socket. + exit(1); +} +``` + +Connect Validation +```c +if (connect(socketId, (struct sockaddr*)&serverAddr, addrSize) == -1) +{ + fprintf(stderr, "Failed: connect()\n%s\n", strerror()); + close(socketId); // Don't forget to close the socket. + exit(1); +} +``` + +# Summary + +The basic socket programs are relatively trivial. But this version 1 has some obvious flaws the major one being checking error states (which a lot of beginners forget in their first version). The next article will look into some more details about read and write operations on the socket. + +# Inspiration for Article + +* 2012-Jul-09 [Two-way communication in TCP: server-client implementation](https://codereview.stackexchange.com/q/13461/507) +* 2012-Jul-23 [Stupidly simple TCP client/server](https://codereview.stackexchange.com/q/13933/507) +* 2013-May-28 [How is this for a “Hello World” of socket programming?](https://codereview.stackexchange.com/q/26683/507) +* 2013-Sep-06 [Extract location from HTTP socket](https://codereview.stackexchange.com/q/30852/507) +* 2014-Mar-10 [Client/server implementation in C (sending data/files)](https://codereview.stackexchange.com/q/43914/507) + diff --git a/content/posts/SocketProtocols.md b/content/posts/SocketProtocols.md new file mode 100644 index 00000000..0ab01ecd --- /dev/null +++ b/content/posts/SocketProtocols.md @@ -0,0 +1,322 @@ +--- +layout: post +title: "Socket Protocols" +date: 2016-05-29T21:13:39-07:00 +author: Loki Astari (C)2016 +comments: true +categories: ["C++", "Sockets", "C++-By-Example", "Coding"] +series: Sockets +tags: Sockets +sharing: true +footer: true +subtitle: So you want to learn C++ +description: A very cursory look at protocols and why they are needed +image: /images/post/post-6.png +imageInfo: + original: https://unsplash.com/photos/Bj6ENZDMSDY + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Ben Griffiths + AttributionLink: https://unsplash.com/@benofthenorth +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2016/05/29/socket-protocols/" +--- + +In the previous articles I have used a very simplistic protocol. In real world situations this simple protocol is not sufficient. To provide a more robust connection between client and server a communications protocol is required so that we can validate messages are sent correctly and generate appropriate responses that can also be validated. + +Designing a communication protocol is a non trivial task and personally I would look for an existing protocol that matches your use case rather than trying to create protocol from scratch. + +#### Example Protocols +* HTTP:  https://tools.ietf.org/html/rfc2616.txt +* IRC:      https://tools.ietf.org/html/rfc1490.txt + +Rather than go through all the different protocols I am simply going to pick the HTTP(S) protocol and use that for further discussion. HTTP(S) is relatively well known; It is simple to implement the basics; There are well known server implementations that support it; There are well known client libraries that can be used in application development. + +#### Example HTTP(S) servers +* [Apache](https://httpd.apache.org/) +* [nginx](https://nginx.org/en/) +* [Node.js](https://nodejs.org/en/about/) + +#### Client Side HTTP Libraries +* [LibCurl](https://curl.haxx.se/libcurl/c/) +* [Libwww](https://www.w3.org/Library/User/Using/) +* [HttpFetch](https://http-fetcher.sourceforge.net/API/index.html) + + +## HTTP(S) +Basically HTTP(S) defines two object. A request object is sent from the client to the server and response object is sent back as a result of a request. The only difference between the two is the start-line. Both HTTP objects can be broken down into three pieces. + +1. Start-Line +2. Header-Section +3. Body + +### Start-Line + +For a request object this is: + + + + + + + +
• Method:HEAD/GET/PUT/POST/DELETE
• Space:One Space character
• URL:Identification of the object/service needed
• Space:One Space character
• HTTP-Version:Usually HTTP/1.1
• CR/LF:Literally '\r\n'
+ +#### Example: +``` +GET https://google.com/maps?id=456 HTTP/1.1\r\n +``` + +For a response object this is: + + + + + + + +
• HTTP-Version:Usually HTTP/1.1
• Space:One Space character
• Response Code:100->599
• Space:One Space character
• Human Readable Response:Human readable explanation of the response code
• CR/LF:Literally '\r\n'
+ +#### Example: +``` +HTTP/1.1 200 OK\r\n +``` + +### Header-Section + +This is a set of key/value pairs one per line separated by a colon. Each Line is terminated by CR/LF and the end of the header section is marked by an empty line. + + + + + + + +
• Key:A text string representing the keys.
• Colon:A single colon (note: some implementations are lax and insert a space before the colon).
• Space:One Space character (note: some implementations are lax and more then one space may be present)
• Value:A set of characters that does not include CR or LF.
• CR/LF:Literally '\r\n'
+ +#### Example +``` +Content-Length: 42\r\n +Content-Type: text/text\r\n +\r\n +``` + +### Body + +The payload of the object should be in the body. Its size is defined by the headers defined in [rfc-2616 section 4.4 Message Length](https://tools.ietf.org/html/rfc2616#section-4.4). + +### Required Headers + +According to the rfc(s) [7230](https://tools.ietf.org/html/rfc7230), [7231](https://tools.ietf.org/html/rfc7231), [7232](https://tools.ietf.org/html/rfc7232), [7233](https://tools.ietf.org/html/rfc7233), [7234](https://tools.ietf.org/html/rfc7234) or [7235](https://tools.ietf.org/html/rfc7235) there are no header fields there are actually required header fields. + +#### Request Object +But real world implementations need some headers to work efficiently, so you probably should send the following headers when making a request to a server: + +* [Content-Type](https://tools.ietf.org/html/rfc7231#section-3.1.1.5): +* [Content-Length](https://tools.ietf.org/html/rfc7230#section-3.3.2): // Or use one of the other techniques to specify length +* [Host](https://tools.ietf.org/html/rfc7230#section-5.4): + +It is also polite to send the following. + +* [User-Agent](https://tools.ietf.org/html/rfc7231#section-5.5.3): +* [Accept](https://tools.ietf.org/html/rfc7231#section-5.3.2): + +#### Response Object +A server implementation "Must" send a `Date:` header field if it is a reasonable approximation of UTC. But that means servers may not supply the `Date:` field so you can't say it is a requirement of the standard. But you will usually see the following headers returned from a server: + +* [Date](https://tools.ietf.org/html/rfc7231#section-7.1.1.2): +* [Server](https://tools.ietf.org/html/rfc7231#section-7.4.2): +* [Content-Length](https://tools.ietf.org/html/rfc7230#section-3.3.2): +* [Content-Type](https://tools.ietf.org/html/rfc7231#section-3.1.1.5): + +## Implementation + +Given this very basic protocol; it seems like the implementation of these requirements should be quite trivial. To be honest the implementation of creating the objects to send is relatively trivial, the hard part is reading objects from the stream in an efficiently and correctly validated manner. You can find my attempt [here](https://github.com/Loki-Astari/Examples/tree/master/Version3): It works but its 500 lines long and only covers the most basics parts of the protocol and does not do any of the hard parts (like authentication or HTTPS). + +To use this protocol correctly you really need to use one of the existing libraries. Here I have re-implemented the client using libcurl. + +[Client uses libcurl wrapper](https://github.com/Loki-Astari/Examples/blob/master/Version4/client.cpp) +```c +int main(int argc, char* argv[]) +{ + namespace Sock = ThorsAnvil::Socket; + if (argc != 3) + { + std::cerr << "Usage: client \n"; + std::exit(1); + } + + Sock::CurlGlobal curlInit; + Sock::CurlPost connect(argv[1], 8080); + + connect.sendMessage("/message", argv[2]); + + std::string message; + connect.recvMessage(message); + std::cout << message << "\n"; +} +``` + + +[libCurl simple wrapper](https://github.com/Loki-Astari/Examples/blob/master/Version4/client.cpp) +```c +#include "Utility.h" +#include +#include +#include +#include + +namespace ThorsAnvil +{ + namespace Socket + { + +class CurlGlobal +{ + public: + CurlGlobal() + { + if (curl_global_init(CURL_GLOBAL_ALL) != 0) + { + throw std::runtime_error(buildErrorMessage("CurlGlobal::", __func__, ": curl_global_init: fail")); + } + } + ~CurlGlobal() + { + curl_global_cleanup(); + } +}; + +extern "C" size_t curlConnectorGetData(char *ptr, size_t size, size_t nmemb, void *userdata); + +enum RequestType {Get, Head, Put, Post, Delete}; +class CurlConnector +{ + CURL* curl; + std::string host; + int port; + std::string response; + + friend size_t curlConnectorGetData(char *ptr, size_t size, size_t nmemb, void *userdata); + std::size_t getData(char *ptr, size_t size) + { + response.append(ptr, size); + return size; + } + template + void curlSetOptionWrapper(CURLoption option, Param parameter, Args... errorMessage) + { + CURLcode res; + if ((res = curl_easy_setopt(curl, option, parameter)) != CURLE_OK) + { + throw std::runtime_error(buildErrorMessage(errorMessage..., curl_easy_strerror(res))); + } + } + + public: + CurlConnector(std::string const& host, int port) + : curl(curl_easy_init( )) + , host(host) + , port(port) + { + if (curl == NULL) + { + throw std::runtime_error(buildErrorMessage("CurlConnector::", __func__, ": curl_easy_init: fail")); + } + } + ~CurlConnector() + { + curl_easy_cleanup(curl); + } + CurlConnector(CurlConnector&) = delete; + CurlConnector& operator=(CurlConnector&) = delete; + CurlConnector(CurlConnector&& rhs) noexcept + : curl(nullptr) + { + rhs.swap(*this); + } + CurlConnector& operator=(CurlConnector&& rhs) noexcept + { + rhs.swap(*this); + return *this; + } + void swap(CurlConnector& other) noexcept + { + using std::swap; + swap(curl, other.curl); + swap(host, other.host); + swap(port, other.port); + swap(response, other.response); + } + + virtual RequestType getRequestType() const = 0; + + void sendMessage(std::string const& urlPath, std::string const& message) + { + std::stringstream url; + response.clear(); + url << "https://" << host; + if (port != 80) + { + url << ":" << port; + } + url << urlPath; + + CURLcode res; + auto sListDeleter = [](struct curl_slist* headers){curl_slist_free_all(headers);}; + std::unique_ptr headers(nullptr, sListDeleter); + headers = std::unique_ptr(curl_slist_append(headers.get(), "Content-Type: text/text"), sListDeleter); + + curlSetOptionWrapper(CURLOPT_HTTPHEADER, headers.get(), "CurlConnector::", __func__, ": curl_easy_setopt CURLOPT_HTTPHEADER:"); + curlSetOptionWrapper(CURLOPT_ACCEPT_ENCODING, "*/*", "CurlConnector::", __func__, ": curl_easy_setopt CURLOPT_ACCEPT_ENCODING:"); + curlSetOptionWrapper(CURLOPT_USERAGENT, "ThorsCurl-Client/0.1", "CurlConnector::", __func__, ": curl_easy_setopt CURLOPT_USERAGENT:"); + curlSetOptionWrapper(CURLOPT_URL, url.str().c_str(), "CurlConnector::", __func__, ": curl_easy_setopt CURLOPT_URL:"); + curlSetOptionWrapper(CURLOPT_POSTFIELDSIZE, message.size(), "CurlConnector::", __func__, ": curl_easy_setopt CURLOPT_POSTFIELDSIZE:"); + curlSetOptionWrapper(CURLOPT_COPYPOSTFIELDS, message.data(), "CurlConnector::", __func__, ": curl_easy_setopt CURLOPT_COPYPOSTFIELDS:"); + curlSetOptionWrapper(CURLOPT_WRITEFUNCTION, curlConnectorGetData, "CurlConnector::", __func__, ": curl_easy_setopt CURLOPT_WRITEFUNCTION:"); + curlSetOptionWrapper(CURLOPT_WRITEDATA, this, "CurlConnector::", __func__, ": curl_easy_setopt CURLOPT_WRITEDATA:"); + + switch(getRequestType()) + { + case Get: res = CURLE_OK; /* The default is GET. So do nothing.*/ break; + case Head: res = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "HEAD"); break; + case Put: res = curl_easy_setopt(curl, CURLOPT_PUT, 1); break; + case Post: res = curl_easy_setopt(curl, CURLOPT_POST, 1); break; + case Delete: res = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); break; + default: + throw std::domain_error(buildErrorMessage("CurlConnector::", __func__, ": invalid method: ", static_cast(getRequestType()))); + } + if (res != CURLE_OK) + { + throw std::runtime_error(buildErrorMessage("CurlConnector::", __func__, ": curl_easy_setopt CURL_METHOD:", curl_easy_strerror(res))); + } + if ((res = curl_easy_perform(curl)) != CURLE_OK) + { + throw std::runtime_error(buildErrorMessage("CurlConnector::", __func__, ": curl_easy_perform:", curl_easy_strerror(res))); + } + } + void recvMessage(std::string& message) + { + message = std::move(response); + } +}; + +class CurlPost: public CurlConnector +{ + public: + using CurlConnector::CurlConnector; + virtual RequestType getRequestType() const {return Post;} + +}; + +size_t curlConnectorGetData(char *ptr, size_t size, size_t nmemb, void *userdata) +{ + CurlConnector* self = reinterpret_cast(userdata); + return self->getData(ptr, size * nmemb); +} + + } +} +``` + diff --git a/content/posts/SocketRead_Write.md b/content/posts/SocketRead_Write.md new file mode 100644 index 00000000..48c1322c --- /dev/null +++ b/content/posts/SocketRead_Write.md @@ -0,0 +1,269 @@ +--- +layout: post +title: "Socket Read/Write" +date: 2016-04-09T21:11:25-0700 +author: Loki Astari (C)2016 +comments: true +categories: ["C++", "Sockets", "C++-By-Example", "Coding"] +series: Sockets +tags: Sockets +sharing: true +footer: true +subtitle: So you want to learn C++ +description: Socket wrappers in C++ +image: /images/post/post-4.png +imageInfo: + original: https://unsplash.com/photos/wX2L8L-fGeA + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Roman Synkevych + AttributionLink: https://unsplash.com/@synkevych +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2016/04/09/socket-read/" +--- + +## Checking read/write success + +The `read()` and `write()` command can fail in a couple of ways but can also succeed without reading/writing all the data, a common mistake is not to check the amount of data read/written from/to a stream. Interestingly not all error condition are fatal and reading/writing can potentially be resumed after an error. + +## Read +To understand if you have read all the information that is available on a stream you need to define a communication protocol (like HTTP). For the first version of this server the protocol is very simple. Messages are passed as strings (not null terminated) and the end of the message is marked by closing the write stream. Thus a client can send one message and receive one reply with each connection it makes. + +getMessage() +```c +/* + * Returns: 0 EOM reached. + * The message is complete. There is no more data to be read. + * >0 Message data has been read (and a null terminator added). + * The value is the number of bytes read from the stream + * You should call getMessage() again to get the next section of the message. + * Note: the message is terminated when 0 is returned. + * -1 An error occured. + */ +int getMessage(int socketId, char* buffer, std::ssize_t size) +{ + std::ssize_t dataRead = 0; + std::ssize_t dataMax = size - 1; + + while(dataRead < dataMax) + { + ssize_t get = read(socketId, buffer + dataRead, size - dataRead); + if (get == -1) + { + return -1; + } + if (get == 0) + { + break; + } + dataRead += get; + } + buffer[dataRead] = '\0'; + return dataRead; +} +``` + +### Read Errors +This initial version treats all `read()` errors as unrecoverable and `getMessage()` return an error state. But not all error codes need to result in a failure. So in this section I will go through some of the error codes and give some potentially actions. In a subsequent articles I may revise these actions as we cover more complex ways of interacting with sockets. + + +The following errors are the result of programming bugs and should not happen in production. + + [EBADF] fildes is not a valid file or socket descriptor open for reading. + [EFAULT] Buf points outside the allocated address space. + [EINVAL] The pointer associated with fildes was negative. + [ENXIO] A requested action cannot be performed by the device. + +If they do happen in production there is no way to correct for them pragmatically because the error has happened in another part of the code unassociated with this function. + +One could argue that because these should never happen the application can abort, but for now we will settle for the read operation aborting with an error code. If we wrap this in a C++ class to control the state of the socket then exceptions may be more appropriate and we will look into that approach in a subsequent article. + +The following errors are potentially recoverable from. +{/* https://stackoverflow.com/questions/8471577/linux-tcp-connect-failure-with-etimedout */} + + [EIO] An I/O error occurred while reading from the file system. + [ENOBUFS] An attempt to allocate a memory buffer fails. + [ENOMEM] Insufficient memory is available. + [ETIMEDOUT] A transmission timeout occurs during a read attempt on a socket. + +But in reality recovering from them within the context of a read operation is not practical (you need to recover from these operations at a point were resource are controlled or user interaction is possible). So for now we will abort the read operation with an error code (we will revisit this in a later article). + +The following error codes means that no more data will be available because the connection has been interrupted. +{/* https://stackoverflow.com/questions/2974021/what-does-econnreset-mean-in-the-context-of-an-af-local-socket */} +{/* https://stackoverflow.com/questions/900042/what-causes-the-enotconn-error */} + + [ECONNRESET] The connection is closed by the peer during a read attempt on a socket. + [ENOTCONN] A read is attempted on an unconnected socket. + +How the application reacts to a broken connection depends on the communication protocol. For the simple protocol defined above we can return any data that has been retrieved from the socket and then indicating to the calling code that we have reached the end of the message (we will revisit this in a later article). This is probably the most iffy decision in handling error codes and returning an error code could be more appropriate but I want to illustrate that we can potentially continue depending on the situation. + +The following error codes are recoverable from. + + [EAGAIN] The file was marked for non-blocking I/O, and no data were ready to be read. + +These error codes are generated when you have a non-blocking stream. In a future article we will discuss how to take advantage of non-blocking streams. + + [EINTR] A read from a slow device was interrupted before any data arrived by the delivery of a signal. + +The exact action that you take will depend on your application (like doing some useful work) but for our simple application simply re-trying the read operation will be the standard action. Again we will come back to this, but taking advantage of timeouts will require a slightly more sophisticated approach rather than using the sockets API directly. + +> **EINTR:** +> An important note about signals. There are a lot of signals that are non lethal and will result in this EINTR error code. But one should note that lethal signals like SIGINT by default will kill the application and thus will not cause this error code (as the call to read() will never return). +> +>But you can override the SIGINT signal handler and a allow your application to continue and at this point your read operation will receive this error. How your code interacts with signals like SIGINT is beyond the scope of this article and it will be discussed just like other signals. + +getMessage() Improved +```c +/* + * Returns: 0 EOM reached. + * There is no data in the buffer. + * >0 Message data has been read. + * If the buffer is full then it is not null terminated. + * If the buffer is partially full then it is null terminated + * and the next call to get getMessage() will return 0. + * <0 An error occured. + */ +int getMessage(int socketId, char* buffer, std::ssize_t size) +{ + std::ssize_t dataRead = 0; + std::ssize_t dataMax = size - 1; + + while(dataRead < dataMax) + { + ssize_t get = read(socketId, buffer + dataRead, size - dataRead); + if (get == -1) + { + switch(errno) + { + case EBADF: + case EFAULT: + case EINVAL: + case ENXIO: + // Fatal error. Programming bug + return -3; + case EIO: + case ENOBUFS: + case ENOMEM: + // Resource aquisition failure or device error + // Can't recover from here so indicate failure + // and exit + return -2; + case ETIMEDOUT: + case EAGAIN: + case EINTR: + // Temporrary error. + // Simply retry the read. + continue; + case ECONNRESET: + case ENOTCONN: + // Connection broken. + // Return the data we have available and exit + // as if the connection was closed correctly. + get = 0; + break; + default: + return -1; + } + } + if (get == 0) + { + break; + } + dataRead += get; + } + buffer[dataRead] = '\0'; + return dataRead; +} +``` + +## Write +The `write()` has exactly the same scenario as `read()`. + +The following errors are the reuls of programming bugs and should not happen in production. + + [EINVAL] The pointer associated with fildes is negative. + [EBADF] fildes is not a valid file descriptor open for writing. + [ECONNRESET] A write is attempted on a socket that is not connected. + [ENXIO] A request is made of a nonexistent device, or the request is outside the capabilities of the device. + [EPIPE] An attempt is made to write to a socket of type SOCK_STREAM that is not connected to a peer socket. + +The following errors are potentially recoverable bugs. Though recovering from them requires some form of awarness of the context that is not provided at the read level. So we must generate an error to stop reading and allow the caller to sort out the problem. + + [EDQUOT] The user's quota of disk blocks on the file system containing the file is exhausted. + [EFBIG] An attempt is made to write a file that exceeds the process's file size limit or the maximum file size. + [EIO] An I/O error occurs while reading from or writing to the file system. + [ENETDOWN] A write is attempted on a socket and the local network interface used to reach the destination is down. + [ENETUNREACH] A write is attempted on a socket and no route to the network is present. + [ENOSPC] There is no free space remaining on the file system containing the file. + + +The following error codes are recoverable from and we covered them above in the section on `read()`. + + [EAGAIN] The file is marked for non-blocking I/O, and no data could be written immediately. + [EINTR] A signal interrupts the write before it could be completed. + +The resulting put function then looks like this. + +putMessage() Improved +```c +/* + * Returns: + * >0 Indicates success and the number of bytes written. + * <0 Indicates failure. + */ +int putMessage(int socketId, char* buffer, ssize_t size) +{ + ssize_t dataWritten = 0; + + while(dataWritten < size) + { + ssize_t put = write(socketId, buffer + dataWritten, size - dataWritten); + if (put == -1) + { + switch(errno) + { + case EINVAL: + case EBADF: + case ECONNRESET: + case ENXIO: + case EPIPE: + // Fatal error. Programming bug + return -3; + case EDQUOT: + case EFBIG: + case EIO: + case ENETDOWN: + case ENETUNREACH: + case ENOSPC: + // Resource aquisition failure or device error + // Can't recover from here so indicate failure + // and exit + return -2; + case EAGAIN: + case EINTR: + // Temporrary error. + // Simply retry the read. + continue; + default: + return -1; + } + } + dataWritten += put; + } + return dataWritten; +} +``` + +# Summary + +This article has shown the most important error that people skip over when reading and writing to a socket: **Not all the data was transported at the same time**. The read and write command may only read/write a portion of the data that you wanted to send/receive and thus you must check the amount that actually was sent/received. + +The next most important point is that not all error codes are fatal (most people actually check these) **but** an interrupt (EINTR) can be relatively common and you can continue reading after it has happened. +# Inspiration + +* 2015-Jun-25 [Impromptu TCP sender/receiver](https://codereview.stackexchange.com/q/94608/507) +* 2015-Jul-03 [Raw Text TCP Client v3](https://codereview.stackexchange.com/q/95638/507) +* 2015-Dec-20 [Server / client desynchronisation of messages ](https://codereview.stackexchange.com/q/114551/507) + + diff --git a/content/posts/SwitchingtoOctoPress.md b/content/posts/SwitchingtoOctoPress.md new file mode 100644 index 00000000..b232dc48 --- /dev/null +++ b/content/posts/SwitchingtoOctoPress.md @@ -0,0 +1,54 @@ +--- +layout: post +title: "Switching to OctoPress" +date: 2013-11-30T15:37:34-0800 +author: Loki Astari, (C)2013 +comments: true +categories: ["WordPress", "OctoPress", "Blogging"] +description: Switching the blog to octopress. +image: /images/post/post-7.png +imageInfo: + original: https://unsplash.com/photos/2EJCSULRwC8 + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Alex Knight + AttributionLink: https://unsplash.com/@agk42 +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2013/11/30/switching-to-octopress/" +--- + +## Switching to OctoPress and Github + +I have not blogged much, until recently, so I am not an HTML/CSS/Javascript expert. Thus layout, or layout during writing an article, is not of supreme importance for me. I expect the framework to handle that all for me. But that was my issue with WordPress. As a normal blogger I am sure it is not an issue, but the tools for blogging about code are rudimentary and not well integrated in to WordPress; basically forcing me to write in HTML (see [Set up WordPress](https://lokiastari.com/posts/WanttosetupWordPresstowriteaboutProgramming)). I do write a lot on other sites that specialize in coding and these sites have developed a style called <MarkDown>. The two most common versions are '[StackOverFlow markdown](https://stackoverflow.com/editing-help)' and '[GitHub markdown](https://daringfireball.net/projects/markdown/syntax)'. + +### MarkDown + +Markdown is a very simplistic form of 'Markup' (yes programmers think they are funny with the up/down thing) that is designed specifically to be simple and deal with the common issues of writing word based articles. Coder sites usually extend this with basic support for placing code (or pre-formatted text) directly into the article. It is not designed for non technical people (they should be using a 'Visual' interface not markup) but for the technical writer who does not want the full blown power of HTML, but wants slightly more control than visual interfaces provide. + +### Attack Vector + +WordPress is also infamous for being the target of attackers, thus new attacks are constantly being developed (the joy of being top dog). This can be mitigated by putting your WordPress site on [wordpress.com](https://wordpress.com). This not only provides you with free hosting, but they do keep on top of security vulnerabilities and make sure all hosted sites are not overexposed. + +If you want use your own domain name (i.e. [LokiAstari.com](https://LokiAstari.com)) or any other "featured" services then you either need to fork up the cash (not an insignificant sum) or run your own WordPress site. So I have been running my own WordPress sites. However, running your own site opens you to the vulnerabilities of WordPress attacks. To be honest not a big deal until I actually tweeted about my articles (now very much so). + +So the combination of these two issues has made me look for alternatives. + +### OctoPress + +[OctoPress](https://octopress.org) was suggested by a colleague [Dan Lecocq](https://github.com/danlecocq). It is basically an off-line blogging system that takes your articles and creates a set of static pages. You can then use several systems to publish these static pages. As the pages are generated once (each time you create a new article) the requirements for the hosting system are minimal, and consequently, because there is no dynamic content, there are no attack vectors that can be used against the site. Note: This does not mean the site has to be simple or boring as the pages can still have dynamic content loaded from other sites (like twitter/github/facebook etc.) It is just that the dynamic content will be fetched by the browser from other sites. + +The other major advantage is that it natively supports MarkDown. In fact, you plug in your favorite MarkDown engine (I have currently stuck with the default 'GitHub markdown'). So you can write your article in MarkDown, and it will translate to the appropriate HTML. + +Like WordPress it has multiple themes, unlike WordPress the user base is small so the pool of user created themes is tiny in comparison (a couple of dozen). Though not as well established as WordPress, you can easily extend it and build your own themes. There are already a couple of themes based on [Bootstrap](https://github.com/twbs/bootstrap) the most commonly forked HTML5/CSS/Javascript web-site project on [GitHub](https://github.com). + +### GitHub + +OctoPress also integrates with [GitHub Pages](https://pages.github.com/) a feature of the site designed to allow you to create documentation for your software. + +Though this is still not my perfect writing environment; OctoPress is a step up from using WordPress (for me, if you are not used to writing code it will not be good for you and I would stick to WordPress's Visual editor). There are a couple of tweaks I still need to iron out here and there. Once I have got a basic system working perfectly I will talk about exactly what I did. I have some ideas on how to improve the basics which may be down the road a bit (I need to perform more research how others are using this tool so I don't reinvent the wheel). + + + + + diff --git a/content/posts/Variables.md b/content/posts/Variables.md new file mode 100644 index 00000000..2385a17f --- /dev/null +++ b/content/posts/Variables.md @@ -0,0 +1,98 @@ +--- +layout: post +title: "Variables" +date: 2013-11-19T09:15:16-0800 +author: Loki Astari, (C)2013 +comments: true +categories: ["C++", "So-You-Want-To-Learn-C++", "Coding"] +series: So-You-Want-To-Learn-C++ +tags: So-You-Want-To-Learn-C++ +sharing: true +footer: true +subtitle: So you want to learn C++ +description: C++ for beginners. Part 3 Variables. In most programming languages you have the concept of variables. These are simply named objects that hold a value (more formerly refereed to as state). By manipulating a variable you manipulate the state of the object that the variable referees too. +image: /images/post/post-5.png +imageInfo: + original: https://unsplash.com/photos/W-oqNwbmin0 + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Oscar Nilsson + AttributionLink: https://unsplash.com/@oscrse +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2013/11/19/so-you-want-to-learn-c-plus-plus-part-3/" +--- + +## Variables + +In most programming languages you have the concept of variables. These are simply named objects that hold a value (more formerly refereed to as state). By manipulating a variable you manipulate the state of the object that the variable referees too. + +add.cpp +```c +void addFunction() +{ + int x = 0; // Declare (and initialize) a variable called "x" + + x = x + 5; // Manipulate the variable "x". + // The variable "x" now holds the value "5" + + int y = x + 3; // Declare (and initialize) a variable called "y" + // This will take the value "8" by adding "+" 3 + // to the value of "x" +} +``` + +C++ is a strongly typed language. This means that each variable has a specific type that does not change (above that type is **int**). The operations that can be performed on an object are dependent on the type of the object and the result of the operation can depend on the types involved. C++ has several built in types (listed below) but allows the definition of new user defined types (which will be described in a later article). The standard library provides a set of commonly used user defined types (listed below). + +Built in Types +```c +char // Represents a character. +bool // Represents a boolean true/false value. +short // Represents an integer of at least 16 bits +int // Represents an integer of at least 32 bits +long // Represents an integer of at least 32 bits +long long // Represents an integer of at least 64 bits +float // Represents a floating point number +double // Represents a double precision floating point number +``` + +Standard Types +```c +// This is a list of the most commonly used types (there are many more) +std::string // Represents a string of characters. +std::vector // Represents a dynamically sizable array + // of objects with the type 'T' +std::array // Represents a fixed 'size' array + // of objects with the type 'T' +std::list // Represents a list of objects with the type 'T' +std::map // Represents a dictionary of key, value pairs (index by key). + // The key has type 'Key' + // The value has type 'Value' +std::set // Represents a set of keys of type 'Key' +``` + +The list may seem a bit daunting at first, but while you are learning if you restrict yourselves to three built in types (**bool**, **int** and **double**) and two standard types (**std::string** and **std::vector<T>**) you will be able to solve most beginner/training problems. + +The other built in types are usually used when you need larger range of values or need to save space. The additional standard type (shown above) are different types of container and provide different accesses characteristics (which will be explained later). We will cover all these types in due course. + +So an example of usage of the most common types is: + +variables.cpp +```c +#include +#include +#include + +int main() +{ + int age = 28; + std::string name = "Loki"; + double grade = 12.45; + std::vector courseNames = { "C++", "Teaching", "Maths", "Art", "Music"}; + + std::cout << "Name: " << name << "\n"; + std::cout << "Age: " << age << "\n"; + std::cout << "Grade:" << grade << "\n"; + std::cout << "Course 1: " << courseNames[1] << "\n"; +} +``` diff --git a/content/posts/Vector-Resize.md b/content/posts/Vector-Resize.md new file mode 100644 index 00000000..40d94ea3 --- /dev/null +++ b/content/posts/Vector-Resize.md @@ -0,0 +1,417 @@ +--- +layout: post +title: "Vector - Resize" +date: 2016-03-12T05:53:07-0700 +author: Loki Astari, (C)2016 +comments: true +categories: ["C++", "Vector", "Resource-Management", "C++-By-Example", "Coding"] +series: Vector +tags: Vector +sharing: true +footer: true +subtitle: C++ By Example +description: C++ By Example. The Vector Part 3. Because resizing a vector is expensive; the standard vector class uses exponential growth to minimize the number of times that the vector is resized; a technique we replicate in this version. But every now and then you still need to resize the internal buffer. +image: /images/post/post-7.png +imageInfo: + original: https://unsplash.com/photos/2EJCSULRwC8 + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Alex Knight + AttributionLink: https://unsplash.com/@agk42 +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2016/03/12/vector-resize/" +--- +Because resizing a vector is expensive; the `std::vector` class uses exponential growth to minimize the number of times that the vector is resized: a technique we replicate in this version. But every now and then you still need to resize the internal buffer. + +In the [current version](#VectorVersion-1), resizing the vector requires allocating a new buffer and copying all the members into it. Basically we are using the copy and swap idiom to provide the strong exception guarantee (If an exception is thrown all resources are cleaned up and the object remains unchanged). + +Vector Resize with Copy + +```c + void pushBackInternal(T const& value) + { + new (buffer + length) T(value); + ++length; + } + + void reserveCapacity(std::size_t newCapacity) + { + Vector tmpBuffer(newCapacity); + std::for_each(buffer, buffer + length, + [&tmpBuffer](T const& v){tmpBuffer.pushBackInternal(v);} + ); + + tmpBuffer.swap(*this); + } +``` + + +# Resize With Move Construction +Thus resizing a `Vector` can be a very expensive operation because of all the copying that can happen. + +Using the move constructor rather than the copy constructor during a resize operation could potentially be much more efficient. But the move constructor mutates the original object and thus if there is a problem we need to undo the mutations to maintain the strong exception guarantee. + +The first attempt at this is: + +Vector Resize with Move With Exceptions +```c +void moveBackInternal(T&& value) +{ + new (buffer + length) T(std::move(value)); + ++length; +} + +void reserveCapacity(std::size_t newCapacity) +{ + Vector tmpBuffer(newCapacity); + try + { + std::for_each(buffer, buffer + length, + [&tmpBuffer](T& v){tmpBuffer.moveBackInternal(std::move(v));} + ); + } + catch(...) + { + // If an exception is thrown you need to move the objects back + // from the temporary buffer back to this object. + for(int loop=0; loop < tmpBuffer.length; ++loop) + { + // The problem is here: + // If the initial move can throw, + // then trying to move any of the objects back can also throw. + // which would leave the object in an inconsistent state. + buffer[loop] = std::move(tmpBuffer[loop]); + } + + // Then remember to rethrow the exception after we have fixed the state. + throw; + } + + tmpBuffer.swap(*this); +} +``` +# Resize With NoThrow Move Construction +As the above code shows; if the type `T` can throw during its move constructor then you can't guarantee that the object gets returned to the original state (as moving the already moved elements back may cause another exception). So we cannot use the move constructor to resize the vector if the type `T` can throw during move construction. + +But not all types throw when being moved. In fact it is recommended that move constructors never throw. If we can guarantee that the move constructor does not throw then we can simplify the above code considerably and still provide the strong exception guarantee. + +Vector Resize with Move +```c +void reserveCapacity(std::size_t newCapacity) +{ + Vector tmpBuffer(newCapacity); + std::for_each(buffer, buffer + length, + [&tmpBuffer](T& v){tmpBuffer.moveBackInternal(std::move(v));} + ); + + tmpBuffer.swap(*this); +} +void moveBackInternal(T&& value) +{ + new (buffer + length) T(std::move(value)); + ++length; +} +``` +# Resize Template Specialization +So now we have to write the code that decides at compile time which version we should use. The simplest way to do this is to use template specialization of a class using the standard class `std::is_nothrow_move_constructible` to help differentiate types that have a non-throwing move constructor. This is simple enough: + +Template class Specialization +```c +template::value> +struct SimpleCopy +{ + // Define two different versions of this class. + // The object is to copy all the elements from src to dst Vector + // using pushBackInternal or moveBackInternal + // + // SimpleCopy: Defines a version that use pushBackInternal (copy constructor) + // This is always safe to use. + // SimpleCopy: Defines a version that uses moveBackInternal (move constructor) + // Safe when move construction does not throw. + // + void operator()(Vector& src, Vector& dst) const; +}; +template +class Vector +{ + public: + ..... + private: + // We are using private methods for effeciency. + // So these classes need to be friends. + friend struct SimpleCopy; + friend struct SimpleCopy; + + void reserveCapacity(std::size_t newCapacity) + { + Vector tmpBuffer(newCapacity); + + // Create the copier object base on the type T. + // Note: The second parameter is automatically generated based + // on if the type T is move constructable with no exception. + SimpleCopy copier; + copier(*this, tmpBuffer); + + tmpBuffer.swap(*this); + } + void pushBackInternal(T const& value) + { + new (buffer + length) T(value); + ++length; + } + void moveBackInternal(T&& value) + { + new (buffer + length) T(std::move(value)); + ++length; + } +} +// Define the two different types of copier +template +struct SimpleCopy // false: does not have nothrow move constructor +{ + void operator()(Vector& src, Vector& dst) const + { + std::for_each(buffer, buffer + length, + [&dst](T const& v){dst.pushBackInternal(v);} + ); + } +}; +template +struct SimpleCopy // true: has a nothrow move constructor +{ + void operator()(Vector& src, Vector& dst) const + { + std::for_each(buffer, buffer + length, + [&dst](T& v){dst.moveBackInternal(std::move(v));} + ); + } +}; +``` +# Resize With NoThrow SFINAE +The above technique has a couple of issues. + +The type `SimpleClass` is publicly available and is a friend of `Vector`. This makes it susceptible to accidentally being used (even if not explicitly documented). Unfortunately it can't be included as a member class and also be specialized. + +Additionally it looks awful!! + +But we can also use [SFINAE](https://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error) and method overloading. + +SFINAE allows us to define several versions of a method with exactly the same arguments, as long as only one of them is valid at compile time. So in the example below we define two versions of the method `SimpleCopy(Vector& src, Vector& dst)` but then use `std::enable_if` to make sure only one version of the function is valid at compile time. + +SFINAE method overload + +```c +template +class Vector +{ + public: + ..... + private: + void reserveCapacity(std::size_t newCapacity) + { + Vector tmpBuffer(newCapacity); + + SimpleCopy(*this, tmpBuffer); + + tmpBuffer.swap(*this); + } + void pushBackInternal(T const& value) + { + new (buffer + length) T(value); + ++length; + } + void moveBackInternal(T&& value) + { + new (buffer + length) T(std::move(value)); + ++length; + } + + template + // Note: this defines the return type of the function. + // But only one has a valid member `type` thus only + // one of the following functions is actually valid. + typename std::enable_if::value == false>::type + simpleCopy(Vector& src, Vector& dst) + { + std::for_each(buffer, buffer + length, + [&dst](T const& v){dst.pushBackInternal(v);} + ); + } + + template + typename std::enable_if::value == true>::type + simpleCopy()(Vector& src, Vector& dst) + { + std::for_each(buffer, buffer + length, + [&dst](T& v){dst.moveBackInternal(std::move(v));} + ); + } +} +``` + +# Final Version + +Vector Final Version +```c +template +class Vector +{ + std::size_t capacity; + std::size_t length; + T* buffer; + + struct Deleter + { + void operator()(T* buffer) const + { + ::operator delete(buffer); + } + }; + + public: + Vector(int capacity = 10) + : capacity(capacity) + , length(0) + , buffer(static_cast(::operator new(sizeof(T) * capacity))) + {} + ~Vector() + { + // Make sure the buffer is deleted even with exceptions + // This will be called to release the pointer at the end + // of scope. + std::unique_ptr deleter(buffer, Deleter()); + + // Call the destructor on all the members in reverse order + for(int loop = 0; loop < length; ++loop) + { + // Note we destroy the elements in reverse order. + buffer[length - 1 - loop].~T(); + } + } + Vector(Vector const& copy) + : capacity(copy.length) + , length(0) + , buffer(static_cast(::operator new(sizeof(T) * capacity))) + { + try + { + for(int loop = 0; loop < copy.length; ++loop) + { + push_back(copy.buffer[loop]); + } + } + catch(...) + { + std::unique_ptr deleter(buffer, Deleter()); + // If there was an exception then destroy everything + // that was created to make it exception safe. + for(int loop = 0; loop < length; ++loop) + { + buffer[length - 1 - loop].~T(); + } + + // Make sure the exceptions continue propagating after + // the cleanup has completed. + throw; + } + } + Vector& operator=(Vector const& copy) + { + // Copy and Swap idiom + Vector tmp(copy); + tmp.swap(*this); + return *this; + } + Vector(Vector&& move) noexcept + : capacity(0) + , length(0) + , buffer(nullptr) + { + move.swap(*this); + } + Vector& operator=(Vector&& move) noexcept + { + move.swap(*this); + return *this; + } + void swap(Vector& other) noexcept + { + using std::swap; + swap(capacity, other.capacity); + swap(length, other.length); + swap(buffer, other.buffer); + } + void push_back(T const& value) + { + resizeIfRequire(); + pushBackInternal(value); + } + void pop_back() + { + --length; + buffer[length].~T(); + } + void reserve(std::size_t capacityUpperBound) + { + if (capacityUpperBound > capacity) + { + reserveCapacity(capacityUpperBound); + } + } + private: + void resizeIfRequire() + { + if (length == capacity) + { + std::size_t newCapacity = std::max(2.0, capacity * 1.5); + reserveCapacity(newCapacity); + } + } + void reserveCapacity(std::size_t newCapacity) + { + Vector tmpBuffer(newCapacity); + + simpleCopy(tmpBuffer); + + tmpBuffer.swap(*this); + } + void pushBackInternal(T const& value) + { + new (buffer + length) T(value); + ++length; + } + void moveBackInternal(T&& value) + { + new (buffer + length) T(std::move(value)); + ++length; + } + + template + typename std::enable_if::value == false>::type + simpleCopy(Vector& dst) + { + std::for_each(buffer, buffer + length, + [&dst](T const& v){dst.pushBackInternal(v);} + ); + } + + template + typename std::enable_if::value == true>::type + simpleCopy(Vector& dst) + { + std::for_each(buffer, buffer + length, + [&dst](T& v){dst.moveBackInternal(std::move(v));} + ); + } +}; +``` + +# Summary +This article has gone over the design of resizing the internal buffer. We have covered a couple of techniques on the way: + +* Move Constructor Concepts +* Template Class Specialization +* SFINAE +* std::is_nothrow_move_constructible<> +* std::enable_if<> diff --git a/content/posts/Vector-ResourceManagementAllocation.md b/content/posts/Vector-ResourceManagementAllocation.md new file mode 100644 index 00000000..61177feb --- /dev/null +++ b/content/posts/Vector-ResourceManagementAllocation.md @@ -0,0 +1,427 @@ +--- +layout: post +title: "Vector - Resource Management Allocation" +date: 2016-02-27T12:00:31-0800 +author: Loki Astari, (C)2016 +comments: true +categories: ["C++", "Vector", "Resource-Management", "C++-By-Example", "Coding"] +series: Vector +tags: Vector +sharing: true +footer: true +subtitle: C++ By Example +description: C++ By Example. The Vector - Part 1. A lot of new developers to C++ attempt to build a `Vector` like container as a learning processes. Getting a simple version of this working for POD types (like int) is not that complicated. The next step in getting this working for arbitrary data types takes a significant leap forward in thinking in C++ especially when you start looking at efficiency and exception safety. This set of five articles looks at building an efficient `Vector` implementation. I show some of the common mistakes and explain why and how to resolve the problems. +image: /images/post/post-5.png +imageInfo: + original: https://unsplash.com/photos/W-oqNwbmin0 + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Oscar Nilsson + AttributionLink: https://unsplash.com/@oscrse +featured: true +draft: false +disqusId: "http://lokiastari.com/blog/2016/02/27/vector/" +--- + +A lot of new developers to C++ attempt to build a `Vector` like container as a learning processes. Getting a simple version of this working for POD types (like int) is not that complicated. The next step in getting this working for arbitrary data types takes a significant leap forward in thinking in C++ especially when you start looking at efficiency and exception safety. This set of five articles looks at building an efficient `Vector` implementation. I show some of the common mistakes and explain why and how to resolve the problems: + +Note: This is not meant to replace `std::vector<>` this is simply meant as a teaching process. + +# Rule of Zero + +You will notice that half the attempts below [Sources](#Sources) are Vector implementations the other half are for Matrix implementations. I mention both because I want to emphasize the [Separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns). An object should be responsible for either business logic or resource management (not both). A lot of the Matrix implementations are trying to mix resource management (memory management) with the business logic of how matrices interact. So if you want to write a matrix class you should delegate resource management to a separate class (In a first pass `std::vector` would be a good choice). + +In C++ the compiler generates a couple of methods for free. + +* Destructor +* Copy Constructor +* Copy Assignment Operator +* Move Constructor +* Move Assignment Operator + +These methods usually work perfectly well; **unless** your class contains a pointer (or a pointer like resource object). But if your class is doing business logic then it should not contain a pointer. So classes that handle business logic therefore should not be defining any of these compiler generated methods (just let the compiler generated ones work for you). Occasionally you want to delete them, to prevent copying or movement, but it is very unusual for these to need specialized implementations. + +Conversely, classes that do resource management usually contain a pointer (or pointer like resource object). These classes should define all the above methods to correctly handle the resource. This is where ownership semantics of the resource are defined. The owner of the resource is responsible for destroying the resource when its lifespan is over (in terms of pointers this means the owner is responsible for calling `delete` on the pointer, usually in the destructor). If you are not the owner of a resource you should not have access to the resource object directly, as it may be destroyed by the owner without other objects knowing. + +# [Rule of three](https://stackoverflow.com/q/4172722/14065) + +The rule of three comes from C++03 where we only had copy semantics. + +## Version-1 Simple Resource Management +When creating a class to manage resources; the first version created by beginner usually looks like this: + +Rule of three first pass +```c +template +class Vector +{ + std::size_t size; + T* buffer; + Vector(int size = 100) + : size(size) + , buffer(new T[size]) // Allocate the resource + {} + ~Vector() + { + delete [] buffer; // Clean up the resource + } +}; +``` +The trouble here is that this version has a fundamental flaw because of the way the [compiler generated](https://stackoverflow.com/a/4044360/14065) copy constructor and copy assignment operator work with pointers (commonly referred to as the [shallow copy problem](https://stackoverflow.com/q/2344664/14065)). + +Shallow copy problem. +```c +int main() +{ + Vector x; + Vector y(x); // Compiler generate copy constructure does + // an element wise shallow copy of each element. + // This means both `x` and `y` have a buffer + // member that points at the same area in memory. + // + // When the objects go out of scope both will + // try and call delete on the memory resulting + // in a double delete of the memory. + + Vector z; // Same problem after an assignment. + z=x; +} +``` + +## Version-2 Rule of Three +The rule of three simply stated is: If you define any of the methods Destructor/Copy Constructor/Copy Assignment Operator then you should define all three. When done correctly this resolves the shallow copy problem. `Vector` defines the destructor so we also need to define the copy constructor and copy assignment operator. + +I see this as an initial attempt at defining the rule of three for vectors very often. + +Rule of three second pass +```c +template +class Vector +{ + std::size_t size; + T* buffer; + Vector(int size = 100) + : size(size) + , buffer(new T[size]) + {} + ~Vector() + { + delete [] buffer; + } + Vector(Vector const& copy) + : size(copy.size) + , buffer(new T[size]) + { + // Copy constructor is simple. + // We create a new resource area of the required size. + // Then we copy the data from the old buffer to the new buffer. + std::copy(copy.buffer, copy.buffer + copy.size, buffer); + } + Vector& operator=(Vector const& copy) + { + // Copy Object + // This is relatively easy. But I want to cover this in detail in a subsquent post. + return *this; + } +}; +``` + +## Version-3 Lazy Construction of elements. + +The problem with the previous version is that it forces initialization of all elements in the buffer immediately. This forces the requirement that members of the `Vector` (i.e. type `T`) must be default constructable. It also has two efficiency constraints imposed on the Vector: + +* You can't pre-allocate space for future members. + + So resizing (larger or smaller) becomes very expensive as each resize requires copy all the elements to the newly re-sized buffer. + + Alternatively pre-creating all the elements you need can also be expensive especially if construction of `T` is expensive. +* The copy constructor is twice as expensive as it should be. Each element must be: + + Default constructed (when the buffer is created). + + Then copy constructed with the value from the source vector. + + +This attempt improves on that by allowing efficient pre-allocating of space (`capacity`) for the buffer. New members are then added by constructing in-place using [placement new](https://stackoverflow.com/questions/362953/what-are-uses-of-the-c-construct-placement-new). + +Rule of three third pass +```c +template +class Vector +{ + std::size_t capacity; + std::size_t length; + T* buffer; + Vector(int capacity) + : capacity(capacity = 100) + , length(0) + // Allocates space but does not call the constructor + , buffer(static_cast(::operator new(sizeof(T) * capacity))) + // Useful if the type T has an expensive constructor + // We preallocate space without initializing it giving + // room to grow and shrink the buffer without re-allocating. + {} + ~Vector() + { + // Because elements are constructed in-place using + // placement new. Then we must manually call the destructor + // on the elements. + for(int loop = 0; loop < length; ++loop) + { + // Note we destroy the elements in reverse order. + buffer[length - 1 - loop].~T(); + } + ::operator delete(buffer); + } + Vector(Vector const& copy) + : capacity(copy.length) + , length(0) + , buffer(static_cast(::operator new(sizeof(T) * capacity))) + { + // Copy constructor is simple. + // We create a new resource area of the required length. + // But these elements are not initialized so we use push_back to copy them + // into the new object. This is an improvement because we + // only construct the members of the vector once. + for(int loop = 0; loop < copy.length; ++loop) + { + push_back(copy.buffer[loop]); + } + } + Vector& operator=(Vector const& copy) + { + // Copy Object + // This is relatively easy. But I want to cover this in detail in a subsquent post. + return *this; + } + void push_back(T const& value) + { + // Use placement new to copy buffer into the new buffer + new (buffer + length) T(value); + ++length; + + // Note we will handle growing the capacity later. + } + void pop_back() + { + // When removing elements need to manually call the destructor + // because we created them using placement new. + --length; + buffer[length].~T(); + } +}; +``` + +# Rule of Five + +In C++11 the language added the concept of "Move Semantics". Rather than having to copy an object (especially on return from a function) we could "move" an object. The concept here is that movement is supposed to be much cheaper than copying because you move the internal data structure of an object rather than all the elements. A good example is a std::vector. Before C++11 a return by value meant copying the object. The constructor of the new object allocates a new internal buffer and then copies all the elements from the original object's buffer to the new object's buffer. On the other hand a move simply gives the new object the internal buffer of the old object (we just move the pointer to the internal buffer). When an object is moved to another object the old object should be left in a valid state, but for efficiency the standard rarely specifies the state of an object after it has been the source of a move. Thus using an object after a move is a bad idea unless you are setting it to a specific state. + +There are two new methods that allow us to specify move semantics on a class. + +Vector Move Semantics. +```c +class Vector +{ + std::size_t capacity; + std::size_t length; + T* buffer; + // STUFF + + // Move Constructor + Vector(Vector&& move) noexcept; + + // Move Assignment Operator + Vector& operator=(Vector&& move) noexcept; +}; +``` + +Notice the `&&` operator. This donates an r-value reference and means that your object is the destination of a move operation. The parameter passed is the source object and the state you should use to define your new object's state. After the move the source object must be left in a valid (but can be undefined state). For a vector this means it must no longer be the owner of the internal buffer that you are now using in your buffer. + +The simplest way to achieve this goal is to set up the object in a valid (but very cheap to achieve state) and then swap the current object with the destination object. + +Vector Move Semantics Implementation +```c +class Vector +{ + std::size_t capacity; + std::size_t length; + T* buffer; + // STUFF + + // Move Constructor + Vector(Vector&& move) noexcept + : capacity(0) + , length(0) + , buffer(nullptr) + { + // The source object now has a nullptr/ + // This object has taken the state of the source object. + move.swap(*this); + } + + // Move Assignment Operator + Vector& operator=(Vector&& move) noexcept + { + // In this case simply swap the source object + // and this object around. + move.swap(*this); + return *this; + } +}; +``` + +Note I marked both move operators `noexcept`. Assuming the operations are guaranteed not to throw you should mark them as `noexcept`. If we know that certain operations are exception safe, then we can optimize resize operations and maintain the strong exception guarantee. This and some other optimizations will be documented in a subsequent post. + +# Final Version + +Vector Final Version +```c +template +class Vector +{ + std::size_t capacity; + std::size_t length; + T* buffer; + + struct Deleter + { + void operator()(T* buffer) const + { + ::operator delete(buffer); + } + }; + + public: + Vector(int capacity = 10) + : capacity(capacity) + , length(0) + , buffer(static_cast(::operator new(sizeof(T) * capacity))) + {} + ~Vector() + { + // Make sure the buffer is deleted even with exceptions + // This will be called to release the pointer at the end + // of scope. + std::unique_ptr deleter(buffer, Deleter()); + + // Call the destructor on all the members in reverse order + for(int loop = 0; loop < length; ++loop) + { + // Note we destroy the elements in reverse order. + buffer[length - 1 - loop].~T(); + } + } + Vector(Vector const& copy) + : capacity(copy.length) + , length(0) + , buffer(static_cast(::operator new(sizeof(T) * capacity))) + { + try + { + for(int loop = 0; loop < copy.length; ++loop) + { + push_back(copy.buffer[loop]); + } + } + catch(...) + { + std::unique_ptr deleter(buffer, Deleter()); + // If there was an exception then destroy everything + // that was created to make it exception safe. + for(int loop = 0; loop < length; ++loop) + { + buffer[length - 1 - loop].~T(); + } + + // Make sure the exceptions continue propagating after + // the cleanup has completed. + throw; + } + } + Vector& operator=(Vector const& copy) + { + // Covered in Part 2 + return *this; + } + Vector(Vector&& move) noexcept + : capacity(0) + , length(0) + , buffer(nullptr) + { + move.swap(*this); + } + Vector& operator=(Vector&& move) noexcept + { + move.swap(*this); + return *this; + } + void swap(Vector& other) noexcept + { + using std::swap; + swap(capacity, other.capacity); + swap(length, other.length); + swap(buffer, other.buffer); + } + void push_back(T const& value) + { + resizeIfRequire(); + new (buffer + length) T(value); + ++length; + } + void pop_back() + { + --length; + buffer[length].~T(); + } + private: + void resizeIfRequire() + { + if (length == capacity) + { + // Covered in Part 2 + } + } +}; +``` +# Summary +This article has shown how to handle the basic resource management required by a vector. It has covered several important principles for C++ programmers. + +* Separation Of Concerns +* Rule of Zero +* Rule of Three +* Rule of Five +* Default compiler generated methods +* Shallow Copy Problem +* Placement New +* Exception Guarantees + +# Sources +Looking at [CodeReview.stackexchange.com](https://CodeReview.stackexchange.com); reimplementing the vector class is a common goal for a first project. + +* 2011/Nov/07 - [Mathematical Vector2 class implementation](https://codereview.stackexchange.com/q/5856/507)* +* 2012/May/21 - [C++ Vector2 Class Review](https://codereview.stackexchange.com/q/11934/507)* +* 2012/Aug/17 - [Templated Matrix class](https://codereview.stackexchange.com/q/14784/507) +* 2013/Jan/07 - [Vector implementation - simple replacement](https://codereview.stackexchange.com/q/20243/507) +* 2013/May/25 - [Review of 2d Vector class](https://codereview.stackexchange.com/q/26608/507) +* 2013/Jun/19 - [Simple matrix class](https://codereview.stackexchange.com/q/27573/507) +* 2013/Jun/21 - [Matrix and Vector4 classes](https://codereview.stackexchange.com/q/27625/507)* +* 2013/Jun/25 - [Simple matrix class - version 2](https://codereview.stackexchange.com/q/27752/507)* +* 2013/Aug/03 - [Template vector class](https://codereview.stackexchange.com/q/29331/507)* +* 2014/Feb/20 - [C++ vector implementation](https://codereview.stackexchange.com/q/42297/507) +* 2014/Mar/01 - [Reimplementation of C++ vector](https://codereview.stackexchange.com/q/43136/507) +* 2014/Mar/12 - [3D mathematical vector class](https://codereview.stackexchange.com/q/44167/507) +* 2014/May/17 - [Creating a custom Vector class](https://codereview.stackexchange.com/q/50975/507) +* 2014/Aug/19 - [STL vector implementation](https://codereview.stackexchange.com/q/60484/507) +* 2014/Sep/12 - [C++ 3D Vector Implementation](https://codereview.stackexchange.com/a/62774/507) +* 2014/Sep/26 - [Custom mathematical vector class](https://codereview.stackexchange.com/q/63970/507) +* 2014/Oct/19 - [Vector backed by memory pages](https://codereview.stackexchange.com/q/67209/507) +* 2014/Oct/31 - [Custom matrix class](https://codereview.stackexchange.com/q/68486/507) +* 2014/Nov/25 - [Vector/matrix class](https://codereview.stackexchange.com/q/70815/507) +* 2014/Dec/22 - [Vector implementation](https://codereview.stackexchange.com/q/74521/507) +* 2015/Feb/17 - [Mathematical matrices implementation](https://codereview.stackexchange.com/q/81751/507) +* 2015/Mar/01 - [C++ vector implementation errors](https://codereview.stackexchange.com/q/82906/507) +* 2015/Jun/20 - [Implementation of std::vector class](https://codereview.stackexchange.com/q/94211/507) +* 2015/Jul/08 - [Second implementation of std::vector](https://codereview.stackexchange.com/q/96253/507) +* 2015/Oct/17 - [Simple multi-dimensional Array class in C++11](https://codereview.stackexchange.com/q/107877/507) +* 2015/Oct/19 - [Creating n-dimensional mathematical vector classes through inheritance](https://codereview.stackexchange.com/q/108072/507) +* 2015/Oct/20 - [Implementation of Vector in C++](https://codereview.stackexchange.com/q/108140/507) +* 2015/Oct/23 - [Simple multi-dimensional Array class in C++11 - follow-up](https://codereview.stackexchange.com/q/108558/507) +* 2015/Nov/18 - [Custom vector that uses less memory than std::vector](https://codereview.stackexchange.com/q/111114/507) +* 2015/Nov/24 - [Attempt at templates by creating a class for N-dimensional mathematical vectors](https://codereview.stackexchange.com/q/111746/507) +* 2016/Jan/10 - [Vector Implementation C++](https://codereview.stackexchange.com/q/116377/507) diff --git a/content/posts/Vector-ResourceManagementCopySwap.md b/content/posts/Vector-ResourceManagementCopySwap.md new file mode 100644 index 00000000..2808a3b8 --- /dev/null +++ b/content/posts/Vector-ResourceManagementCopySwap.md @@ -0,0 +1,384 @@ +--- +layout: post +title: "Vector - Resource Management Copy Swap" +date: 2016-02-29T12:29:20-0800 +author: Loki Astari, (C)2016 +comments: true +categories: ["C++", "Vector", "Resource-Management", "C++-By-Example", "Coding"] +series: Vector +tags: Vector +sharing: true +footer: true +subtitle: C++ By Example +description: C++ By Example. The Vector Part 2. In the previous article I went over basic allocation for a `Vector` like class. In this article I want to put some detail around the copy assignment operator and resizing the underlying `Vector`. Unlike the other methods previously discussed these methods have to deal with both construction and destruction of elements and the potential of exceptions interrupting the processes. The goal is to provide exception safe methods that provide the strong exception guarantee for the object and do not leak resources. +image: /images/post/post-6.png +imageInfo: + original: https://unsplash.com/photos/Bj6ENZDMSDY + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Ben Griffiths + AttributionLink: https://unsplash.com/@benofthenorth +featured: true +draft: false +disqusId: "http://lokiastari.com/blog/2016/02/29/vector-resource-management-ii-copy-assignment/" +--- + +In the previous article I went over basic allocation for a `Vector` like class. In this article I want to put some detail around the copy assignment operator and resizing the underlying `Vector`. Unlike the other methods previously discussed these methods have to deal with both construction and destruction of elements and the potential of exceptions interrupting the processes. The goal is to provide exception safe methods that provide the strong exception guarantee for the object and do not leak resources. + +# Copy Assignment +## First Try +This is a very common first attempt at a copy constructor. +It simply calls the destructor on all elements currently in the object. Then uses the existing `push_back()` method to copy member elements from the source object, thus allowing the object to automatically resize if required. + +Copy Assignment (Try 1) +```c +class Vector +{ + std::size_t capacity; + std::size_t length; + T* buffer; + // STUFF + Vector& operator=(Vector const& copy) + { + if (© == this) + { + // Early exit for self assignment + return *this; + } + // First we have to destroy all the current elements. + for(int loop = 0; loop < length; ++loop) + { + // Destroy in reverse order + buffer[length - 1 - loop].~T(); + } + // Now the buffer is empty so reset size to zero. + length = 0; + + // Now copy all the elements from the source into this object + for(int loop = 0; loop < copy.length; ++loop) + { + push_back(copy.buffer[loop]); + } + return *this; + } +}; +``` + +## Strong Exception Guarantee +The obvious problems about efficiency when a resize is required is a minor issue here. The real problem is that this does not provide the strong exception guarantee. If any of the constructors/destructor throw then the object will be left in an inconsistent state with no way to restore the original state. The strong exception guarantee basically means that the operation works or does not change the state of the object. The easiest technique to achieve this is to create a copy in a new temporary buffer that can be thrown away if things go wrong (leaving the current object untouched). If the copy succeeds then we use it and throw away the original data. + +Copy Assignment (Try 2) +```c +class Vector +{ + std::size_t capacity; + std::size_t length; + T* buffer; + // STUFF + Vector& operator=(Vector const& copy) + { + if (© == this) + { + // Early exit for self assignment + return *this; + } + // Part-1 Create a copy of the src object. + std::size_t tmpCap = copy.length; + std::size_t tmpSize = 0; + T* tmpBuffer = static_cast(::operator new(sizeof(T) * tmpCap)); + + // Now copy all the elements from the source into the temporary object + for(int loop = 0; loop < copy.length; ++loop) + { + new (tmpBuffer + tmpSize) T(copy.buffer[loop]); + ++tmpSize; + } + + // Part-2 Swap the state + // We have successfully created the new version of this object + // So swap the temporary and object states. + std::swap(tmpCap, capacity); + std::swap(tmpSize, length); + std::swap(tmpBuffer, buffer); + + // Part-3 Destroy the old state. + // Now we have to delete the old state. + // If this fails it does not matter the state of the object is consistent + for(int loop = 0; loop < tmpSize; ++loop) + { + tmpBuffer[tmpSize - 1 - loop].~T(); + } + ::operator delete(tmpBuffer); + return *this; + } +}; +``` + +## Copy and Swap +This second attempt is a better attempt. But it still leaks if an exception is throw. But before we add exception handling, let us take a closer look at the three sections of the assignment operator. + +Part-1 looks exactly like the copy constructor of Vector. + +Copy Assignment Part 1 +```c + std::size_t tmpCap = copy.length; + std::size_t tmpSize = 0; + T* tmpBuffer = static_cast(::operator new(sizeof(T) * tmpCap)); + + // Now copy all the elements from the source into the temporary object + for(int loop = 0; loop < copy.length; ++loop) + { + // This looks exactly like push_back() + new (tmpBuffer + tmpSize) T(copy.buffer[loop]); + ++tmpSize; + } +``` + +Part-3 looks exactly like destructor of Vector. + +Copy Assignment Part 3 +```c + // Now we have to delete the old state. + for(int loop = 0; loop < tmpSize; ++loop) + { + tmpBuffer[tmpSize - 1 - loop].~T(); + } + ::operator delete(tmpBuffer); +``` + +Using these two observations we have a rewrite of the copy assignment operator. + +Copy Assignment (Try 3) +```c +class Vector +{ + std::size_t capacity; + std::size_t length; + T* buffer; + // STUFF + Vector& operator=(Vector const& copy) + { + if (© == this) + { + // Early exit for self assignment + return *this; + } + // Part-1 Create a copy + Vector tmp(copy); + + // Part-2 Swap the state + std::swap(tmp.capacity, capacity); + std::swap(tmp.length, length); + std::swap(tmp.buffer, buffer); + + return *this; + // Part-3 Destructor called at end of scope. + // No actual code required here. + } +}; +``` +## [Copy And Swap Idiom](https://stackoverflow.com/q/3279543/14065) + +The copy and swap idiom is about dealing with replacing an object state from another object. It is very commonly used in the copy assignment operator but has application whenever state is being changed and the [strong exception guarantee](https://en.wikipedia.org/wiki/Exception_safety) is required. + +The above code works perfectly. But in Part-2 the swap looks like a normal swap operation so let's use that rather than doing it manually. Also self assignment now works without the need for a test (because we are copying into a temporary). So we can remove the check for self assignment. Yes this does make the performance for self assignment worse, but it makes the normal operation even more efficient. Since the occurrence of self assignment is extremely rare I would not prematurely optimize for it but rather make the most common case the best optimized. So one final re-factor of the copy constructor leaves us with this. + +Copy Assignment (Try 4) +```c +class Vector +{ + std::size_t capacity; + std::size_t length; + T* buffer; + // STUFF + Vector& operator=(Vector const& copy) + { + Vector tmp(copy); + tmp.swap(*this); + return *this; + } + void swap(Vector& other) noexcept + { + std::swap(other.capacity, capacity); + std::swap(other.length, length); + std::swap(other.buffer, buffer); + } +}; +``` + +# Resizing Underlying buffer + +When pushing data into the array we need to verify that capacity has not been exceeded. If it has then we need to allocate more capacity then copy the current content into the new buffer and destroy the old buffer after calling the destructor on all elements. + +## Using Copy and Swap +This operation is exceedingly similar to the description of the copy assignment operator. As a result the best solution looks very similar and uses the Copy and Swap idiom. + +Vector Reallocating Buffer +```c +class Vector +{ + std::size_t capacity; + std::size_t length; + T* buffer; + // STUFF + void resizeIfRequire() + { + if (length == capacity) + { + // Create a temporary object with a larger capacity. + std::size_t newCapacity = std::max(2.0, capacity * 1.5); + Vector tmpBuffer(newCapacity); + + // Copy the state of this object into the new object. + std::for_each(buffer, buffer + length, [&tmpBuffer](T const& item){tmpBuffer.push_back(item);}); + + // All the work has been successfully done. So swap + // the state of the temporary and the current object. + tmpBuffer.swap(*this); + + // The temporary object goes out of scope here and + // tidies up the state that is no longer needed. + } + } +}; +``` + +# Final Version + +Vector Final Version +```c +template +class Vector +{ + std::size_t capacity; + std::size_t length; + T* buffer; + + struct Deleter + { + void operator()(T* buffer) const + { + ::operator delete(buffer); + } + }; + + public: + Vector(int capacity = 10) + : capacity(capacity) + , length(0) + , buffer(static_cast(::operator new(sizeof(T) * capacity))) + {} + ~Vector() + { + // Make sure the buffer is deleted even with exceptions + // This will be called to release the pointer at the end + // of scope. + std::unique_ptr deleter(buffer, Deleter()); + + // Call the destructor on all the members in reverse order + for(int loop = 0; loop < length; ++loop) + { + // Note we destroy the elements in reverse order. + buffer[length - 1 - loop].~T(); + } + } + Vector(Vector const& copy) + : capacity(copy.length) + , length(0) + , buffer(static_cast(::operator new(sizeof(T) * capacity))) + { + try + { + for(int loop = 0; loop < copy.length; ++loop) + { + push_back(copy.buffer[loop]); + } + } + catch(...) + { + std::unique_ptr deleter(buffer, Deleter()); + // If there was an exception then destroy everything + // that was created to make it exception safe. + for(int loop = 0; loop < length; ++loop) + { + buffer[length - 1 - loop].~T(); + } + + // Make sure the exceptions continue propagating after + // the cleanup has completed. + throw; + } + } + Vector& operator=(Vector const& copy) + { + // Copy and Swap idiom + Vector tmp(copy); + tmp.swap(*this); + return *this; + } + Vector(Vector&& move) noexcept + : capacity(0) + , length(0) + , buffer(nullptr) + { + move.swap(*this); + } + Vector& operator=(Vector&& move) noexcept + { + move.swap(*this); + return *this; + } + void swap(Vector& other) noexcept + { + using std::swap; + swap(capacity, other.capacity); + swap(length, other.length); + swap(buffer, other.buffer); + } + void push_back(T const& value) + { + resizeIfRequire(); + pushBackInternal(value); + } + void pop_back() + { + --length; + buffer[length].~T(); + } + void reserve(std::size_t capacityUpperBound) + { + if (capacityUpperBound > capacity) + { + reserveCapacity(capacityUpperBound); + } + } + private: + void resizeIfRequire() + { + if (length == capacity) + { + std::size_t newCapacity = std::max(2.0, capacity * 1.5); + reserveCapacity(newCapacity); + } + } + void pushBackInternal(T const& value) + { + new (buffer + length) T(value); + ++length; + } + void reserveCapacity(std::size_t newCapacity) + { + Vector tmpBuffer(newCapacity); + std::for_each(buffer, buffer + length, [&tmpBuffer](T const& v){tmpBuffer.pushBackInternal(v);}); + + tmpBuffer.swap(*this); + } +}; +``` + +# Summary +This article has gone over the design of the Copy and Swap idiom and shown how it is used in the Copy Assignment Operator and the resize operation. + +* Separation Of Concerns +* Copy and Swap Idiom +* Exception Gurantees diff --git a/content/posts/Vector-SimpleOptimizations.md b/content/posts/Vector-SimpleOptimizations.md new file mode 100644 index 00000000..2031430c --- /dev/null +++ b/content/posts/Vector-SimpleOptimizations.md @@ -0,0 +1,368 @@ +--- +layout: post +title: "Vector - Simple Optimizations" +date: 2016-03-19T15:06:40-0700 +author: Loki Astari, (C)2016 +comments: true +categories: ["C++", "Vector", "Resource-Management", "C++-By-Example", "Coding"] +series: Vector +tags: Vector +sharing: true +footer: true +subtitle: C++ By Example +description: C++ By Example. The Vector Part 4. We look at a couple of other types available in the template utility library that allow optimization via SFINAE. +image: /images/post/post-8.png +imageInfo: + original: https://unsplash.com/photos/oSvR0wGYUBs + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Matthew Brodeur + AttributionLink: https://unsplash.com/@mrbrodeur +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2016/03/19/vector-simple-optimizations/" +--- + +So now that we have used `std::is_nothrow_move_constructible` we can also look at a couple of other types available in the template utility library. + +# Optimized Destruction + +Since we have to manually call the destructor on all objects in the container (because we are using placement new) we can look to see if we can optimize that. The type `std::is_trivially_destructible` detects if the type is **Trivially** destructible. This basically means that there will be no side effects from the destructor (See: Section 12.4 Paragraph 5 of the standard). For types we don't need to call the destructor of the object. For the `Vector` class this means we can eliminate the call to the destructor but more importantly the loop. + +Destroying Elements +```c +~Vector() +{ + // STUFF.. + + // Call the destructor on all the members in reverse order + for(int loop = 0; loop < length; ++loop) + { + // Note we destroy the elements in reverse order. + buffer[length - 1 - loop].~T(); + } +} +Vector(Vector const& copy) + : capacity(copy.length) + , length(0) + , buffer(static_cast(::operator new(sizeof(T) * capacity))) +{ + try + { + // STUFF 1 ... + } + catch(...) + { + // STUFF 2 ... + // If there was an exception then destroy everything + // that was created to make it exception safe. + for(int loop = 0; loop < length; ++loop) + { + buffer[length - 1 - loop].~T(); + } + throw; + } +} +``` + +We can use the same SFINAE technique that we used in the previous article to remove the loops when the contained type is trivially destructible. + +```c +~Vector() +{ + // STUFF.. + clearElements(); +} +Vector(Vector const& copy) + : capacity(copy.length) + , length(0) + , buffer(static_cast(::operator new(sizeof(T) * capacity))) +{ + try + { + // STUFF 1 ... + } + catch(...) + { + // STUFF 2 ... + clearElements(); + throw; + } +} + +template +typename std::enable_if::value == false>::type +clearElements() +{ + // Call the destructor on all the members in reverse order + for(int loop = 0; loop < length; ++loop) + { + // Note we destroy the elements in reverse order. + buffer[length - 1 - loop].~T(); + } +} + +template +typename std::enable_if::value == true>::type +clearElements() +{ + // Trivially destructible objects can be re-used without using the destructor. +} +``` + +# Optimized Assignment Operator +The final optimization is because resource allocation is expensive. So if we can avoid the resource allocation completely and just reuse the space we currently have. + +Copy Assignment +```c +Vector& operator=(Vector const& copy) +{ + // Copy and Swap idiom + Vector tmp(copy); + tmp.swap(*this); + return *this; +} +``` + +The copy and swap idiom is perfect for providing the strong exception guarantee in the presence of exceptions. **But** if there are no exceptions during destruction or construction then we can potentially just reuse the available memory. So if we rewrote the assignment operator with the assumption that there were no exceptions it would look like the following (Note in the real code use SFINAE to do the optimization only when necessary). + +Copy the easy way +```c +Vector& operator=(Vector const& copy) +{ + // Check for self assignment + // As we are doing work anyway. + if (this == ©) + { + return *this; + } + + // If the length of the `copy` object exceeds + // the capacity of the current object then + // we have to do resource management. It costs + // nothing extra to use the copy and swap idiom + if (copy.length > capacity) + { + // Copy and Swap idiom + Vector tmp(copy); + tmp.swap(*this); + return *this; + } + + // The optimization happens here. + // We can reuse the buffer we already have. + clearElements(); // use clearElements() as it probably does very little. + length = 0; + + // Now add the elements to this container as cheaply as possible. + for(int loop = 0; loop < copy.length; ++loop) + { + pushBackInternal(copy[loop]); + } + return *this; +} +``` + +# Final Version + +The final version + +Vector Final Version +```c +template +class Vector +{ + std::size_t capacity; + std::size_t length; + T* buffer; + + struct Deleter + { + void operator()(T* buffer) const + { + ::operator delete(buffer); + } + }; + + public: + Vector(int capacity = 10) + : capacity(capacity) + , length(0) + , buffer(static_cast(::operator new(sizeof(T) * capacity))) + {} + ~Vector() + { + // Make sure the buffer is deleted even with exceptions + // This will be called to release the pointer at the end + // of scope. + std::unique_ptr deleter(buffer, Deleter()); + + clearElements(); + } + Vector(Vector const& copy) + : capacity(copy.length) + , length(0) + , buffer(static_cast(::operator new(sizeof(T) * capacity))) + { + try + { + for(int loop = 0; loop < copy.length; ++loop) + { + push_back(copy.buffer[loop]); + } + } + catch(...) + { + std::unique_ptr deleter(buffer, Deleter()); + clearElements(); + + // Make sure the exceptions continue propagating after + // the cleanup has completed. + throw; + } + } + Vector& operator=(Vector const& copy) + { + copyAssign(copy); + return *this; + } + Vector(Vector&& move) noexcept + : capacity(0) + , length(0) + , buffer(nullptr) + { + move.swap(*this); + } + Vector& operator=(Vector&& move) noexcept + { + move.swap(*this); + return *this; + } + void swap(Vector& other) noexcept + { + using std::swap; + swap(capacity, other.capacity); + swap(length, other.length); + swap(buffer, other.buffer); + } + void push_back(T const& value) + { + resizeIfRequire(); + pushBackInternal(value); + } + void pop_back() + { + --length; + buffer[length].~T(); + } + void reserve(std::size_t capacityUpperBound) + { + if (capacityUpperBound > capacity) + { + reserveCapacity(capacityUpperBound); + } + } + private: + void resizeIfRequire() + { + if (length == capacity) + { + std::size_t newCapacity = std::max(2.0, capacity * 1.5); + reserveCapacity(newCapacity); + } + } + void reserveCapacity(std::size_t newCapacity) + { + Vector tmpBuffer(newCapacity); + + simpleCopy(tmpBuffer); + + tmpBuffer.swap(*this); + } + void pushBackInternal(T const& value) + { + new (buffer + length) T(value); + ++length; + } + void moveBackInternal(T&& value) + { + new (buffer + length) T(std::move(value)); + ++length; + } + + template + typename std::enable_if::value == false>::type + simpleCopy(Vector& dst) + { + std::for_each(buffer, buffer + length, + [&dst](T const& v){dst.pushBackInternal(v);} + ); + } + + template + typename std::enable_if::value == true>::type + simpleCopy(Vector& dst) + { + std::for_each(buffer, buffer + length, + [&dst](T& v){dst.moveBackInternal(std::move(v));} + ); + } + + template + typename std::enable_if::value == false>::type + clearElements() + { + // Call the destructor on all the members in reverse order + for(int loop = 0; loop < length; ++loop) + { + // Note we destroy the elements in reverse order. + buffer[length - 1 - loop].~T(); + } + } + + template + typename std::enable_if::value == true>::type + clearElements() + { + // Trivially destructible objects can be reused without using the destructor. + } + + template + typename std::enable_if<(std::is_nothrow_copy_constructible::value + && std::is_nothrow_destructible::value) == true>::type + copyAssign(Vector& copy) + { + if (this == ©) + { + return; + } + + if (capacity <= copy.length) + { + clearElements(); + length = 0; + for(int loop = 0; loop < copy.length; ++loop) + { + pushBackInternal(copy[loop]); + } + } + else + { + // Copy and Swap idiom + Vector tmp(copy); + tmp.swap(*this); + } + } + template + typename std::enable_if<(std::is_nothrow_copy_constructible::value + && std::is_nothrow_destructible::value) == false>::type + copyAssign(Vector& copy) + { + // Copy and Swap idiom + Vector tmp(copy); + tmp.swap(*this); + } +}; +``` + +# Summary diff --git a/content/posts/Vector-TheOtherStuff.md b/content/posts/Vector-TheOtherStuff.md new file mode 100644 index 00000000..16bbc5b0 --- /dev/null +++ b/content/posts/Vector-TheOtherStuff.md @@ -0,0 +1,440 @@ +--- +layout: post +title: "Vector - The Other Stuff" +date: 2016-03-20T22:26:43-0700 +author: Loki Astari, (C)2016 +comments: true +categories: ["C++", "Vector", "C++-By-Example", "Coding"] +series: Vector +tags: Vector +sharing: true +footer: true +subtitle: C++ By Example +description: C++ By Example. The Vector Part 5. So the C++ standard specifies a set of requirements for containers. Very few requirements are specified in terms of containers so adhering to these exactly is not required (unless you want to be considered for the standard). But they provide an insight into what can be done with them and if you support them will allow your container to be more easily used with some features of the language and standard library. I am not going to go over all of them here (that is left as an exercise for the reader), but I will go over the ones I would expect to see in a simple implementation (the kind you would see in a university project). +image: /images/post/post-1.png +imageInfo: + original: https://unsplash.com/photos/g29arbbvPjo + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Possessed Photography + AttributionLink: https://unsplash.com/@possessedphotography +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2016/03/20/vector-the-other-stuff/" +--- + +So the C++ standard specifies a set of requirements for containers. Very few requirements are specified in terms of containers so adhering to these exactly is not required (unless you want to be considered for the standard). But they provide an insight into what can be done with them and if you support them will allow your container to be more easily used with some features of the language and standard library. I am not going to go over all of them here (that is left as an exercise for the reader), but I will go over the ones I would expect to see in a simple implementation (the kind you would see in a university project). + +For details see the [latest copy of the C++ standard](https://stackoverflow.com/a/4653479/14065). + +* 23.2.1 General container requirements [container.requirements.general] +* 23.2.3 Sequence containers [sequence.reqmts] + + +#### Internal Types +* value_type +* reference +* const_reference +* iterator +* const_iterator +* difference_type +* size_type + +It is worth specifying the internal types defined here. As this allows you to abstract the implementation details of the container. This will allow you to change the implementation details without users having to change their implementation; as long as the changes still provide the same interface but the interface to reference/pointers/iterators are relatively trivial and well defined. + +#### Constructors + +In C++11 the `std::initializer_list` was introduced. This allows a better list initialization syntax to be used with user defined types. Since this is usually defined in terms of the range based construction we should probably add both of these constructors. + +* Vector(std::initializer_list<T> const& list) +* Vector(I begin, I end) + +#### Iterators +* begin() +* rbegin() +* begin() const +* rbegin() const +* cbegin() const +* crbegin() const +* end() +* rend() +* end() const +* cend() const +* rend() const +* crend() const + +The iterators are relatively easy to write. They also allow the container to be used with the new range based for that was added in C++14. So this becomes another easy add. + +#### Member Access +* at(<index>) +* at(<index>) const +* operator[](<index>) +* operator[](<index>) const +* front() +* back() +* front() const +* back() const + +Member access to a vector should be very efficient. As a result normally range checks are not performed on member access, i.e. the user is expected to make sure that the method preconditions have been met before calling the method. This results in very efficient access to the members of a `Vector`. This is not normally a problem because index ranges are normally checked as part of a loop range as long as these are validated against the size of the array it does not need to be validated again. + +For Loop Vector Access +```c +Vector d = getData(); +for(int loop = 0; loop < d.size(); ++loop) +{ + std::cout << d[loop]; // No need for antoher range + // check here as we know that loop is inside the + // bounds of the vector d. +} +``` + +There is also the `at()` method which does validate the index provided before accessing the element (throwing an exception if the index is out of range). + + +#### Non-Mutating Member Functions +* size() const +* bool() const + +To allow us to check the preconditions on the element access methods we need some functions that check the state of the object. These are provided here. + +#### Mutating Member Functions +* push_back(<object-ref>) +* push_back(<object-rvalue-ref>) +* emplace_back(<args...>) +* pop_back() + +The following members are standard easy to implement methods of `std::vector` (O(1)) that I would expect to see in every implementation. + +The other mutating member functions are less trivial as they require elements to be moved around. They are not that hard but you must put some thought into the most efficient techniques to move elements (i.e. move or copy) and make sure that capacity is not exceeded by multiple inserts. As a result I would expect to see these methods only on an as needed basis. + +#### Comparators +* operator== const +* operator!= const + +Easy comparison operators. +Optionally you can provide the other comparison operators. + + +# Final +**No idea why Jackal is adding all the blank lines to my source** + +Vector +```c +#include +#include +#include +#include +#include + +template +class Vector +{ + public: + using value_type = T; + using reference = T&; + using const_reference = T const&; + using pointer = T*; + using const_pointer = T const*; + using iterator = T*; + using const_iterator = T const*; + using riterator = std::reverse_iterator; + using const_riterator = std::reverse_iterator; + using difference_type = std::ptrdiff_t; + using size_type = std::size_t; + + private: + size_type capacity; + size_type length; + T* buffer; + + struct Deleter + { + void operator()(T* buffer) const + { + ::operator delete(buffer); + } + }; + + public: + Vector(int capacity = 10) + : capacity(capacity) + , length(0) + , buffer(static_cast(::operator new(sizeof(T) * capacity))) + {} + template + Vector(I begin, I end) + : capacity(std::distance(begin, end)) + , length(0) + , buffer(static_cast(::operator new(sizeof(T) * capacity))) + { + for(auto loop = begin;loop != end; ++loop) + { + pushBackInternal(*loop); + } + } + Vector(std::initializer_list const& list) + : Vector(std::begin(list), std::end(list)) + {} + ~Vector() + { + // Make sure the buffer is deleted even with exceptions + // This will be called to release the pointer at the end + // of scope. + std::unique_ptr deleter(buffer, Deleter()); + clearElements(); + } + Vector(Vector const& copy) + : capacity(copy.length) + , length(0) + , buffer(static_cast(::operator new(sizeof(T) * capacity))) + { + try + { + for(int loop = 0; loop < copy.length; ++loop) + { + push_back(copy.buffer[loop]); + } + } + catch(...) + { + std::unique_ptr deleter(buffer, Deleter()); + clearElements(); + + // Make sure the exceptions continue propagating after + // the cleanup has completed. + throw; + } + } + Vector& operator=(Vector const& copy) + { + copyAssign(copy); + return *this; + } + Vector(Vector&& move) noexcept + : capacity(0) + , length(0) + , buffer(nullptr) + { + move.swap(*this); + } + Vector& operator=(Vector&& move) noexcept + { + move.swap(*this); + return *this; + } + void swap(Vector& other) noexcept + { + using std::swap; + swap(capacity, other.capacity); + swap(length, other.length); + swap(buffer, other.buffer); + } + + // Non-Mutating functions + size_type size() const {return length;} + bool empty() const {return length == 0;} + + // Validated element access + reference at(size_type index) {validateIndex(index);return buffer[index];} + const_reference at(size_type index) const {validateIndex(index);return buffer[index];} + + // Non-Validated element access + reference operator[](size_type index) {return buffer[index];} + const_reference operator[](size_type index) const {return buffer[index];} + reference front() {return buffer[0];} + const_reference front() const {return buffer[0];} + reference back() {return buffer[length - 1];} + const_reference back() const {return buffer[length - 1];} + + // Iterators + iterator begin() {return buffer;} + riterator rbegin() {return riterator(end());} + const_iterator begin() const {return buffer;} + const_riterator rbegin() const {return const_riterator(end());} + + iterator end() {return buffer + length;} + riterator rend() {return riterator(begin());} + const_iterator end() const {return buffer + length;} + const_riterator rend() const {return const_riterator(begin());} + + const_iterator cbegin() const {return begin();} + const_riterator crbegin() const {return rbegin();} + const_iterator cend() const {return end();} + const_riterator crend() const {return rend();} + + // Comparison + bool operator!=(Vector const& rhs) const {return !(*this == rhs);} + bool operator==(Vector const& rhs) const + { + return (size() == rhs.size()) + && std::equal(begin(), end(), rhs.begin()); + } + + // Mutating functions + void push_back(value_type const& value) + { + resizeIfRequire(); + pushBackInternal(value); + } + void push_back(value_type&& value) + { + resizeIfRequire(); + moveBackInternal(std::move(value)); + } + template + void emplace_back(Args&&... args) + { + resizeIfRequire(); + emplaceBackInternal(std::move(args)...); + } + void pop_back() + { + --length; + buffer[length].~T(); + } + void reserve(size_type capacityUpperBound) + { + if (capacityUpperBound > capacity) + { + reserveCapacity(capacityUpperBound); + } + } + private: + void validateIndex(size_type index) const + { + if (index >= length) + { + throw std::out_of_range("Out of Range"); + } + } + + void resizeIfRequire() + { + if (length == capacity) + { + size_type newCapacity = std::max(2.0, capacity * 1.5); + reserveCapacity(newCapacity); + } + } + void reserveCapacity(size_type newCapacity) + { + Vector tmpBuffer(newCapacity); + + simpleCopy(tmpBuffer); + + tmpBuffer.swap(*this); + } + + // Add new element to the end using placement new + void pushBackInternal(T const& value) + { + new (buffer + length) T(value); + ++length; + } + void moveBackInternal(T&& value) + { + new (buffer + length) T(std::move(value)); + ++length; + } + template + void emplaceBackInternal(Args&&... args) + { + new (buffer + length) T(std::move(args)...); + ++length; + } + + // Optimizations that use SFINAE to only instantiate one + // of two versions of a function. + // simpleCopy() Moves when no exceptions are guaranteed, otherwise copies. + // clearElements() When no destructor remove loop. + // copyAssign() Avoid resource allocation when no exceptions guaranteed. + // ie. When copying integers reuse the buffer if we can + // to avoid expensive resource allocation. + + template + typename std::enable_if::value == false>::type + simpleCopy(Vector& dst) + { + std::for_each(buffer, buffer + length, + [&dst](T const& v){dst.pushBackInternal(v);} + ); + } + template + typename std::enable_if::value == true>::type + simpleCopy(Vector& dst) + { + std::for_each(buffer, buffer + length, + [&dst](T& v){dst.moveBackInternal(std::move(v));} + ); + } + + + template + typename std::enable_if::value == false>::type + clearElements() + { + // Call the destructor on all the members in reverse order + for(int loop = 0; loop < length; ++loop) + { + // Note we destroy the elements in reverse order. + buffer[length - 1 - loop].~T(); + } + } + + template + typename std::enable_if::value == true>::type + clearElements() + { + // Trivially destructible objects can be reused without using the destructor. + } + + template + typename std::enable_if<(std::is_nothrow_copy_constructible::value + && std::is_nothrow_destructible::value) == true>::type + copyAssign(Vector& copy) + { + // This function is only used if there is no chance of an exception being + // thrown during destruction or copy construction of the type T. + + + // Quick return for self assignment. + if (this == ©) + { + return; + } + + if (capacity <= copy.length) + { + // If we have enough space to copy then reuse the space we currently + // have to avoid the need to perform an expensive resource allocation. + + clearElements(); // Potentially does nothing (see above) + // But if required will call the destructor of + // all elements. + + // buffer now ready to get a copy of the data. + length = 0; + for(int loop = 0; loop < copy.length; ++loop) + { + pushBackInternal(copy[loop]); + } + } + else + { + // Fallback to copy and swap if we need to more space anyway + Vector tmp(copy); + tmp.swap(*this); + } + } + + template + typename std::enable_if<(std::is_nothrow_copy_constructible::value + && std::is_nothrow_destructible::value) == false>::type + copyAssign(Vector& copy) + { + // Copy and Swap idiom + Vector tmp(copy); + tmp.swap(*this); + } +}; +``` diff --git a/content/posts/WanttosetupWordPresstowriteaboutProgramming.md b/content/posts/WanttosetupWordPresstowriteaboutProgramming.md new file mode 100644 index 00000000..abaedb98 --- /dev/null +++ b/content/posts/WanttosetupWordPresstowriteaboutProgramming.md @@ -0,0 +1,37 @@ +--- +layout: post +title: "Want to set up WordPress to write about Programming" +date: 2013-11-12T11:43:06-0800 +author: Loki Astari, (C)2012 +comments: true +categories: ["Blogging", "Coding", "Markup", "Markup Plugin", "WordPress"] +description: Setting up WordPress to display syntax highlighted code was a struggle due to different plugins that don’t all seem to work together, the different types of editor, etc. I don’t want to learn all about WordPress. I just want to write some simple articles. +image: /images/post/post-3.png +imageInfo: + original: https://unsplash.com/photos/d6dxQwmxV2Q + License: Unsplash License + LicenseLink: https://unsplash.com/license + Attribution: Ken Blode + AttributionLink: https://unsplash.com/@benkolde +featured: false +draft: false +disqusId: "http://lokiastari.com/blog/2013/11/12/want-to-set-up-wordpress-to-write-about-programming/" +--- + +Setting up WordPress to display syntax highlighted code was a struggle due to different plugins that don’t all seem to work together, the different types of editor, etc. I don’t want to learn all about WordPress. I just want to write some simple articles. + +I am at the point where I am productive and don’t destroy my articles accidentally by switching between Visual editor and Text editor, however, I am still not totally happy. Writing articles in pure HTML is not the best solution. Even with help buttons, this is the realm of the web developer that needs to lay out elements perfectly. The article writer (blogger) just needs text to flow and highlight with a smattering of subtle color. I would prefer some slightly higher level markup such as in `Stackoverflow` or `github` preferably. If you have worked through this problem and have a good solution, drop me a line. + +Here is a list of things I did to make myself productive: + +* Turn off the Visual Editor + Switching between the `visual` editor and the `text` editor always seems to destroy something in the code. What survived and what was mutated depended on the plugins but the result was always disastrous. Therefore turn it off. + Of course this means I am now writing in HTML (not perfect buy I can manage). + Goto `Users->Your Profile`. The first option allows you to disable the visual editor +* Install the plugins: + + Crayon Syntax Highlighter: + There are a lot of syntax highlighters out there. It does not matter which one you choose as they all seem to use the same back-end to do the coloring. This one worked for me. + + Preserve Code Formatting: + This prevents WordPress from mucking with the spaces between the <pre> tags. + + diff --git a/content/posts/post-1.md b/content/posts/post-1.md deleted file mode 100755 index 307323d5..00000000 --- a/content/posts/post-1.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "How to make toys from old Olarpaper" -date: 2022-04-04T01:00:00Z -image: /images/post/post-1.png -categories: ["programming"] -featured: true -draft: false ---- - -Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Covid-19 Situation - -Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -> Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -![alter-text](/images/post/post-1.png) -*Example Caption* - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! diff --git a/content/posts/post-10.md b/content/posts/post-10.md deleted file mode 100755 index 6dc75f38..00000000 --- a/content/posts/post-10.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "My work from home workstation" -date: 2022-04-04T10:00:00Z -image: /images/post/post-2.png -categories: ["programming"] -featured: false -draft: false ---- - -Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Covid-19 Situation - -Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -> Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -![alter-text](/images/post/post-1.png) -*Example Caption* - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! diff --git a/content/posts/post-11.md b/content/posts/post-11.md deleted file mode 100755 index 8ccb532f..00000000 --- a/content/posts/post-11.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "Robotic world is growing very fast" -date: 2022-04-04T11:00:00Z -image: /images/post/post-3.png -categories: ["assistance"] -featured: false -draft: false ---- - -Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Covid-19 Situation - -Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -> Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -![alter-text](/images/post/post-1.png) -*Example Caption* - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! diff --git a/content/posts/post-12.md b/content/posts/post-12.md deleted file mode 100755 index 8c82aafc..00000000 --- a/content/posts/post-12.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "What is a Virtual Assistant" -date: 2022-04-04T12:00:00Z -image: /images/post/post-4.png -categories: ["github"] -featured: true -draft: false ---- - -Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Covid-19 Situation - -Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -> Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -![alter-text](/images/post/post-1.png) -*Example Caption* - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! diff --git a/content/posts/post-13.md b/content/posts/post-13.md deleted file mode 100755 index 41bf2d8a..00000000 --- a/content/posts/post-13.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "Why you need to learn PHP" -date: 2022-04-04T13:00:00Z -image: /images/post/post-5.png -categories: ["youtube", "artificial-intelligence"] -featured: false -draft: false ---- - -Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Covid-19 Situation - -Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -> Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -![alter-text](/images/post/post-1.png) -*Example Caption* - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! diff --git a/content/posts/post-14.md b/content/posts/post-14.md deleted file mode 100755 index e1be2bd4..00000000 --- a/content/posts/post-14.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "What you need to know about Programming" -date: 2022-04-04T14:00:00Z -image: /images/post/post-6.png -categories: ["robotics", "youtube"] -featured: false -draft: false ---- - -Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Covid-19 Situation - -Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -> Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -![alter-text](/images/post/post-1.png) -*Example Caption* - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! diff --git a/content/posts/post-15.md b/content/posts/post-15.md deleted file mode 100755 index 4355e925..00000000 --- a/content/posts/post-15.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "How to make toys from old Olarpaper" -date: 2022-04-04T15:00:00Z -image: /images/post/post-7.png -categories: ["robotics", "assistance"] -featured: false -draft: false ---- - -Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Covid-19 Situation - -Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -> Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -![alter-text](/images/post/post-1.png) -*Example Caption* - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! diff --git a/content/posts/post-2.md b/content/posts/post-2.md deleted file mode 100755 index 8077dc0c..00000000 --- a/content/posts/post-2.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: My work from home workstation -date: 2022-04-04T02:00:00Z -image: /images/post/post-2.png -categories: ["drone"] -featured: true -draft: false ---- - -Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Covid-19 Situation - -Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -> Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -![alter-text](/images/post/post-1.png) -*Example Caption* - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! diff --git a/content/posts/post-3.md b/content/posts/post-3.md deleted file mode 100755 index c1b12253..00000000 --- a/content/posts/post-3.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: What you need to know about Photography -date: 2022-04-02T03:00:00+00:00 -image: /images/post/post-3.png -categories: ["workstation"] -featured: true -draft: false ---- - -Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Covid-19 Situation - -Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -> Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -![alter-text](/images/post/post-1.png) -*Example Caption* - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! diff --git a/content/posts/post-4.md b/content/posts/post-4.md deleted file mode 100755 index 18185ef1..00000000 --- a/content/posts/post-4.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "How to make toys from old Olarpaper" -date: 2022-04-04T04:00:00Z -image: /images/post/post-4.png -categories: ["robotics", "programming"] -featured: false -draft: false ---- - -Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Covid-19 Situation - -Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -> Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -![alter-text](/images/post/post-1.png) -*Example Caption* - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! diff --git a/content/posts/post-5.md b/content/posts/post-5.md deleted file mode 100755 index edf01b88..00000000 --- a/content/posts/post-5.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: "How to make toys from old Olarpaper" -date: 2022-04-04T05:00:00Z -image: /images/post/post-5.png -categories: ["assistance", "github"] -featured: true -draft: false ---- - -Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Covid-19 Situation - -Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -> Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Work From Home - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -![alter-text](/images/post/post-1.png) -*Example Caption* - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!quatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! diff --git a/content/posts/post-6.md b/content/posts/post-6.md deleted file mode 100755 index d01fbbd9..00000000 --- a/content/posts/post-6.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "How to make toys from old Olarpaper" -date: 2022-04-04T06:00:00Z -image: /images/post/post-6.png -categories: ["artificial-intelligence", "programming"] -featured: true -draft: false ---- - -Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Covid-19 Situation - -Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -> Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -![alter-text](/images/post/post-1.png) -*Example Caption* - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! diff --git a/content/posts/post-7.md b/content/posts/post-7.md deleted file mode 100755 index b3c7c1d0..00000000 --- a/content/posts/post-7.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "Artificial Intelligence and Robotics In A Nutshell" -date: 2022-04-04T07:00:00Z -image: /images/post/post-7.png -categories: ["programming", "youtube"] -featured: false -draft: false ---- - -Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Covid-19 Situation - -Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -> Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -![alter-text](/images/post/post-1.png) -*Example Caption* - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! diff --git a/content/posts/post-8.md b/content/posts/post-8.md deleted file mode 100755 index 9cd12c9c..00000000 --- a/content/posts/post-8.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "Drone Software and Development" -date: 2022-04-04T08:00:00Z -image: /images/post/post-8.png -categories: ["drone", "robotics"] -featured: true -draft: false ---- - -Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Covid-19 Situation - -Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -> Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -![alter-text](/images/post/post-1.png) -*Example Caption* - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! diff --git a/content/posts/post-9.md b/content/posts/post-9.md deleted file mode 100755 index 95cb072b..00000000 --- a/content/posts/post-9.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "Github Repository Controls" -date: 2022-04-04T09:00:00Z -image: /images/post/post-1.png -categories: ["workstation", "youtube"] -featured: false -draft: false ---- - -Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -## Covid-19 Situation - -Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. - -> Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! - -![alter-text](/images/post/post-1.png) -*Example Caption* - -Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! diff --git a/layouts/About.js b/layouts/About.js index b0576da9..36b5715f 100755 --- a/layouts/About.js +++ b/layouts/About.js @@ -29,36 +29,40 @@ const About = ({ data }) => {
-
-
- {markdownify(education.title, "h2", "section-title mb-12")} -
- {education.degrees.map((degree, index) => ( -
-

- {degree.university} -

-

{degree.content}

+ {education && ( +
+
+ {markdownify(education.title, "h2", "section-title mb-12")} +
+ {education.degrees.map((degree, index) => ( +
+

+ {degree.university} +

+

{degree.content}

+
+ ))}
- ))} -
-
-
-
-
- {markdownify(experience.title, "h2", "section-title mb-12")} -
    - {experience?.list?.map((item, index) => ( -
  • - {item} -
  • - ))} -
+
-
+ )} + {experience && ( +
+
+ {markdownify(experience.title, "h2", "section-title mb-12")} +
    + {experience?.list?.map((item, index) => ( +
  • + {item} +
  • + ))} +
+
+
+ )}
diff --git a/layouts/Baseof.js b/layouts/Baseof.js index 5e7d31fb..17c615e4 100755 --- a/layouts/Baseof.js +++ b/layouts/Baseof.js @@ -30,6 +30,7 @@ const Base = ({ {/* canonical url */} {canonical && } + {/* noindex robots */} {noindex && } diff --git a/layouts/PostSingle.js b/layouts/PostSingle.js index 96f7fd37..04cda9f9 100755 --- a/layouts/PostSingle.js +++ b/layouts/PostSingle.js @@ -1,4 +1,6 @@ import config from "@config/config.json"; +import React, { useContext, useRef, useEffect } from "react"; +import { MathJaxContext, MathJaxBaseContext } from "better-react-mathjax"; import Base from "@layouts/Baseof"; import InnerPagination from "@layouts/components/InnerPagination"; import dateFormat from "@lib/utils/dateFormat"; @@ -14,6 +16,27 @@ import Sidebar from "./partials/Sidebar"; import shortcodes from "./shortcodes/all"; const { disqus } = config; const { meta_author } = config.metadata; +const ThorMath = ({content}) => { + + const mjContext = useContext(MathJaxBaseContext); + const mathBlock = useRef(null); + + useEffect(() => { + if (mjContext && mathBlock.current) { + mjContext.promise.then((mathJax) => { + mathJax.startup.promise.then(() => { + mathJax.typesetClear([mathBlock.current]); + mathJax.typesetPromise([mathBlock.current]); + }); + }); + } + }); + + return ( +
$$ {content} $$
+ ); +}; +const components={shortcodes: shortcodes, ThorMath: ThorMath, MathJaxContext: MathJaxContext}; const PostSingle = ({ frontmatter, @@ -52,6 +75,11 @@ const PostSingle = ({ className="rounded-lg" /> )} + {frontmatter.imageInfo.Attribution && ( + + )}
    {categories.map((tag, index) => (
- +
- {config.settings.InnerPaginationOptions.enableBottom && ( + {config.settings.InnerPaginationOptions.enableBot && ( )} diff --git a/lib/utils/mdxParser.js b/lib/utils/mdxParser.js index 0af5060f..953bd6c1 100644 --- a/lib/utils/mdxParser.js +++ b/lib/utils/mdxParser.js @@ -1,12 +1,15 @@ import { serialize } from "next-mdx-remote/serialize"; -import rehypeSlug from "rehype-slug"; +//import rehypeSlug from "rehype-slug"; +import rehypeHighlight from "rehype-highlight"; +//import rehypeHighlight from "react-syntax-highlighter"; +//import HighlightedCode from "@layouts/shortcodes/Code"; import remarkGfm from "remark-gfm"; // mdx content parser const parseMDX = async (content) => { const options = { mdxOptions: { - rehypePlugins: [rehypeSlug], + rehypePlugins: [rehypeHighlight], // [rehypeSlug], remarkPlugins: [remarkGfm], }, }; diff --git a/next.config.js b/next.config.js index 5cfe45f4..eaf20878 100755 --- a/next.config.js +++ b/next.config.js @@ -2,8 +2,17 @@ * @type {import('next').NextConfig} */ + const nextConfig = { - reactStrictMode: true, + output: 'standalone', + rewrites: async () => { + return [ + { + source: "/Json/", + destination: "/Json/", + } + ] + }, }; module.exports = nextConfig; diff --git a/package.json b/package.json index 253d0733..468636b9 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "start": "next start" }, "dependencies": { + "better-react-mathjax": "^2.0.2", "disqus-react": "^1.1.5", "github-slugger": "^2.0.0", "gray-matter": "^4.0.3", @@ -26,6 +27,7 @@ "react-lite-youtube-embed": "^2.3.52", "react-mailchimp-subscribe": "^2.1.3", "react-syntax-highlighter": "^15.5.0", + "rehype-highlight": "^6.0.0", "rehype-slug": "^5.1.0", "remark-gfm": "^3.0.1" }, diff --git a/pages/all/index.js b/pages/all/index.js new file mode 100644 index 00000000..8fa03dc0 --- /dev/null +++ b/pages/all/index.js @@ -0,0 +1,46 @@ +import config from "@config/config.json"; +import Base from "@layouts/Baseof"; +import { humanize, markdownify } from "@lib/utils/textConverter"; +import Link from "next/link"; +const { blog_folder } = config.settings; +import { getSinglePage } from "@lib/contentParser"; +import { sortByDate } from "@lib/utils/sortFunctions"; + +const All = ({ posts }) => { + return ( + +
+ {markdownify( + "All Posts", + "h1", + "h2 mb-16 bg-theme-light dark:bg-darkmode-theme-dark py-12 text-center lg:text-[55px]" + )} +
+ {posts.map(post => ( +
+ + + {post.frontmatter.title} + + +
+ ))} +
+
+ + ); +}; + +export default All; + +export const getStaticProps = () => { + const posts = getSinglePage(`content/${blog_folder}`); + const sortedPosts = sortByDate(posts).reverse(); + return { + props: { + posts: sortedPosts, + }, + }; +}; diff --git a/pages/series/index.js b/pages/series/index.js new file mode 100644 index 00000000..7e565707 --- /dev/null +++ b/pages/series/index.js @@ -0,0 +1,67 @@ +import config from "@config/config.json"; +import Base from "@layouts/Baseof"; +import { getTaxonomy } from "@lib/taxonomyParser"; +import { humanize, markdownify } from "@lib/utils/textConverter"; +import Link from "next/link"; +const { blog_folder } = config.settings; +import { getSinglePage } from "@lib/contentParser"; +import { sortByDate } from "@lib/utils/sortFunctions"; +import { FaFolder } from "react-icons/fa"; +import { slugify } from "@lib/utils/textConverter"; + +const Categories = ({ series }) => { + return ( + +
+ {markdownify( + "Series", + "h1", + "h2 mb-16 bg-theme-light dark:bg-darkmode-theme-dark py-12 text-center lg:text-[55px]" + )} +
+ {series.map(aSeries => ( +
+
+ + {humanize(aSeries.name)} + +
+ {aSeries.posts.map(post => ( +
+ + + {post.frontmatter.title} + + +
+ ))} +
+ ))} +
+
+ + ); +}; + +export default Categories; + +export const getStaticProps = () => { + const posts = getSinglePage(`content/${blog_folder}`); + const series = getTaxonomy(`content/${blog_folder}`, "series"); + const seriesWithPosts = series.map((seriesName) => { + const filteredPosts = sortByDate(posts).filter(post => + slugify(post.frontmatter.series) == seriesName + ); + return { + name: seriesName, + posts: filteredPosts.reverse(), + }; + }); + return { + props: { + series: seriesWithPosts, + }, + }; +}; diff --git a/public/Json/Conformance.linux.html b/public/Json/Conformance.linux.html new file mode 100644 index 00000000..d68fddbd --- /dev/null +++ b/public/Json/Conformance.linux.html @@ -0,0 +1,3266 @@ + + + + + + + + + +
+ + +
+

Source CSV

+ +
+ +
+ + + + +
+
+ + diff --git a/public/Json/Conformance.osx.html b/public/Json/Conformance.osx.html new file mode 100644 index 00000000..330effef --- /dev/null +++ b/public/Json/Conformance.osx.html @@ -0,0 +1,3266 @@ + + + + + + + + + +
+ + +
+

Source CSV

+ +
+ +
+ + + + +
+ + + diff --git a/public/Json/Performance.linux.html b/public/Json/Performance.linux.html new file mode 100644 index 00000000..961e9344 --- /dev/null +++ b/public/Json/Performance.linux.html @@ -0,0 +1,722 @@ + + + + + + + + + +
+ + +
+

Source CSV

+ +
+ +
+ + + + +
+ + + diff --git a/public/Json/Performance.osx.html b/public/Json/Performance.osx.html new file mode 100644 index 00000000..cc452059 --- /dev/null +++ b/public/Json/Performance.osx.html @@ -0,0 +1,722 @@ + + + + + + + + + +
+ + +
+

Source CSV

+ +
+ +
+ + + + +
+ + + diff --git a/public/Json/Stats.html b/public/Json/Stats.html new file mode 100644 index 00000000..8278d48b --- /dev/null +++ b/public/Json/Stats.html @@ -0,0 +1,215 @@ + + + + + + + + + +
+ + +
+

Source CSV

+ +
+ +
+ + + + +
+ + + diff --git a/public/Json/combine.css b/public/Json/combine.css new file mode 100644 index 00000000..01132263 --- /dev/null +++ b/public/Json/combine.css @@ -0,0 +1,72 @@ + +.google-visualization-toolbar{font-size:100%}.google-visualization-toolbar .google-visualization-toolbar-export-igoogle,.google-visualization-toolbar .google-visualization-toolbar-export-data,.google-visualization-toolbar .google-visualization-toolbar-html-code{margin-right:.1em}.google-visualization-toolbar-html-code-explanation{font-weight:bold}.google-visualization-toolbar-ok-button{padding:2px}.google-visualization-toolbar-triangle{position:absolute;right:0;top:0}.google-visualization-toolbar-caption-table{width:100%;padding:0;margin:0;border:0;border-collapse:collapse}.google-visualization-toolbar-small-dialog{width:500px}.google-visualization-toolbar-big-dialog{width:800px}.google-visualization-toolbar-small-dialog,.google-visualization-toolbar-big-dialog{position:absolute;background-color:#c1d9ff;border:1px solid #3a5774;padding:8px}.google-visualization-toolbar-small-dialog-bg,.google-visualization-toolbar-big-dialog-bg{background-color:#ddd;position:absolute;top:0;left:0}.google-visualization-toolbar-small-dialog-title,.google-visualization-toolbar-big-dialog-title{background-color:#e0edfe;color:#000;cursor:pointer;padding:8px;position:relative;font-size:12pt;font-weight:bold;vertical-align:middle}.google-visualization-toolbar-small-dialog-content,.google-visualization-toolbar-big-dialog-content{background-color:#fff;padding:4px;font-weight:normal;overflow:auto}.google-visualization-toolbar-small-dialog-title-close,.google-visualization-toolbar-big-dialog-title-close{background:transparent url(close_box.gif) no-repeat scroll center;height:15px;position:absolute;right:10px;top:8px;width:15px}.google-visualization-toolbar-small-dialog-content iframe,.google-visualization-toolbar-big-dialog-content iframe{width:500px;height:700px;border:1px solid black}.charts-inline-block{position:relative;display:-moz-inline-box;display:inline-block}* html .charts-inline-block,*:first-child+html .charts-inline-block{display:inline}.charts-menu{background:#fff;border-color:#ccc #666 #666 #ccc;border-style:solid;border-width:1px;cursor:default;font:normal 13px Arial,sans-serif;margin:0;outline:none;padding:4px 0;position:absolute;z-index:20000}.charts-menu-button{background:#ddd url(//ssl.gstatic.com/editor/button-bg.png) repeat-x top left;border:0;color:#000;cursor:pointer;list-style:none;margin:2px;outline:none;padding:0;text-decoration:none;vertical-align:middle}.charts-menu-button-outer-box,.charts-menu-button-inner-box{border-style:solid;border-color:#aaa;vertical-align:top}.charts-menu-button-outer-box{margin:0;border-width:1px 0;padding:0}.charts-menu-button-inner-box{margin:0 -1px;border-width:0 1px;padding:3px 4px}* html .charts-menu-button-inner-box{left:-1px}* html .charts-menu-button-rtl .charts-menu-button-outer-box{left:-1px;right:auto}* html .charts-menu-button-rtl .charts-menu-button-inner-box{right:auto}*:first-child+html .charts-menu-button-inner-box{left:-1px}*:first-child+html .charts-menu-button-rtl .charts-menu-button-inner-box{left:1px;right:auto}::root .charts-menu-button{line-height:0}::root .charts-menu-button-outer-box{line-height:0}::root .charts-menu-button-inner-box{line-height:0}::root .charts-menu-button-caption{line-height:normal}::root .charts-menu-button-dropdown{line-height:normal}.charts-menu-button-disabled{background-image:none!important;opacity:.3;-moz-opacity:.3;filter:alpha(opacity=30)}.charts-menu-button-disabled .charts-menu-button-outer-box,.charts-menu-button-disabled .charts-menu-button-inner-box,.charts-menu-button-disabled .charts-menu-button-caption,.charts-menu-button-disabled .charts-menu-button-dropdown{color:#333!important;border-color:#999!important}* html .charts-menu-button-disabled,*:first-child+html .charts-menu-button-disabled{margin:2px 1px!important;padding:0 1px!important}.charts-menu-button-hover .charts-menu-button-outer-box,.charts-menu-button-hover .charts-menu-button-inner-box{border-color:#9cf #69e #69e #7af!important}.charts-menu-button-active,.charts-menu-button-open{background-color:#bbb;background-position:bottom left}.charts-menu-button-focused .charts-menu-button-outer-box,.charts-menu-button-focused .charts-menu-button-inner-box{border-color:orange}.charts-menu-button-caption{padding:0 4px 0 0;vertical-align:top}.charts-menu-button-dropdown{height:15px;width:7px;background:url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -388px 0;vertical-align:top}.charts-menu-button-collapse-right,.charts-menu-button-collapse-right .charts-menu-button-outer-box,.charts-menu-button-collapse-right .charts-menu-button-inner-box{margin-right:0}.charts-menu-button-collapse-left,.charts-menu-button-collapse-left .charts-menu-button-outer-box{margin-left:0}.charts-menu-button-collapse-left .charts-menu-button-inner-box{margin-left:0;border-left:1px solid #fff}.charts-menu-button-collapse-left.charts-menu-button-checked .charts-menu-button-inner-box{border-left:1px solid #ddd}.charts-menuitem{color:#000;font:normal 13px Arial,sans-serif;list-style:none;margin:0;padding:4px 7em 4px 28px;white-space:nowrap}.charts-menuitem.charts-menuitem-rtl{padding-left:7em;padding-right:28px}.charts-menu-nocheckbox .charts-menuitem,.charts-menu-noicon .charts-menuitem{padding-left:12px}.charts-menu-noaccel .charts-menuitem{padding-right:20px}.charts-menuitem-content{color:#000;font:normal 13px Arial,sans-serif}.charts-menuitem-disabled .charts-menuitem-accel,.charts-menuitem-disabled .charts-menuitem-content{color:#ccc!important}.charts-menuitem-disabled .charts-menuitem-icon{opacity:.3;-moz-opacity:.3;filter:alpha(opacity=30)}.charts-menuitem-highlight,.charts-menuitem-hover{background-color:#d6e9f8;border-color:#d6e9f8;border-style:dotted;border-width:1px 0;padding-bottom:3px;padding-top:3px}.charts-menuitem-checkbox,.charts-menuitem-icon{background-repeat:no-repeat;height:16px;left:6px;position:absolute;right:auto;vertical-align:middle;width:16px}.charts-menuitem-rtl .charts-menuitem-checkbox,.charts-menuitem-rtl .charts-menuitem-icon{left:auto;right:6px}.charts-option-selected .charts-menuitem-checkbox,.charts-option-selected .charts-menuitem-icon{background:url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -512px 0}.charts-menuitem-accel{color:#999;direction:ltr;left:auto;padding:0 6px;position:absolute;right:0;text-align:right}.charts-menuitem-rtl .charts-menuitem-accel{left:0;right:auto;text-align:left}.charts-menuitem-mnemonic-hint{text-decoration:underline}.charts-menuitem-mnemonic-separator{color:#999;font-size:12px;padding-left:4px} + +.charts-inline-block{position:relative;display:-moz-inline-box;display:inline-block}* html .charts-inline-block,*:first-child+html .charts-inline-block{display:inline}.charts-custom-button{margin:2px;border:0;padding:0;font-family:Arial,sans-serif;color:#000;background:#ddd url(//ssl.gstatic.com/editor/button-bg.png) repeat-x top left;text-decoration:none;list-style:none;vertical-align:middle;cursor:default;outline:none}.charts-custom-button-outer-box,.charts-custom-button-inner-box{border-style:solid;border-color:#aaa;vertical-align:top}.charts-custom-button-outer-box{margin:0;border-width:1px 0;padding:0}.charts-custom-button-inner-box{margin:0 -1px;border-width:0 1px;padding:3px 4px;white-space:nowrap}* html .charts-custom-button-inner-box{left:-1px}* html .charts-custom-button-rtl .charts-custom-button-outer-box{left:-1px}* html .charts-custom-button-rtl .charts-custom-button-inner-box{right:auto}*:first-child+html .charts-custom-button-inner-box{left:-1px}*:first-child+html .charts-custom-button-rtl .charts-custom-button-inner-box{left:1px}::root .charts-custom-button{line-height:0}::root .charts-custom-button-outer-box{line-height:0}::root .charts-custom-button-inner-box{line-height:normal}.charts-custom-button-disabled{background-image:none!important;opacity:.3;-moz-opacity:.3;filter:alpha(opacity=30)}.charts-custom-button-disabled .charts-custom-button-outer-box,.charts-custom-button-disabled .charts-custom-button-inner-box{color:#333!important;border-color:#999!important}* html .charts-custom-button-disabled,*:first-child+html .charts-custom-button-disabled{margin:2px 1px!important;padding:0 1px!important}.charts-custom-button-hover .charts-custom-button-outer-box,.charts-custom-button-hover .charts-custom-button-inner-box{border-color:#9cf #69e #69e #7af!important}.charts-custom-button-active,.charts-custom-button-checked{background-color:#bbb;background-position:bottom left}.charts-custom-button-focused .charts-custom-button-outer-box,.charts-custom-button-focused .charts-custom-button-inner-box{border-color:orange}.charts-custom-button-collapse-right,.charts-custom-button-collapse-right .charts-custom-button-outer-box,.charts-custom-button-collapse-right .charts-custom-button-inner-box{margin-right:0}.charts-custom-button-collapse-left,.charts-custom-button-collapse-left .charts-custom-button-outer-box{margin-left:0}.charts-custom-button-collapse-left .charts-custom-button-inner-box{margin-left:0;border-left:1px solid #fff}.charts-custom-button-collapse-left.charts-custom-button-checked .charts-custom-button-inner-box{border-left:1px solid #ddd}* html .charts-custom-button-collapse-left .charts-custom-button-inner-box,*:first-child+html .charts-custom-button-collapse-left .charts-custom-button-inner-box{left:0}.charts-flat-button{position:relative;margin:2px;border:1px solid #000;padding:2px 6px;font:normal 13px "Trebuchet MS",Tahoma,Arial,sans-serif;color:#fff;background-color:#8c2425;cursor:pointer;outline:none}.charts-flat-button-disabled{border-color:#888;color:#888;background-color:#ccc;cursor:default}.charts-flat-button-hover{border-color:#8c2425;color:#8c2425;background-color:#eaa4a5}.charts-flat-button-active,.charts-flat-button-selected,.charts-flat-button-checked{border-color:#5b4169;color:#5b4169;background-color:#d1a8ea}.charts-flat-button-focused{border-color:#5b4169}.charts-flat-button-collapse-right{margin-right:0}.charts-flat-button-collapse-left{margin-left:0;border-left:none}.charts-button{color:#036;border-color:#036;background-color:#69c}.charts-button-disabled{border-color:#333;color:#333;background-color:#999}.charts-button-hover{color:#369;border-color:#369;background-color:#9cf}.charts-button-active{color:#69c;border-color:#69c}.google-visualization-table-table{font-family:arial,helvetica;font-size:10pt;cursor:default;margin:0;background:white;border-spacing:0}.google-visualization-table-table *{margin:0;vertical-align:middle;padding:2px}.google-visualization-table-tr-head .gradient,.google-visualization-table-tr-head-nonstrict .gradient,.google-visualization-table-div-page .gradient{background:#fff url("//ssl.gstatic.com/charts/static/table-title-bg.gif") repeat-x left bottom;background:-moz-linear-gradient(top,rgba(255,255,255,1) 0%,rgba(249,250,253,1) 30%,rgba(238,242,247,1) 60%,rgba(228,233,244,1) 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,rgba(255,255,255,1)),color-stop(30%,rgba(249,250,253,1)),color-stop(60%,rgba(238,242,247,1)),color-stop(100%,rgba(228,233,244,1)));background:-webkit-linear-gradient(top,rgba(255,255,255,1) 0%,rgba(249,250,253,1) 30%,rgba(238,242,247,1) 60%,rgba(228,233,244,1) 100%);background:-o-linear-gradient(top,rgba(255,255,255,1) 0%,rgba(249,250,253,1) 30%,rgba(238,242,247,1) 60%,rgba(228,233,244,1) 100%);background:-ms-linear-gradient(top,rgba(255,255,255,1) 0%,rgba(249,250,253,1) 30%,rgba(238,242,247,1) 60%,rgba(228,233,244,1) 100%);background:linear-gradient(to bottom,rgba(255,255,255,1) 0%,rgba(249,250,253,1) 30%,rgba(238,242,247,1) 60%,rgba(228,233,244,1) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff',endColorstr='#e4e9f4',GradientType=0)}.google-visualization-table-tr-head,.google-visualization-table-tr-head-nonstrict{font-weight:bold;text-align:center}.google-visualization-table-tr-even,.google-visualization-table-tr-even-nonstrict{background-color:#fff}.google-visualization-table-tr-odd,.google-visualization-table-tr-odd-nonstrict{background-color:#fafafa}.google-visualization-table-tr-sel,.google-visualization-table-tr-sel-nonstrict{background-color:#d6e9f8}.google-visualization-table-tr-over,.google-visualization-table-tr-over-nonstrict{background-color:#e7e9f9}.google-visualization-table-sorthdr{cursor:pointer}.google-visualization-table-table .unsorted .google-visualization-table-sortind:after{content:"\002003"}.google-visualization-table-table .sort-ascending .google-visualization-table-sortind:after{content:"\0025b2"}.google-visualization-table-table .sort-descending .google-visualization-table-sortind:after{content:"\0025bc"}.google-visualization-table-sortind{color:#ccc;font-size:9px;padding-left:6px}.google-visualization-table-th,.google-visualization-table-td{border:1px solid #eee;padding-right:3px;padding-left:3px;padding-top:2px;padding-bottom:2px}.google-visualization-table-table .last-frozen-cell{border-right:2px ridge}.google-visualization-table-td-bool{text-align:center;font-family:"Arial Unicode MS",Arial,Helvetica}.google-visualization-table-td-center{text-align:center}.google-visualization-table-td-number{text-align:right;white-space:nowrap}.google-visualization-table-seq{text-align:right;color:#666}.google-visualization-table-div-page{margin:2px 0 0;padding:0;border:0;display:inline-block;float:left}.google-visualization-table-div-page [role="button"]{display:inline-block;cursor:pointer}.google-visualization-table-page-numbers{display:inline-block;margin:2px 0;padding:0}.google-visualization-table-page-numbers .page-number{display:inline-block;border:1px ButtonShadow outset;border-radius:3px;color:black;font-size:.8em;line-height:.9em;min-width:1.5em;margin:2px .25em;padding:.15em .3em .2em .25em;text-align:center;text-decoration:none}.google-visualization-table-page-numbers .page-number.current{font-weight:bold}.google-visualization-table-page-numbers .page-number:hover{background:#fefefe;border-color:#fefefe}.google-visualization-table .transparent{background-image:none;background-color:transparent;border-color:transparent}.google-visualization-table .transparentIE6{background:none}.google-visualization-table th .transparent,.google-visualization-table td .transparent{color:transparent;opacity:0}.google-visualization-table .google-visualization-hidden{visibility:hidden;pointer-events:none}.google-visualization-table-loadtest{padding-left:6px} +/* Copyright 2012 Google Inc. All Rights Reserved. */ + +.google-visualization-tooltip-action: hover { + background-color: #eeeeee; +} +.google-visualization-tooltip { + border:solid 1px #bdbdbd; + border-radius: 2px; + background-color: white; + position: absolute; + box-shadow: 0px 2px 2px 0px rgba(204, 204, 204, 0.6); + font-size: 12px; + padding: 0px; + -moz-box-shadow: 0px 2px 2px 0px rgba(204, 204, 204, 0.6); + -webkit-box-shadow: 0px 2px 2px 0px rgba(204, 204, 204, 0.6); +} +.google-visualization-tooltip-action-list { + list-style-type: none; + margin: 0; + padding: 0.5em 0em 0.5em 0em; + cursor: hand; +} +.google-visualization-tooltip-action { + margin: 0; + cursor: pointer; + padding: 0.5em 2em 0.5em 1em; +} +.google-visualization-tooltip-action:hover { + background-color: #eeeeee; +} +.google-visualization-tooltip-item-list { + list-style-type: none; + margin: 1em 0 1em 0; + padding: 0em; +} +.google-visualization-tooltip-item { + margin: 0.65em 0em 0.65em 0em; + padding: 0em 2em 0em 1em; +} +.google-visualization-tooltip-item-list +.google-visualization-tooltip-item:first-child { + margin: 1em 0em 1em 0em; +} +.google-visualization-tooltip-separator { + margin: 0; + padding: 0; + height: 1px; + background-color: #dddddd; +} +.google-visualization-tooltip-square { + display: inline-block; + /* IE does not support inline-block fall back to float left */ + float: left\9; + clear: none; + width: 0.5em; + height: 0.5em; + margin: 0.16em 0.7em 0em 0em; + border-bottom: solid 0.1em white; +} +/*! + * Bootstrap v3.2.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.1 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(glyphicons-halflings-regular.eot);src:url(glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(glyphicons-halflings-regular.woff) format('woff'),url(glyphicons-halflings-regular.ttf) format('truetype'),url(glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:before,:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;width:100% \9;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;width:100% \9;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:400;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}mark,.mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#428bca}a.text-primary:hover{color:#3071a9}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=radio],input[type=checkbox]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#777;opacity:1}.form-control:-ms-input-placeholder{color:#777}.form-control::-webkit-input-placeholder{color:#777}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px;line-height:1.42857143 \0}input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;min-height:20px;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.radio input[type=radio],.radio-inline input[type=radio],.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox]{position:absolute;margin-top:4px \9;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type=radio][disabled],input[type=checkbox][disabled],input[type=radio].disabled,input[type=checkbox].disabled,fieldset[disabled] input[type=radio],fieldset[disabled] input[type=checkbox]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm,.form-horizontal .form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.input-lg,.form-horizontal .form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg,select[multiple].input-lg{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:25px;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type=radio],.form-inline .checkbox input[type=checkbox]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{top:0;right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.3px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn:focus,.btn:active:focus,.btn.active:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#3071a9;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#777}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn>input[type=radio],[data-toggle=buttons]>.btn>input[type=checkbox]{position:absolute;z-index:-1;filter:alpha(opacity=0);opacity:0}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=radio],.input-group-addon input[type=checkbox]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;-webkit-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type=radio],.navbar-form .checkbox input[type=checkbox]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#333}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#777}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#777}.navbar-inverse .navbar-nav>li>a{color:#777}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#777}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#777}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#fff}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#428bca;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:hover,.label-default[href]:focus{background-color:#5e5e5e}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar[aria-valuenow="1"],.progress-bar[aria-valuenow="2"]{min-width:30px}.progress-bar[aria-valuenow="0"]{min-width:30px;color:#777;background-color:transparent;background-image:none;-webkit-box-shadow:none;box-shadow:none}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{color:#777;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#428bca}.panel-primary>.panel-heading .badge{color:#428bca;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate3d(0,-25%,0);-o-transform:translate3d(0,-25%,0);transform:translate3d(0,-25%,0)}.modal.in .modal-dialog{-webkit-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-size:12px;line-height:1.4;visibility:visible;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{display:table;content:" "}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed;-webkit-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none!important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}/*! + * Bootstrap v3.2.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default:disabled,.btn-default[disabled]{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-o-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#2d6ca2));background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-primary:disabled,.btn-primary[disabled]{background-color:#2d6ca2;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-success:disabled,.btn-success[disabled]{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-info:disabled,.btn-info[disabled]{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-warning:disabled,.btn-warning[disabled]{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-danger:disabled,.btn-danger[disabled]{background-color:#c12e2a;background-image:none}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f3f3f3));background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:-o-linear-gradient(top,#222 0,#282828 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#222),to(#282828));background-image:linear-gradient(to bottom,#222 0,#282828 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-o-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3071a9));background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-o-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3278b3));background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);background-repeat:repeat-x;border-color:#3278b3}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} diff --git a/public/Json/combine.js b/public/Json/combine.js new file mode 100644 index 00000000..06643683 --- /dev/null +++ b/public/Json/combine.js @@ -0,0 +1,11995 @@ +/*! + * jQuery JavaScript Library v1.8.2 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: Thu Sep 20 2012 21:13:05 GMT-0400 (Eastern Daylight Time) + */ +(function( window, undefined ) { +var + // A central reference to the root jQuery(document) + rootjQuery, + + // The deferred used on DOM ready + readyList, + + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + location = window.location, + navigator = window.navigator, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // Save a reference to some core methods + core_push = Array.prototype.push, + core_slice = Array.prototype.slice, + core_indexOf = Array.prototype.indexOf, + core_toString = Object.prototype.toString, + core_hasOwn = Object.prototype.hasOwnProperty, + core_trim = String.prototype.trim, + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Used for matching numbers + core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source, + + // Used for detecting and trimming whitespace + core_rnotwhite = /\S/, + core_rspace = /\s+/, + + // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE) + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, + rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + + // The ready event handler and self cleanup method + DOMContentLoaded = function() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + } else if ( document.readyState === "complete" ) { + // we're here because readyState === "complete" in oldIE + // which is good enough for us to call the dom ready! + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = ( context && context.nodeType ? context.ownerDocument || context : document ); + + // scripts is true for back-compat + selector = jQuery.parseHTML( match[1], doc, true ); + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + this.attr.call( selector, context, true ); + } + + return jQuery.merge( this, selector ); + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.8.2", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return core_slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; + }, + + eq: function( i ) { + i = +i; + return i === -1 ? + this.slice( i ) : + this.slice( i, i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( core_slice.apply( this, arguments ), + "slice", core_slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: core_push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger("ready").off("ready"); + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ core_toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !core_hasOwn.call(obj, "constructor") && + !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || core_hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + // data: string of html + // context (optional): If specified, the fragment will be created in this context, defaults to document + // scripts (optional): If true, will include scripts passed in the html string + parseHTML: function( data, context, scripts ) { + var parsed; + if ( !data || typeof data !== "string" ) { + return null; + } + if ( typeof context === "boolean" ) { + scripts = context; + context = 0; + } + context = context || document; + + // Single tag + if ( (parsed = rsingleTag.exec( data )) ) { + return [ context.createElement( parsed[1] ) ]; + } + + parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] ); + return jQuery.merge( [], + (parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes ); + }, + + parseJSON: function( data ) { + if ( !data || typeof data !== "string") { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + var xml, tmp; + if ( !data || typeof data !== "string" ) { + return null; + } + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && core_rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var name, + i = 0, + length = obj.length, + isObj = length === undefined || jQuery.isFunction( obj ); + + if ( args ) { + if ( isObj ) { + for ( name in obj ) { + if ( callback.apply( obj[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( obj[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in obj ) { + if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) { + break; + } + } + } + } + + return obj; + }, + + // Use native String.trim function wherever possible + trim: core_trim && !core_trim.call("\uFEFF\xA0") ? + function( text ) { + return text == null ? + "" : + core_trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var type, + ret = results || []; + + if ( arr != null ) { + // The window, strings (and functions) also have 'length' + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + type = jQuery.type( arr ); + + if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) { + core_push.call( ret, arr ); + } else { + jQuery.merge( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( core_indexOf ) { + return core_indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var l = second.length, + i = first.length, + j = 0; + + if ( typeof l === "number" ) { + for ( ; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var retVal, + ret = [], + i = 0, + length = elems.length; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, + ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = core_slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context, args.concat( core_slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + // Multifunctional method to get and set values of a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, pass ) { + var exec, + bulk = key == null, + i = 0, + length = elems.length; + + // Sets many values + if ( key && typeof key === "object" ) { + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); + } + chainable = 1; + + // Sets one value + } else if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = pass === undefined && jQuery.isFunction( value ); + + if ( bulk ) { + // Bulk operations only iterate when executing function values + if ( exec ) { + exec = fn; + fn = function( elem, key, value ) { + return exec.call( jQuery( elem ), value ); + }; + + // Otherwise they run against the entire set + } else { + fn.call( elems, value ); + fn = null; + } + } + + if ( fn ) { + for (; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + } + + chainable = 1; + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + } +}); + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready, 1 ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch(e) {} + + if ( top && top.doScroll ) { + (function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll("left"); + } catch(e) { + return setTimeout( doScrollCheck, 50 ); + } + + // and execute any waiting functions + jQuery.ready(); + } + })(); + } + } + } + return readyList.promise( obj ); +}; + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.split( core_rspace ), function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" && ( !options.unique || !self.has( arg ) ) ) { + list.push( arg ); + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Control if a given callback is in the list + has: function( fn ) { + return jQuery.inArray( fn, list ) > -1; + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( list && ( !fired || stack ) ) { + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var action = tuple[ 0 ], + fn = fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ]( jQuery.isFunction( fn ) ? + function() { + var returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + } : + newDefer[ action ] + ); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] = list.fire + deferred[ tuple[0] ] = list.fire; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = core_slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; + if( values === progressValues ) { + deferred.notifyWith( contexts, values ); + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); +jQuery.support = (function() { + + var support, + all, + a, + select, + opt, + input, + fragment, + eventName, + i, + isSupported, + clickFn, + div = document.createElement("div"); + + // Preliminary tests + div.setAttribute( "className", "t" ); + div.innerHTML = "
a"; + + all = div.getElementsByTagName("*"); + a = div.getElementsByTagName("a")[ 0 ]; + a.style.cssText = "top:1px;float:left;opacity:.5"; + + // Can't get basic test support + if ( !all || !all.length ) { + return {}; + } + + // First batch of supports tests + select = document.createElement("select"); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName("input")[ 0 ]; + + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute("href") === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.5/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Tests for enctype support on a form(#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode + boxModel: ( document.compatMode === "CSS1Compat" ), + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true, + boxSizingReliable: true, + pixelPosition: false + }; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", clickFn = function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent("onclick"); + div.detachEvent( "onclick", clickFn ); + } + + // Check if a radio maintains its value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute( "type", "radio" ); + support.radioValue = input.value === "t"; + + input.setAttribute( "checked", "checked" ); + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.lastChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + fragment.removeChild( input ); + fragment.appendChild( div ); + + // Technique from Juriy Zaytsev + // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for ( i in { + submit: true, + change: true, + focusin: true + }) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + // Run tests that need a body at doc ready + jQuery(function() { + var container, div, tds, marginDiv, + divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;", + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + container = document.createElement("div"); + container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px"; + body.insertBefore( container, body.firstChild ); + + // Construct the test element + div = document.createElement("div"); + container.appendChild( div ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + div.innerHTML = "
t
"; + tds = div.getElementsByTagName("td"); + tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE <= 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check box-sizing and margin behavior + div.innerHTML = ""; + div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; + support.boxSizing = ( div.offsetWidth === 4 ); + support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); + + // NOTE: To any future maintainer, we've window.getComputedStyle + // because jsdom on node.js will break without it. + if ( window.getComputedStyle ) { + support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; + support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + marginDiv = document.createElement("div"); + marginDiv.style.cssText = div.style.cssText = divReset; + marginDiv.style.marginRight = marginDiv.style.width = "0"; + div.style.width = "1px"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); + } + + if ( typeof div.style.zoom !== "undefined" ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.innerHTML = ""; + div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = "block"; + div.style.overflow = "visible"; + div.innerHTML = "
"; + div.firstChild.style.width = "5px"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + + container.style.zoom = 1; + } + + // Null elements to avoid leaks in IE + body.removeChild( container ); + container = div = tds = marginDiv = null; + }); + + // Null elements to avoid leaks in IE + fragment.removeChild( div ); + all = a = select = opt = input = fragment = div = null; + + return support; +})(); +var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, + rmultiDash = /([A-Z])/g; + +jQuery.extend({ + cache: {}, + + deletedIds: [], + + // Remove at next major release (1.9/2.0) + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ internalKey ] = id = jQuery.deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, l, + + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split(" "); + } + } + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + } else if ( jQuery.support.deleteExpando || cache != cache.window ) { + delete cache[ id ]; + + // When all else fails, null + } else { + cache[ id ] = null; + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; + + // nodes accept data unless otherwise specified; rejection can be conditional + return !noData || noData !== true && elem.getAttribute("classid") === noData; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var parts, part, attr, name, l, + elem = this[0], + i = 0, + data = null; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attr = elem.attributes; + for ( l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( !name.indexOf( "data-" ) ) { + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( elem, name, data[ name ] ); + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + parts = key.split( ".", 2 ); + parts[1] = parts[1] ? "." + parts[1] : ""; + part = parts[1] + "!"; + + return jQuery.access( this, function( value ) { + + if ( value === undefined ) { + data = this.triggerHandler( "getData" + part, [ parts[0] ] ); + + // Try to fetch any internally stored data first + if ( data === undefined && elem ) { + data = jQuery.data( elem, key ); + data = dataAttr( elem, key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + } + + parts[1] = value; + this.each(function() { + var self = jQuery( this ); + + self.triggerHandler( "setData" + part, parts ); + jQuery.data( this, key, value ); + self.triggerHandler( "changeData" + part, parts ); + }); + }, null, value, arguments.length > 1, null, false ); + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray(data) ) { + queue = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + jQuery.removeData( elem, type + "queue", true ); + jQuery.removeData( elem, key, true ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var nodeHook, boolHook, fixSpecified, + rclass = /[\t\r\n]/g, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea|)$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( core_rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( setClass.indexOf( " " + classNames[ c ] + " " ) < 0 ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var removes, className, elem, c, cl, i, l; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + if ( (value && typeof value === "string") || value === undefined ) { + removes = ( value || "" ).split( core_rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + if ( elem.nodeType === 1 && elem.className ) { + + className = (" " + elem.className + " ").replace( rclass, " " ); + + // loop over each item in the removal list + for ( c = 0, cl = removes.length; c < cl; c++ ) { + // Remove until there is nothing to remove, + while ( className.indexOf(" " + removes[ c ] + " ") >= 0 ) { + className = className.replace( " " + removes[ c ] + " " , " " ); + } + } + elem.className = value ? jQuery.trim( className ) : ""; + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( core_rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space separated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var val, + self = jQuery(this); + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, i, max, option, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + i = one ? index : 0; + max = one ? index + 1 : options.length; + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + // Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9 + attrFn: {}, + + attr: function( elem, name, value, pass ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, value + "" ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var propName, attrNames, name, isBool, + i = 0; + + if ( value && elem.nodeType === 1 ) { + + attrNames = value.split( core_rspace ); + + for ( ; i < attrNames.length; i++ ) { + name = attrNames[ i ]; + + if ( name ) { + propName = jQuery.propFix[ name ] || name; + isBool = rboolean.test( name ); + + // See #9699 for explanation of this approach (setting first, then removal) + // Do not do this for boolean attributes (see #10870) + if ( !isBool ) { + jQuery.attr( elem, name, "" ); + } + elem.removeAttribute( getSetAttribute ? name : propName ); + + // Set corresponding property to false for boolean attributes + if ( isBool && propName in elem ) { + elem[ propName ] = false; + } + } + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode, + property = jQuery.prop( elem, name ); + return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + fixSpecified = { + name: true, + id: true, + coords: true + }; + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ? + ret.value : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return ( ret.value = value + "" ); + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + if ( value === "" ) { + value = "false"; + } + nodeHook.set( elem, value, name ); + } + }; +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = value + "" ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); +var rformElems = /^(?:textarea|input|select)$/i, + rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/, + rhoverHack = /(?:^|\s)hover(\.\S+|)\b/, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + hoverHack = function( events ) { + return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); + }; + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + add: function( elem, types, handler, data, selector ) { + + var elemData, eventHandle, events, + t, tns, type, namespaces, handleObj, + handleObjIn, handlers, special; + + // Don't attach events to noData or text/comment nodes (allow plain objects tho) + if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + events = elemData.events; + if ( !events ) { + elemData.events = events = {}; + } + eventHandle = elemData.handle; + if ( !eventHandle ) { + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = jQuery.trim( hoverHack(types) ).split( " " ); + for ( t = 0; t < types.length; t++ ) { + + tns = rtypenamespace.exec( types[t] ) || []; + type = tns[1]; + namespaces = ( tns[2] || "" ).split( "." ).sort(); + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: tns[1], + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + handlers = events[ type ]; + if ( !handlers ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var t, tns, type, origType, namespaces, origCount, + j, events, special, eventType, handleObj, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = jQuery.trim( hoverHack( types || "" ) ).split(" "); + for ( t = 0; t < types.length; t++ ) { + tns = rtypenamespace.exec( types[t] ) || []; + type = origType = tns[1]; + namespaces = tns[2]; + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector? special.delegateType : special.bindType ) || type; + eventType = events[ type ] || []; + origCount = eventType.length; + namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null; + + // Remove matching events + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !namespaces || namespaces.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + eventType.splice( j--, 1 ); + + if ( handleObj.selector ) { + eventType.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( eventType.length === 0 && origCount !== eventType.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery.removeData( elem, "events", true ); + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Don't do events on text and comment nodes + if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { + return; + } + + // Event object or event type + var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType, + type = event.type || event, + namespaces = []; + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "!" ) >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf( "." ) >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.isTrigger = true; + event.exclusive = exclusive; + event.namespace = namespaces.join( "." ); + event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null; + ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; + + // Handle a global trigger + if ( !elem ) { + + // TODO: Stop taunting the data cache; remove global events and always attach to document + cache = jQuery.cache; + for ( i in cache ) { + if ( cache[ i ].events && cache[ i ].events[ type ] ) { + jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); + } + } + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + eventPath = [[ elem, special.bindType || type ]]; + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; + for ( old = elem; cur; cur = cur.parentNode ) { + eventPath.push([ cur, bubbleType ]); + old = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( old === (elem.ownerDocument || document) ) { + eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); + } + } + + // Fire handlers on the event path + for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { + + cur = eventPath[i][0]; + event.type = eventPath[i][1]; + + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + // Note that this is a bare JS function and not a jQuery handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + // IE<9 dies on focus/blur to hidden element (#1486) + if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( old ) { + elem[ ontype ] = old; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event || window.event ); + + var i, j, cur, ret, selMatch, matched, matches, handleObj, sel, related, + handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), + delegateCount = handlers.delegateCount, + args = core_slice.call( arguments ), + run_all = !event.exclusive && !event.namespace, + special = jQuery.event.special[ event.type ] || {}, + handlerQueue = []; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers that should run if there are delegated events + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && !(event.button && event.type === "click") ) { + + for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { + + // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.disabled !== true || event.type !== "click" ) { + selMatch = {}; + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + sel = handleObj.selector; + + if ( selMatch[ sel ] === undefined ) { + selMatch[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( selMatch[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, matches: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( handlers.length > delegateCount ) { + handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); + } + + // Run delegates first; they may want to stop propagation beneath us + for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { + matched = handlerQueue[ i ]; + event.currentTarget = matched.elem; + + for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { + handleObj = matched.matches[ j ]; + + // Triggered event must either 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { + + event.data = handleObj.data; + event.handleObj = handleObj; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** + props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, + originalEvent = event, + fixHook = jQuery.event.fixHooks[ event.type ] || {}, + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = jQuery.Event( originalEvent ); + + for ( i = copy.length; i; ) { + prop = copy[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Target should not be a text node (#504, Safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8) + event.metaKey = !!event.metaKey; + + return fixHook.filter? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + + focus: { + delegateType: "focusin" + }, + blur: { + delegateType: "focusout" + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +// Some plugins are using, but it's undocumented/deprecated and will be removed. +// The 1.7 special event interface should provide all the hooks needed now. +jQuery.event.handle = jQuery.event.dispatch; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 – + // detachEvent needed property on element, by name of that event, to properly expose it to GC + if ( typeof elem[ name ] === "undefined" ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj, + selector = handleObj.selector; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !jQuery._data( form, "_submit_attached" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + jQuery._data( form, "_submit_attached", true ); + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + } + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event, true ); + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + jQuery._data( elem, "_change_attached", true ); + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { // && selector != null + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + live: function( types, data, fn ) { + jQuery( this.context ).on( types, this.selector, data, fn ); + return this; + }, + die: function( types, fn ) { + jQuery( this.context ).off( types, this.selector || "**", fn ); + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + + if ( rkeyEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; + } + + if ( rmouseEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; + } +}); +/*! + * Sizzle CSS Selector Engine + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license + * http://sizzlejs.com/ + */ +(function( window, undefined ) { + +var cachedruns, + assertGetIdNotName, + Expr, + getText, + isXML, + contains, + compile, + sortOrder, + hasDuplicate, + outermostContext, + + baseHasDuplicate = true, + strundefined = "undefined", + + expando = ( "sizcache" + Math.random() ).replace( ".", "" ), + + Token = String, + document = window.document, + docElem = document.documentElement, + dirruns = 0, + done = 0, + pop = [].pop, + push = [].push, + slice = [].slice, + // Use a stripped-down indexOf if a native one is unavailable + indexOf = [].indexOf || function( elem ) { + var i = 0, + len = this.length; + for ( ; i < len; i++ ) { + if ( this[i] === elem ) { + return i; + } + } + return -1; + }, + + // Augment a function for special use by Sizzle + markFunction = function( fn, value ) { + fn[ expando ] = value == null || value; + return fn; + }, + + createCache = function() { + var cache = {}, + keys = []; + + return markFunction(function( key, value ) { + // Only keep the most recent entries + if ( keys.push( key ) > Expr.cacheLength ) { + delete cache[ keys.shift() ]; + } + + return (cache[ key ] = value); + }, cache ); + }, + + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + + // Regex + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors) + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors + operators = "([*^$|!~]?=)", + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + + "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", + + // Prefer arguments not in parens/brackets, + // then attribute selectors and non-pseudos (denoted by :), + // then anything else + // These preferences are here to reduce the number of selectors + // needing tokenize in the PSEUDO preFilter + pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:" + attributes + ")|[^:]|\\\\.)*|.*))\\)|)", + + // For matchExpr.POS and matchExpr.needsContext + pos = ":(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ), + rpseudo = new RegExp( pseudos ), + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/, + + rnot = /^:not/, + rsibling = /[\x20\t\r\n\f]*[+~]/, + rendsWithNot = /:not\($/, + + rheader = /h\d/i, + rinputs = /input|select|textarea|button/i, + + rbackslash = /\\(?!\\)/g, + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "POS": new RegExp( pos, "i" ), + "CHILD": new RegExp( "^:(only|nth|first|last)-child(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + // For use in libraries implementing .is() + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" ) + }, + + // Support + + // Used for testing something on an element + assert = function( fn ) { + var div = document.createElement("div"); + + try { + return fn( div ); + } catch (e) { + return false; + } finally { + // release memory in IE + div = null; + } + }, + + // Check if getElementsByTagName("*") returns only elements + assertTagNameNoComments = assert(function( div ) { + div.appendChild( document.createComment("") ); + return !div.getElementsByTagName("*").length; + }), + + // Check if getAttribute returns normalized href attributes + assertHrefNotNormalized = assert(function( div ) { + div.innerHTML = ""; + return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && + div.firstChild.getAttribute("href") === "#"; + }), + + // Check if attributes should be retrieved by attribute nodes + assertAttributes = assert(function( div ) { + div.innerHTML = ""; + var type = typeof div.lastChild.getAttribute("multiple"); + // IE8 returns a string for some attributes even when not present + return type !== "boolean" && type !== "string"; + }), + + // Check if getElementsByClassName can be trusted + assertUsableClassName = assert(function( div ) { + // Opera can't find a second classname (in 9.6) + div.innerHTML = ""; + if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) { + return false; + } + + // Safari 3.2 caches class attributes and doesn't catch changes + div.lastChild.className = "e"; + return div.getElementsByClassName("e").length === 2; + }), + + // Check if getElementById returns elements by name + // Check if getElementsByName privileges form controls or returns elements by ID + assertUsableName = assert(function( div ) { + // Inject content + div.id = expando + 0; + div.innerHTML = "
"; + docElem.insertBefore( div, docElem.firstChild ); + + // Test + var pass = document.getElementsByName && + // buggy browsers will return fewer than the correct 2 + document.getElementsByName( expando ).length === 2 + + // buggy browsers will return more than the correct 0 + document.getElementsByName( expando + 0 ).length; + assertGetIdNotName = !document.getElementById( expando ); + + // Cleanup + docElem.removeChild( div ); + + return pass; + }); + +// If slice is not available, provide a backup +try { + slice.call( docElem.childNodes, 0 )[0].nodeType; +} catch ( e ) { + slice = function( i ) { + var elem, + results = []; + for ( ; (elem = this[i]); i++ ) { + results.push( elem ); + } + return results; + }; +} + +function Sizzle( selector, context, results, seed ) { + results = results || []; + context = context || document; + var match, elem, xml, m, + nodeType = context.nodeType; + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + if ( nodeType !== 1 && nodeType !== 9 ) { + return []; + } + + xml = isXML( context ); + + if ( !xml && !seed ) { + if ( (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) { + push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); + return results; + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed, xml ); +} + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + return Sizzle( expr, null, null, [ elem ] ).length > 0; +}; + +// Returns a function to use in pseudos for input types +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +// Returns a function to use in pseudos for buttons +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +// Returns a function to use in pseudos for positionals +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( nodeType ) { + if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (see #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + } else { + + // If no nodeType, this is expected to be an array + for ( ; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } + return ret; +}; + +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +// Element contains another +contains = Sizzle.contains = docElem.contains ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) ); + } : + docElem.compareDocumentPosition ? + function( a, b ) { + return b && !!( a.compareDocumentPosition( b ) & 16 ); + } : + function( a, b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + return false; + }; + +Sizzle.attr = function( elem, name ) { + var val, + xml = isXML( elem ); + + if ( !xml ) { + name = name.toLowerCase(); + } + if ( (val = Expr.attrHandle[ name ]) ) { + return val( elem ); + } + if ( xml || assertAttributes ) { + return elem.getAttribute( name ); + } + val = elem.getAttributeNode( name ); + return val ? + typeof elem[ name ] === "boolean" ? + elem[ name ] ? name : null : + val.specified ? val.value : null : + null; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + // IE6/7 return a modified href + attrHandle: assertHrefNotNormalized ? + {} : + { + "href": function( elem ) { + return elem.getAttribute( "href", 2 ); + }, + "type": function( elem ) { + return elem.getAttribute("type"); + } + }, + + find: { + "ID": assertGetIdNotName ? + function( id, context, xml ) { + if ( typeof context.getElementById !== strundefined && !xml ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + } : + function( id, context, xml ) { + if ( typeof context.getElementById !== strundefined && !xml ) { + var m = context.getElementById( id ); + + return m ? + m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? + [m] : + undefined : + []; + } + }, + + "TAG": assertTagNameNoComments ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== strundefined ) { + return context.getElementsByTagName( tag ); + } + } : + function( tag, context ) { + var results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + var elem, + tmp = [], + i = 0; + + for ( ; (elem = results[i]); i++ ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }, + + "NAME": assertUsableName && function( tag, context ) { + if ( typeof context.getElementsByName !== strundefined ) { + return context.getElementsByName( name ); + } + }, + + "CLASS": assertUsableClassName && function( className, context, xml ) { + if ( typeof context.getElementsByClassName !== strundefined && !xml ) { + return context.getElementsByClassName( className ); + } + } + }, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( rbackslash, "" ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 3 xn-component of xn+y argument ([+-]?\d*n|) + 4 sign of xn-component + 5 x of xn-component + 6 sign of y-component + 7 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1] === "nth" ) { + // nth-child requires argument + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) ); + match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" ); + + // other types prohibit arguments + } else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var unquoted, excess; + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + if ( match[3] ) { + match[2] = match[3]; + } else if ( (unquoted = match[4]) ) { + // Only check arguments that contain a pseudo + if ( rpseudo.test(unquoted) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + unquoted = unquoted.slice( 0, excess ); + match[0] = match[0].slice( 0, excess ); + } + match[2] = unquoted; + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + "ID": assertGetIdNotName ? + function( id ) { + id = id.replace( rbackslash, "" ); + return function( elem ) { + return elem.getAttribute("id") === id; + }; + } : + function( id ) { + id = id.replace( rbackslash, "" ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); + return node && node.value === id; + }; + }, + + "TAG": function( nodeName ) { + if ( nodeName === "*" ) { + return function() { return true; }; + } + nodeName = nodeName.replace( rbackslash, "" ).toLowerCase(); + + return function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ expando ][ className ]; + if ( !pattern ) { + pattern = classCache( className, new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)") ); + } + return function( elem ) { + return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); + }; + }, + + "ATTR": function( name, operator, check ) { + return function( elem, context ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.substr( result.length - check.length ) === check : + operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.substr( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, argument, first, last ) { + + if ( type === "nth" ) { + return function( elem ) { + var node, diff, + parent = elem.parentNode; + + if ( first === 1 && last === 0 ) { + return true; + } + + if ( parent ) { + diff = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + diff++; + if ( elem === node ) { + break; + } + } + } + } + + // Incorporate the offset (or cast to NaN), then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + }; + } + + return function( elem ) { + var node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + /* falls through */ + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), + // not comment, processing instructions, or others + // Thanks to Diego Perini for the nodeName shortcut + // Greater than "@" means alpha characters (specifically not starting with "#" or "?") + var nodeType; + elem = elem.firstChild; + while ( elem ) { + if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) { + return false; + } + elem = elem.nextSibling; + } + return true; + }, + + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "text": function( elem ) { + var type, attr; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && + (type = elem.type) === "text" && + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type ); + }, + + // Input types + "radio": createInputPseudo("radio"), + "checkbox": createInputPseudo("checkbox"), + "file": createInputPseudo("file"), + "password": createInputPseudo("password"), + "image": createInputPseudo("image"), + + "submit": createButtonPseudo("submit"), + "reset": createButtonPseudo("reset"), + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "focus": function( elem ) { + var doc = elem.ownerDocument; + return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href); + }, + + "active": function( elem ) { + return elem === elem.ownerDocument.activeElement; + }, + + // Positional types + "first": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length, argument ) { + for ( var i = 0; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length, argument ) { + for ( var i = 1; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + for ( var i = argument < 0 ? argument + length : argument; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + for ( var i = argument < 0 ? argument + length : argument; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +function siblingCheck( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; +} + +sortOrder = docElem.compareDocumentPosition ? + function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + return ( !a.compareDocumentPosition || !b.compareDocumentPosition ? + a.compareDocumentPosition : + a.compareDocumentPosition(b) & 4 + ) ? -1 : 1; + } : + function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + +// Always assume the presence of duplicates if sort doesn't +// pass them to our comparison function (as in Google Chrome). +[0, 0].sort( sortOrder ); +baseHasDuplicate = !hasDuplicate; + +// Document sorting and removing duplicates +Sizzle.uniqueSort = function( results ) { + var elem, + i = 1; + + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( ; (elem = results[i]); i++ ) { + if ( elem === results[ i - 1 ] ) { + results.splice( i--, 1 ); + } + } + } + + return results; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +function tokenize( selector, parseOnly ) { + var matched, match, tokens, type, soFar, groups, preFilters, + cached = tokenCache[ expando ][ selector ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + soFar = soFar.slice( match[0].length ); + } + groups.push( tokens = [] ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + tokens.push( matched = new Token( match.shift() ) ); + soFar = soFar.slice( matched.length ); + + // Cast descendant combinators to space + matched.type = match[0].replace( rtrim, " " ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + // The last two arguments here are (context, xml) for backCompat + (match = preFilters[ type ]( match, document, true ))) ) { + + tokens.push( matched = new Token( match.shift() ) ); + soFar = soFar.slice( matched.length ); + matched.type = type; + matched.matches = match; + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && combinator.dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( checkNonElements || elem.nodeType === 1 ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( !xml ) { + var cache, + dirkey = dirruns + " " + doneName + " ", + cachedkey = dirkey + cachedruns; + while ( (elem = elem[ dir ]) ) { + if ( checkNonElements || elem.nodeType === 1 ) { + if ( (cache = elem[ expando ]) === cachedkey ) { + return elem.sizset; + } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) { + if ( elem.sizset ) { + return elem; + } + } else { + elem[ expando ] = cachedkey; + if ( matcher( elem, context, xml ) ) { + elem.sizset = true; + return elem; + } + elem.sizset = false; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( checkNonElements || elem.nodeType === 1 ) { + if ( matcher( elem, context, xml ) ) { + return elem; + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + // Positional selectors apply to seed elements, so it is invalid to follow them with relative ones + if ( seed && postFinder ) { + return; + } + + var i, elem, postFilterIn, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [], seed ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + postFilterIn = condense( matcherOut, postMap ); + postFilter( postFilterIn, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = postFilterIn.length; + while ( i-- ) { + if ( (elem = postFilterIn[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + // Keep seed and results synchronized + if ( seed ) { + // Ignore postFinder because it can't coexist with seed + i = preFilter && matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + seed[ preMap[i] ] = !(results[ preMap[i] ] = elem); + } + } + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + // The concatenated values are (context, xml) for backCompat + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && tokens.slice( 0, i - 1 ).join("").replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && tokens.join("") + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, expandContext ) { + var elem, j, matcher, + setMatched = [], + matchedCount = 0, + i = "0", + unmatched = seed && [], + outermost = expandContext != null, + contextBackup = outermostContext, + // We must always have either seed elements or context + elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), + // Nested matchers should use non-integer dirruns + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.E); + + if ( outermost ) { + outermostContext = context !== document && context; + cachedruns = superMatcher.el; + } + + // Add elements passing elementMatchers directly to results + for ( ; (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + for ( j = 0; (matcher = elementMatchers[j]); j++ ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + cachedruns = ++superMatcher.el; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + for ( j = 0; (matcher = setMatchers[j]); j++ ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + superMatcher.el = 0; + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ expando ][ selector ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !group ) { + group = tokenize( selector ); + } + i = group.length; + while ( i-- ) { + cached = matcherFromTokens( group[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + } + return cached; +}; + +function multipleContexts( selector, contexts, results, seed ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results, seed ); + } + return results; +} + +function select( selector, context, results, seed, xml ) { + var i, tokens, token, type, find, + match = tokenize( selector ), + j = match.length; + + if ( !seed ) { + // Try to minimize operations if there is only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && !xml && + Expr.relative[ tokens[1].type ] ) { + + context = Expr.find["ID"]( token.matches[0].replace( rbackslash, "" ), context, xml )[0]; + if ( !context ) { + return results; + } + + selector = selector.slice( tokens.shift().length ); + } + + // Fetch a seed set for right-to-left matching + for ( i = matchExpr["POS"].test( selector ) ? -1 : tokens.length - 1; i >= 0; i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( rbackslash, "" ), + rsibling.test( tokens[0].type ) && context.parentNode || context, + xml + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && tokens.join(""); + if ( !selector ) { + push.apply( results, slice.call( seed, 0 ) ); + return results; + } + + break; + } + } + } + } + } + + // Compile and execute a filtering function + // Provide `match` to avoid retokenization if we modified the selector above + compile( selector, match )( + seed, + context, + xml, + results, + rsibling.test( selector ) + ); + return results; +} + +if ( document.querySelectorAll ) { + (function() { + var disconnectedMatch, + oldSelect = select, + rescape = /'|\\/g, + rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, + + // qSa(:focus) reports false when true (Chrome 21), + // A support test would require too much code (would include document ready) + rbuggyQSA = [":focus"], + + // matchesSelector(:focus) reports false when true (Chrome 21), + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + // A support test would require too much code (would include document ready) + // just skip matchesSelector for :active + rbuggyMatches = [ ":active", ":focus" ], + matches = docElem.matchesSelector || + docElem.mozMatchesSelector || + docElem.webkitMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector; + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explictly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + div.innerHTML = ""; + + // IE8 - Some boolean attributes are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here (do not put tests after this one) + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + }); + + assert(function( div ) { + + // Opera 10-12/IE9 - ^= $= *= and empty values + // Should not select anything + div.innerHTML = "

"; + if ( div.querySelectorAll("[test^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here (do not put tests after this one) + div.innerHTML = ""; + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push(":enabled", ":disabled"); + } + }); + + // rbuggyQSA always contains :focus, so no need for a length check + rbuggyQSA = /* rbuggyQSA.length && */ new RegExp( rbuggyQSA.join("|") ); + + select = function( selector, context, results, seed, xml ) { + // Only use querySelectorAll when not filtering, + // when this is not xml, + // and when no QSA bugs apply + if ( !seed && !xml && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + var groups, i, + old = true, + nid = expando, + newContext = context, + newSelector = context.nodeType === 9 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + groups[i].join(""); + } + newContext = rsibling.test( selector ) && context.parentNode || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, slice.call( newContext.querySelectorAll( + newSelector + ), 0 ) ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + + return oldSelect( selector, context, results, seed, xml ); + }; + + if ( matches ) { + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + try { + matches.call( div, "[test!='']:sizzle" ); + rbuggyMatches.push( "!=", pseudos ); + } catch ( e ) {} + }); + + // rbuggyMatches always contains :active and :focus, so no need for a length check + rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") ); + + Sizzle.matchesSelector = function( elem, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + // rbuggyMatches always contains :active, so no need for an existence check + if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && (!rbuggyQSA || !rbuggyQSA.test( expr )) ) { + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch(e) {} + } + + return Sizzle( expr, null, null, [ elem ] ).length > 0; + }; + } + })(); +} + +// Deprecated +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Back-compat +function setFilters() {} +Expr.filters = setFilters.prototype = Expr.pseudos; +Expr.setFilters = new setFilters(); + +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})( window ); +var runtil = /Until$/, + rparentsprev = /^(?:parents|prev(?:Until|All))/, + isSimple = /^.[^:#\[\.,]*$/, + rneedsContext = jQuery.expr.match.needsContext, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var i, l, length, n, r, ret, + self = this; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + ret = this.pushStack( "", "find", selector ); + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + rneedsContext.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + ret = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + cur = this[i]; + + while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + } + cur = cur.parentNode; + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +jQuery.fn.andSelf = jQuery.fn.addBack; + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( this.length > 1 && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, core_slice.call( arguments ).join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rtbody = /]", "i"), + rcheckableType = /^(?:checkbox|radio)$/, + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptType = /\/(java|ecma)script/i, + rcleanScript = /^\s*\s*$/g, + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
", "
" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + col: [ 2, "", "
" ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement("div") ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, +// unless wrapped in a div with non-breaking characters in front of it. +if ( !jQuery.support.htmlSerialize ) { + wrapMap._default = [ 1, "X
", "
" ]; +} + +jQuery.fn.extend({ + text: function( value ) { + return jQuery.access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); + }, + + wrapAll: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapAll( html.call(this, i) ); + }); + } + + if ( this[0] ) { + // The elements to wrap the target around + var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); + + if ( this[0].parentNode ) { + wrap.insertBefore( this[0] ); + } + + wrap.map(function() { + var elem = this; + + while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { + elem = elem.firstChild; + } + + return elem; + }).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapInner( html.call(this, i) ); + }); + } + + return this.each(function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + }); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each(function(i) { + jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); + }); + }, + + unwrap: function() { + return this.parent().each(function() { + if ( !jQuery.nodeName( this, "body" ) ) { + jQuery( this ).replaceWith( this.childNodes ); + } + }).end(); + }, + + append: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 ) { + this.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 ) { + this.insertBefore( elem, this.firstChild ); + } + }); + }, + + before: function() { + if ( !isDisconnected( this[0] ) ) { + return this.domManip(arguments, false, function( elem ) { + this.parentNode.insertBefore( elem, this ); + }); + } + + if ( arguments.length ) { + var set = jQuery.clean( arguments ); + return this.pushStack( jQuery.merge( set, this ), "before", this.selector ); + } + }, + + after: function() { + if ( !isDisconnected( this[0] ) ) { + return this.domManip(arguments, false, function( elem ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + }); + } + + if ( arguments.length ) { + var set = jQuery.clean( arguments ); + return this.pushStack( jQuery.merge( this, set ), "after", this.selector ); + } + }, + + // keepData is for internal use only--do not document + remove: function( selector, keepData ) { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + if ( !selector || jQuery.filter( selector, [ elem ] ).length ) { + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( elem.getElementsByTagName("*") ); + jQuery.cleanData( [ elem ] ); + } + + if ( elem.parentNode ) { + elem.parentNode.removeChild( elem ); + } + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( elem.getElementsByTagName("*") ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function () { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return jQuery.access( this, function( value ) { + var elem = this[0] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( elem.getElementsByTagName( "*" ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function( value ) { + if ( !isDisconnected( this[0] ) ) { + // Make sure that the elements are removed from the DOM before they are inserted + // this can help fix replacing a parent with child elements + if ( jQuery.isFunction( value ) ) { + return this.each(function(i) { + var self = jQuery(this), old = self.html(); + self.replaceWith( value.call( this, i, old ) ); + }); + } + + if ( typeof value !== "string" ) { + value = jQuery( value ).detach(); + } + + return this.each(function() { + var next = this.nextSibling, + parent = this.parentNode; + + jQuery( this ).remove(); + + if ( next ) { + jQuery(next).before( value ); + } else { + jQuery(parent).append( value ); + } + }); + } + + return this.length ? + this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : + this; + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, table, callback ) { + + // Flatten any nested arrays + args = [].concat.apply( [], args ); + + var results, first, fragment, iNoClone, + i = 0, + value = args[0], + scripts = [], + l = this.length; + + // We can't cloneNode fragments that contain checked, in WebKit + if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) { + return this.each(function() { + jQuery(this).domManip( args, table, callback ); + }); + } + + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + args[0] = value.call( this, i, table ? self.html() : undefined ); + self.domManip( args, table, callback ); + }); + } + + if ( this[0] ) { + results = jQuery.buildFragment( args, this, scripts ); + fragment = results.fragment; + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + table = table && jQuery.nodeName( first, "tr" ); + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + // Fragments from the fragment cache must always be cloned and never used in place. + for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) { + callback.call( + table && jQuery.nodeName( this[i], "table" ) ? + findOrAppend( this[i], "tbody" ) : + this[i], + i === iNoClone ? + fragment : + jQuery.clone( fragment, true, true ) + ); + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + + if ( scripts.length ) { + jQuery.each( scripts, function( i, elem ) { + if ( elem.src ) { + if ( jQuery.ajax ) { + jQuery.ajax({ + url: elem.src, + type: "GET", + dataType: "script", + async: false, + global: false, + "throws": true + }); + } else { + jQuery.error("no ajax"); + } + } else { + jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) ); + } + + if ( elem.parentNode ) { + elem.parentNode.removeChild( elem ); + } + }); + } + } + + return this; + } +}); + +function findOrAppend( elem, tag ) { + return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function cloneFixAttributes( src, dest ) { + var nodeName; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + // clearAttributes removes the attributes, which we don't want, + // but also removes the attachEvent events, which we *do* want + if ( dest.clearAttributes ) { + dest.clearAttributes(); + } + + // mergeAttributes, in contrast, only merges back on the + // original attributes, not the events + if ( dest.mergeAttributes ) { + dest.mergeAttributes( src ); + } + + nodeName = dest.nodeName.toLowerCase(); + + if ( nodeName === "object" ) { + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + + // IE blanks contents when cloning scripts + } else if ( nodeName === "script" && dest.text !== src.text ) { + dest.text = src.text; + } + + // Event data gets referenced instead of copied if the expando + // gets copied too + dest.removeAttribute( jQuery.expando ); +} + +jQuery.buildFragment = function( args, context, scripts ) { + var fragment, cacheable, cachehit, + first = args[ 0 ]; + + // Set context from what may come in as undefined or a jQuery collection or a node + // Updated to fix #12266 where accessing context[0] could throw an exception in IE9/10 & + // also doubles as fix for #8950 where plain objects caused createDocumentFragment exception + context = context || document; + context = !context.nodeType && context[0] || context; + context = context.ownerDocument || context; + + // Only cache "small" (1/2 KB) HTML strings that are associated with the main document + // Cloning options loses the selected state, so don't cache them + // IE 6 doesn't like it when you put or elements in a fragment + // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache + // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 + if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document && + first.charAt(0) === "<" && !rnocache.test( first ) && + (jQuery.support.checkClone || !rchecked.test( first )) && + (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) { + + // Mark cacheable and look for a hit + cacheable = true; + fragment = jQuery.fragments[ first ]; + cachehit = fragment !== undefined; + } + + if ( !fragment ) { + fragment = context.createDocumentFragment(); + jQuery.clean( args, context, fragment, scripts ); + + // Update the cache, but only store false + // unless this is a second parsing of the same content + if ( cacheable ) { + jQuery.fragments[ first ] = cachehit && fragment; + } + } + + return { fragment: fragment, cacheable: cacheable }; +}; + +jQuery.fragments = {}; + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + l = insert.length, + parent = this.length === 1 && this[0].parentNode; + + if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) { + insert[ original ]( this[0] ); + return this; + } else { + for ( ; i < l; i++ ) { + elems = ( i > 0 ? this.clone(true) : this ).get(); + jQuery( insert[i] )[ original ]( elems ); + ret = ret.concat( elems ); + } + + return this.pushStack( ret, name, insert.selector ); + } + }; +}); + +function getAll( elem ) { + if ( typeof elem.getElementsByTagName !== "undefined" ) { + return elem.getElementsByTagName( "*" ); + + } else if ( typeof elem.querySelectorAll !== "undefined" ) { + return elem.querySelectorAll( "*" ); + + } else { + return []; + } +} + +// Used in clean, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( rcheckableType.test( elem.type ) ) { + elem.defaultChecked = elem.checked; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var srcElements, + destElements, + i, + clone; + + if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + // IE copies events bound via attachEvent when using cloneNode. + // Calling detachEvent on the clone will also remove the events + // from the original. In order to get around this, we use some + // proprietary methods to clear the events. Thanks to MooTools + // guys for this hotness. + + cloneFixAttributes( elem, clone ); + + // Using Sizzle here is crazy slow, so we use getElementsByTagName instead + srcElements = getAll( elem ); + destElements = getAll( clone ); + + // Weird iteration because IE will replace the length property + // with an element if you are cloning the body and one of the + // elements on the page has a name or id of "length" + for ( i = 0; srcElements[i]; ++i ) { + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + cloneFixAttributes( srcElements[i], destElements[i] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + cloneCopyEvent( elem, clone ); + + if ( deepDataAndEvents ) { + srcElements = getAll( elem ); + destElements = getAll( clone ); + + for ( i = 0; srcElements[i]; ++i ) { + cloneCopyEvent( srcElements[i], destElements[i] ); + } + } + } + + srcElements = destElements = null; + + // Return the cloned set + return clone; + }, + + clean: function( elems, context, fragment, scripts ) { + var i, j, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags, + safe = context === document && safeFragment, + ret = []; + + // Ensure that context is a document + if ( !context || typeof context.createDocumentFragment === "undefined" ) { + context = document; + } + + // Use the already-created safe fragment if context permits + for ( i = 0; (elem = elems[i]) != null; i++ ) { + if ( typeof elem === "number" ) { + elem += ""; + } + + if ( !elem ) { + continue; + } + + // Convert html string into DOM nodes + if ( typeof elem === "string" ) { + if ( !rhtml.test( elem ) ) { + elem = context.createTextNode( elem ); + } else { + // Ensure a safe container in which to render the html + safe = safe || createSafeFragment( context ); + div = context.createElement("div"); + safe.appendChild( div ); + + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(rxhtmlTag, "<$1>"); + + // Go to html and back, then peel off extra wrappers + tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + depth = wrap[0]; + div.innerHTML = wrap[1] + elem + wrap[2]; + + // Move to the right depth + while ( depth-- ) { + div = div.lastChild; + } + + // Remove IE's autoinserted from table fragments + if ( !jQuery.support.tbody ) { + + // String was a , *may* have spurious + hasBody = rtbody.test(elem); + tbody = tag === "table" && !hasBody ? + div.firstChild && div.firstChild.childNodes : + + // String was a bare or + wrap[1] === "
" && !hasBody ? + div.childNodes : + []; + + for ( j = tbody.length - 1; j >= 0 ; --j ) { + if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { + tbody[ j ].parentNode.removeChild( tbody[ j ] ); + } + } + } + + // IE completely kills leading whitespace when innerHTML is used + if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); + } + + elem = div.childNodes; + + // Take out of fragment container (we need a fresh div each time) + div.parentNode.removeChild( div ); + } + } + + if ( elem.nodeType ) { + ret.push( elem ); + } else { + jQuery.merge( ret, elem ); + } + } + + // Fix #11356: Clear elements from safeFragment + if ( div ) { + elem = div = safe = null; + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !jQuery.support.appendChecked ) { + for ( i = 0; (elem = ret[i]) != null; i++ ) { + if ( jQuery.nodeName( elem, "input" ) ) { + fixDefaultChecked( elem ); + } else if ( typeof elem.getElementsByTagName !== "undefined" ) { + jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); + } + } + } + + // Append elements to a provided document fragment + if ( fragment ) { + // Special handling of each script element + handleScript = function( elem ) { + // Check if we consider it executable + if ( !elem.type || rscriptType.test( elem.type ) ) { + // Detach the script and store it in the scripts array (if provided) or the fragment + // Return truthy to indicate that it has been handled + return scripts ? + scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) : + fragment.appendChild( elem ); + } + }; + + for ( i = 0; (elem = ret[i]) != null; i++ ) { + // Check if we're done after handling an executable script + if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) { + // Append to fragment and handle embedded scripts + fragment.appendChild( elem ); + if ( typeof elem.getElementsByTagName !== "undefined" ) { + // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration + jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript ); + + // Splice the scripts into ret after their former ancestor and advance our index beyond them + ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); + i += jsTags.length; + } + } + } + } + + return ret; + }, + + cleanData: function( elems, /* internal */ acceptData ) { + var data, id, elem, type, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + deleteExpando = jQuery.support.deleteExpando, + special = jQuery.event.special; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( acceptData || jQuery.acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( deleteExpando ) { + delete elem[ internalKey ]; + + } else if ( elem.removeAttribute ) { + elem.removeAttribute( internalKey ); + + } else { + elem[ internalKey ] = null; + } + + jQuery.deletedIds.push( id ); + } + } + } + } + } +}); +// Limit scope pollution from any deprecated API +(function() { + +var matched, browser; + +// Use of jQuery.browser is frowned upon. +// More details: http://api.jquery.com/jQuery.browser +// jQuery.uaMatch maintained for back-compat +jQuery.uaMatch = function( ua ) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || + /(webkit)[ \/]([\w.]+)/.exec( ua ) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || + /(msie) ([\w.]+)/.exec( ua ) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; +}; + +matched = jQuery.uaMatch( navigator.userAgent ); +browser = {}; + +if ( matched.browser ) { + browser[ matched.browser ] = true; + browser.version = matched.version; +} + +// Chrome is Webkit, but Webkit is also Safari. +if ( browser.chrome ) { + browser.webkit = true; +} else if ( browser.webkit ) { + browser.safari = true; +} + +jQuery.browser = browser; + +jQuery.sub = function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; +}; + +})(); +var curCSS, iframe, iframeDoc, + ralpha = /alpha\([^)]*\)/i, + ropacity = /opacity=([^)]*)/, + rposition = /^(top|right|bottom|left)$/, + // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" + // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rmargin = /^margin/, + rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), + rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), + rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ), + elemdisplay = {}, + + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: 0, + fontWeight: 400 + }, + + cssExpand = [ "Top", "Right", "Bottom", "Left" ], + cssPrefixes = [ "Webkit", "O", "Moz", "ms" ], + + eventsToggle = jQuery.fn.toggle; + +// return a css property mapped to a potentially vendor prefixed property +function vendorPropName( style, name ) { + + // shortcut for names that are not vendor prefixed + if ( name in style ) { + return name; + } + + // check for vendor prefixed names + var capName = name.charAt(0).toUpperCase() + name.slice(1), + origName = name, + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in style ) { + return name; + } + } + + return origName; +} + +function isHidden( elem, el ) { + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); +} + +function showHide( elements, show ) { + var elem, display, + values = [], + index = 0, + length = elements.length; + + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + values[ index ] = jQuery._data( elem, "olddisplay" ); + if ( show ) { + // Reset the inline display of this element to learn if it is + // being hidden by cascaded rules or not + if ( !values[ index ] && elem.style.display === "none" ) { + elem.style.display = ""; + } + + // Set elements which have been overridden with display: none + // in a stylesheet to whatever the default browser style is + // for such an element + if ( elem.style.display === "" && isHidden( elem ) ) { + values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); + } + } else { + display = curCSS( elem, "display" ); + + if ( !values[ index ] && display !== "none" ) { + jQuery._data( elem, "olddisplay", display ); + } + } + } + + // Set the display of most of the elements in a second loop + // to avoid the constant reflow + for ( index = 0; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + if ( !show || elem.style.display === "none" || elem.style.display === "" ) { + elem.style.display = show ? values[ index ] || "" : "none"; + } + } + + return elements; +} + +jQuery.fn.extend({ + css: function( name, value ) { + return jQuery.access( this, function( elem, name, value ) { + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + }, + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state, fn2 ) { + var bool = typeof state === "boolean"; + + if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) { + return eventsToggle.apply( this, arguments ); + } + + return this.each(function() { + if ( bool ? state : isHidden( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + }); + } +}); + +jQuery.extend({ + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + + } + } + } + }, + + // Exclude the following css properties to add px + cssNumber: { + "fillOpacity": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + // normalize float css property + "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + style = elem.style; + + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // convert relative number strings (+= or -=) to relative numbers. #7345 + if ( type === "string" && (ret = rrelNum.exec( value )) ) { + value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); + // Fixes bug #9237 + type = "number"; + } + + // Make sure that NaN and null values aren't set. See: #7116 + if ( value == null || type === "number" && isNaN( value ) ) { + return; + } + + // If a number was passed in, add 'px' to the (except for certain CSS properties) + if ( type === "number" && !jQuery.cssNumber[ origName ] ) { + value += "px"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { + // Wrapped to prevent IE from throwing errors when 'invalid' values are provided + // Fixes bug #5509 + try { + style[ name ] = value; + } catch(e) {} + } + + } else { + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, numeric, extra ) { + var val, num, hooks, + origName = jQuery.camelCase( name ); + + // Make sure that we're working with the right name + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name ); + } + + //convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Return, converting to number if forced or a qualifier was provided and val looks numeric + if ( numeric || extra !== undefined ) { + num = parseFloat( val ); + return numeric || jQuery.isNumeric( num ) ? num || 0 : val; + } + return val; + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; + } +}); + +// NOTE: To any future maintainer, we've window.getComputedStyle +// because jsdom on node.js will break without it. +if ( window.getComputedStyle ) { + curCSS = function( elem, name ) { + var ret, width, minWidth, maxWidth, + computed = window.getComputedStyle( elem, null ), + style = elem.style; + + if ( computed ) { + + ret = computed[ name ]; + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right + // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels + // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values + if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret; + }; +} else if ( document.documentElement.currentStyle ) { + curCSS = function( elem, name ) { + var left, rsLeft, + ret = elem.currentStyle && elem.currentStyle[ name ], + style = elem.style; + + // Avoid setting ret to empty string here + // so we don't default to auto + if ( ret == null && style && style[ name ] ) { + ret = style[ name ]; + } + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + // but not position css attributes, as those are proportional to the parent element instead + // and we can't measure the parent instead because it might trigger a "stacking dolls" problem + if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { + + // Remember the original values + left = style.left; + rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; + + // Put in the new values to get a computed value out + if ( rsLeft ) { + elem.runtimeStyle.left = elem.currentStyle.left; + } + style.left = name === "fontSize" ? "1em" : ret; + ret = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + if ( rsLeft ) { + elem.runtimeStyle.left = rsLeft; + } + } + + return ret === "" ? "auto" : ret; + }; +} + +function setPositiveNumber( elem, value, subtract ) { + var matches = rnumsplit.exec( value ); + return matches ? + Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox ) { + var i = extra === ( isBorderBox ? "border" : "content" ) ? + // If we already have the right measurement, avoid augmentation + 4 : + // Otherwise initialize for horizontal or vertical properties + name === "width" ? 1 : 0, + + val = 0; + + for ( ; i < 4; i += 2 ) { + // both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + // we use jQuery.css instead of curCSS here + // because of the reliableMarginRight CSS hook! + val += jQuery.css( elem, extra + cssExpand[ i ], true ); + } + + // From this point on we use curCSS for maximum performance (relevant in animations) + if ( isBorderBox ) { + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; + } + + // at this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; + } + } else { + // at this point, extra isn't content, so add padding + val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; + + // at this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with offset property, which is equivalent to the border-box value + var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, + valueIsBorderBox = true, + isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"; + + // some non-html elements return undefined for offsetWidth, so check for null/undefined + // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 + // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 + if ( val <= 0 || val == null ) { + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name ); + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + } + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test(val) ) { + return val; + } + + // we need the check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + } + + // use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox + ) + ) + "px"; +} + + +// Try to determine the default display value of an element +function css_defaultDisplay( nodeName ) { + if ( elemdisplay[ nodeName ] ) { + return elemdisplay[ nodeName ]; + } + + var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ), + display = elem.css("display"); + elem.remove(); + + // If the simple way fails, + // get element's real default display by attaching it to a temp iframe + if ( display === "none" || display === "" ) { + // Use the already-created iframe if possible + iframe = document.body.appendChild( + iframe || jQuery.extend( document.createElement("iframe"), { + frameBorder: 0, + width: 0, + height: 0 + }) + ); + + // Create a cacheable copy of the iframe document on first call. + // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML + // document to it; WebKit & Firefox won't allow reusing the iframe document. + if ( !iframeDoc || !iframe.createElement ) { + iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; + iframeDoc.write(""); + iframeDoc.close(); + } + + elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) ); + + display = curCSS( elem, "display" ); + document.body.removeChild( iframe ); + } + + // Store the correct default display + elemdisplay[ nodeName ] = display; + + return display; +} + +jQuery.each([ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + // certain elements can have dimension info if we invisibly show them + // however, it must have a current display style that would benefit from this + if ( elem.offsetWidth === 0 && rdisplayswap.test( curCSS( elem, "display" ) ) ) { + return jQuery.swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + }); + } else { + return getWidthOrHeight( elem, name, extra ); + } + } + }, + + set: function( elem, value, extra ) { + return setPositiveNumber( elem, value, extra ? + augmentWidthOrHeight( + elem, + name, + extra, + jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box" + ) : 0 + ); + } + }; +}); + +if ( !jQuery.support.opacity ) { + jQuery.cssHooks.opacity = { + get: function( elem, computed ) { + // IE uses filters for opacity + return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? + ( 0.01 * parseFloat( RegExp.$1 ) ) + "" : + computed ? "1" : ""; + }, + + set: function( elem, value ) { + var style = elem.style, + currentStyle = elem.currentStyle, + opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", + filter = currentStyle && currentStyle.filter || style.filter || ""; + + // IE has trouble with opacity if it does not have layout + // Force it by setting the zoom level + style.zoom = 1; + + // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 + if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" && + style.removeAttribute ) { + + // Setting style.filter to null, "" & " " still leave "filter:" in the cssText + // if "filter:" is present at all, clearType is disabled, we want to avoid this + // style.removeAttribute is IE Only, but so apparently is this code path... + style.removeAttribute( "filter" ); + + // if there there is no filter style applied in a css rule, we are done + if ( currentStyle && !currentStyle.filter ) { + return; + } + } + + // otherwise, set new filter values + style.filter = ralpha.test( filter ) ? + filter.replace( ralpha, opacity ) : + filter + " " + opacity; + } + }; +} + +// These hooks cannot be added until DOM ready because the support test +// for it is not run until after DOM ready +jQuery(function() { + if ( !jQuery.support.reliableMarginRight ) { + jQuery.cssHooks.marginRight = { + get: function( elem, computed ) { + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + // Work around by temporarily setting element display to inline-block + return jQuery.swap( elem, { "display": "inline-block" }, function() { + if ( computed ) { + return curCSS( elem, "marginRight" ); + } + }); + } + }; + } + + // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 + // getComputedStyle returns percent when specified for top/left/bottom/right + // rather than make the css module depend on the offset module, we just check for it here + if ( !jQuery.support.pixelPosition && jQuery.fn.position ) { + jQuery.each( [ "top", "left" ], function( i, prop ) { + jQuery.cssHooks[ prop ] = { + get: function( elem, computed ) { + if ( computed ) { + var ret = curCSS( elem, prop ); + // if curCSS returns percentage, fallback to offset + return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret; + } + } + }; + }); + } + +}); + +if ( jQuery.expr && jQuery.expr.filters ) { + jQuery.expr.filters.hidden = function( elem ) { + return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none"); + }; + + jQuery.expr.filters.visible = function( elem ) { + return !jQuery.expr.filters.hidden( elem ); + }; +} + +// These hooks are used by animate to expand properties +jQuery.each({ + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i, + + // assumes a single number if not a string + parts = typeof value === "string" ? value.split(" ") : [ value ], + expanded = {}; + + for ( i = 0; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +}); +var r20 = /%20/g, + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, + rselectTextarea = /^(?:select|textarea)/i; + +jQuery.fn.extend({ + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map(function(){ + return this.elements ? jQuery.makeArray( this.elements ) : this; + }) + .filter(function(){ + return this.name && !this.disabled && + ( this.checked || rselectTextarea.test( this.nodeName ) || + rinput.test( this.type ) ); + }) + .map(function( i, elem ){ + var val = jQuery( this ).val(); + + return val == null ? + null : + jQuery.isArray( val ) ? + jQuery.map( val, function( val, i ){ + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + }) : + { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + }).get(); + } +}); + +//Serialize an array of form elements or a set of +//key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, value ) { + // If value is a function, invoke it and return its value + value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); + s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); + }; + + // Set traditional to true for jQuery <= 1.3.2 behavior. + if ( traditional === undefined ) { + traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + }); + + } else { + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ).replace( r20, "+" ); +}; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( jQuery.isArray( obj ) ) { + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + // If array item is non-scalar (array or object), encode its + // numeric index to resolve deserialization ambiguity issues. + // Note that rack (as of 1.0.0) can't currently deserialize + // nested arrays properly, and attempting to do so may cause + // a server error. Possible fixes are to modify rack's + // deserialization algorithm or to provide an option or flag + // to force array serialization to be shallow. + buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); + } + }); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + // Serialize scalar item. + add( prefix, obj ); + } +} +var + // Document location + ajaxLocParts, + ajaxLocation, + + rhash = /#.*$/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + rquery = /\?/, + rscript = /)<[^<]*)*<\/script>/gi, + rts = /([?&])_=[^&]*/, + rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/, + + // Keep a copy of the old load method + _load = jQuery.fn.load, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = ["*/"] + ["*"]; + +// #8138, IE may throw an exception when accessing +// a field from window.location if document.domain has been set +try { + ajaxLocation = location.href; +} catch( e ) { + // Use the href attribute of an A element + // since IE will modify it given document.location + ajaxLocation = document.createElement( "a" ); + ajaxLocation.href = ""; + ajaxLocation = ajaxLocation.href; +} + +// Segment location into parts +ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, list, placeBefore, + dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ), + i = 0, + length = dataTypes.length; + + if ( jQuery.isFunction( func ) ) { + // For each dataType in the dataTypeExpression + for ( ; i < length; i++ ) { + dataType = dataTypes[ i ]; + // We control if we're asked to add before + // any existing element + placeBefore = /^\+/.test( dataType ); + if ( placeBefore ) { + dataType = dataType.substr( 1 ) || "*"; + } + list = structure[ dataType ] = structure[ dataType ] || []; + // then we add to the structure accordingly + list[ placeBefore ? "unshift" : "push" ]( func ); + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, + dataType /* internal */, inspected /* internal */ ) { + + dataType = dataType || options.dataTypes[ 0 ]; + inspected = inspected || {}; + + inspected[ dataType ] = true; + + var selection, + list = structure[ dataType ], + i = 0, + length = list ? list.length : 0, + executeOnly = ( structure === prefilters ); + + for ( ; i < length && ( executeOnly || !selection ); i++ ) { + selection = list[ i ]( options, originalOptions, jqXHR ); + // If we got redirected to another dataType + // we try there if executing only and not done already + if ( typeof selection === "string" ) { + if ( !executeOnly || inspected[ selection ] ) { + selection = undefined; + } else { + options.dataTypes.unshift( selection ); + selection = inspectPrefiltersOrTransports( + structure, options, originalOptions, jqXHR, selection, inspected ); + } + } + } + // If we're only executing or nothing was selected + // we try the catchall dataType if not done already + if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) { + selection = inspectPrefiltersOrTransports( + structure, options, originalOptions, jqXHR, "*", inspected ); + } + // unnecessary when only executing (prefilters) + // but it'll be ignored by the caller in that case + return selection; +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } +} + +jQuery.fn.load = function( url, params, callback ) { + if ( typeof url !== "string" && _load ) { + return _load.apply( this, arguments ); + } + + // Don't do a request if no elements are being requested + if ( !this.length ) { + return this; + } + + var selector, type, response, + self = this, + off = url.indexOf(" "); + + if ( off >= 0 ) { + selector = url.slice( off, url.length ); + url = url.slice( 0, off ); + } + + // If it's a function + if ( jQuery.isFunction( params ) ) { + + // We assume that it's the callback + callback = params; + params = undefined; + + // Otherwise, build a param string + } else if ( params && typeof params === "object" ) { + type = "POST"; + } + + // Request the remote document + jQuery.ajax({ + url: url, + + // if "type" variable is undefined, then "GET" method will be used + type: type, + dataType: "html", + data: params, + complete: function( jqXHR, status ) { + if ( callback ) { + self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); + } + } + }).done(function( responseText ) { + + // Save response for use in complete callback + response = arguments; + + // See if a selector was specified + self.html( selector ? + + // Create a dummy div to hold the results + jQuery("
") + + // inject the contents of the document in, removing the scripts + // to avoid any 'Permission Denied' errors in IE + .append( responseText.replace( rscript, "" ) ) + + // Locate the specified elements + .find( selector ) : + + // If not, just inject the full result + responseText ); + + }); + + return this; +}; + +// Attach a bunch of functions for handling common AJAX events +jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ + jQuery.fn[ o ] = function( f ){ + return this.on( o, f ); + }; +}); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + // shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + return jQuery.ajax({ + type: method, + url: url, + data: data, + success: callback, + dataType: type + }); + }; +}); + +jQuery.extend({ + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + if ( settings ) { + // Building a settings object + ajaxExtend( target, jQuery.ajaxSettings ); + } else { + // Extending ajaxSettings + settings = target; + target = jQuery.ajaxSettings; + } + ajaxExtend( target, settings ); + return target; + }, + + ajaxSettings: { + url: ajaxLocation, + isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), + global: true, + type: "GET", + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + processData: true, + async: true, + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + xml: "application/xml, text/xml", + html: "text/html", + text: "text/plain", + json: "application/json, text/javascript", + "*": allTypes + }, + + contents: { + xml: /xml/, + html: /html/, + json: /json/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText" + }, + + // List of data converters + // 1) key format is "source_type destination_type" (a single space in-between) + // 2) the catchall symbol "*" can be used for source_type + converters: { + + // Convert anything to text + "* text": window.String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": jQuery.parseJSON, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + context: true, + url: true + } + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var // ifModified key + ifModifiedKey, + // Response headers + responseHeadersString, + responseHeaders, + // transport + transport, + // timeout handle + timeoutTimer, + // Cross-domain detection vars + parts, + // To know if global events are to be dispatched + fireGlobals, + // Loop variable + i, + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + // Callbacks context + callbackContext = s.context || s, + // Context for global events + // It's the callbackContext if one was provided in the options + // and if it's a DOM node or a jQuery collection + globalEventContext = callbackContext !== s && + ( callbackContext.nodeType || callbackContext instanceof jQuery ) ? + jQuery( callbackContext ) : jQuery.event, + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + // Status-dependent callbacks + statusCode = s.statusCode || {}, + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + // The jqXHR state + state = 0, + // Default abort message + strAbort = "canceled", + // Fake xhr + jqXHR = { + + readyState: 0, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( !state ) { + var lname = name.toLowerCase(); + name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Raw string + getAllResponseHeaders: function() { + return state === 2 ? responseHeadersString : null; + }, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( state === 2 ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match === undefined ? null : match; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( !state ) { + s.mimeType = type; + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + statusText = statusText || strAbort; + if ( transport ) { + transport.abort( statusText ); + } + done( 0, statusText ); + return this; + } + }; + + // Callback for when everything is done + // It is defined here because jslint complains if it is declared + // at the end of the function (which would be more logical and readable) + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Called once + if ( state === 2 ) { + return; + } + + // State is "done" now + state = 2; + + // Clear timeout if it exists + if ( timeoutTimer ) { + clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // If successful, handle type chaining + if ( status >= 200 && status < 300 || status === 304 ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + + modified = jqXHR.getResponseHeader("Last-Modified"); + if ( modified ) { + jQuery.lastModified[ ifModifiedKey ] = modified; + } + modified = jqXHR.getResponseHeader("Etag"); + if ( modified ) { + jQuery.etag[ ifModifiedKey ] = modified; + } + } + + // If not modified + if ( status === 304 ) { + + statusText = "notmodified"; + isSuccess = true; + + // If we have data + } else { + + isSuccess = ajaxConvert( s, response ); + statusText = isSuccess.state; + success = isSuccess.data; + error = isSuccess.error; + isSuccess = !error; + } + } else { + // We extract error from statusText + // then normalize statusText and status for non-aborts + error = statusText; + if ( !statusText || status ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ), + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + // Attach deferreds + deferred.promise( jqXHR ); + jqXHR.success = jqXHR.done; + jqXHR.error = jqXHR.fail; + jqXHR.complete = completeDeferred.add; + + // Status-dependent callbacks + jqXHR.statusCode = function( map ) { + if ( map ) { + var tmp; + if ( state < 2 ) { + for ( tmp in map ) { + statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ]; + } + } else { + tmp = map[ jqXHR.status ]; + jqXHR.always( tmp ); + } + } + return this; + }; + + // Remove hash character (#7531: and string promotion) + // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) + // We also use the url parameter if available + s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); + + // Extract dataTypes list + s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace ); + + // A cross-domain request is in order when we have a protocol:host:port mismatch + if ( s.crossDomain == null ) { + parts = rurl.exec( s.url.toLowerCase() ) || false; + s.crossDomain = parts && ( parts.join(":") + ( parts[ 3 ] ? "" : parts[ 1 ] === "http:" ? 80 : 443 ) ) !== + ( ajaxLocParts.join(":") + ( ajaxLocParts[ 3 ] ? "" : ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ); + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( state === 2 ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + fireGlobals = s.global; + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // If data is available, append data to url + if ( s.data ) { + s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Get ifModifiedKey before adding the anti-cache parameter + ifModifiedKey = s.url; + + // Add anti-cache in url if needed + if ( s.cache === false ) { + + var ts = jQuery.now(), + // try replacing _= if it is there + ret = s.url.replace( rts, "$1_=" + ts ); + + // if nothing was replaced, add timestamp to the end + s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + ifModifiedKey = ifModifiedKey || s.url; + if ( jQuery.lastModified[ ifModifiedKey ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); + } + if ( jQuery.etag[ ifModifiedKey ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); + } + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? + s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { + // Abort if not done already and return + return jqXHR.abort(); + + } + + // aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + for ( i in { success: 1, error: 1, complete: 1 } ) { + jqXHR[ i ]( s[ i ] ); + } + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = setTimeout( function(){ + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + state = 1; + transport.send( requestHeaders, done ); + } catch (e) { + // Propagate exception as error if not done + if ( state < 2 ) { + done( -1, e ); + // Simply rethrow otherwise + } else { + throw e; + } + } + } + + return jqXHR; + }, + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {} + +}); + +/* Handles responses to an ajax request: + * - sets all responseXXX fields accordingly + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes, + responseFields = s.responseFields; + + // Fill responseXXX fields + for ( type in responseFields ) { + if ( type in responses ) { + jqXHR[ responseFields[type] ] = responses[ type ]; + } + } + + // Remove auto dataType and get content-type in the process + while( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "content-type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +// Chain conversions given the request and the original response +function ajaxConvert( s, response ) { + + var conv, conv2, current, tmp, + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(), + prev = dataTypes[ 0 ], + converters = {}, + i = 0; + + // Apply the dataFilter if provided + if ( s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + // Convert to each sequential dataType, tolerating list modification + for ( ; (current = dataTypes[++i]); ) { + + // There's only work to do if current dataType is non-auto + if ( current !== "*" ) { + + // Convert response if prev dataType is non-auto and differs from current + if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split(" "); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.splice( i--, 0, current ); + } + + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s["throws"] ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; + } + } + } + } + + // Update prev for next iteration + prev = current; + } + } + + return { state: "success", data: response }; +} +var oldCallbacks = [], + rquestion = /\?/, + rjsonp = /(=)\?(?=&|$)|\?\?/, + nonce = jQuery.now(); + +// Default jsonp settings +jQuery.ajaxSetup({ + jsonp: "callback", + jsonpCallback: function() { + var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); + this[ callback ] = true; + return callback; + } +}); + +// Detect, normalize options and install callbacks for jsonp requests +jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { + + var callbackName, overwritten, responseContainer, + data = s.data, + url = s.url, + hasCallback = s.jsonp !== false, + replaceInUrl = hasCallback && rjsonp.test( url ), + replaceInData = hasCallback && !replaceInUrl && typeof data === "string" && + !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && + rjsonp.test( data ); + + // Handle iff the expected data type is "jsonp" or we have a parameter to set + if ( s.dataTypes[ 0 ] === "jsonp" || replaceInUrl || replaceInData ) { + + // Get callback name, remembering preexisting value associated with it + callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? + s.jsonpCallback() : + s.jsonpCallback; + overwritten = window[ callbackName ]; + + // Insert callback into url or form data + if ( replaceInUrl ) { + s.url = url.replace( rjsonp, "$1" + callbackName ); + } else if ( replaceInData ) { + s.data = data.replace( rjsonp, "$1" + callbackName ); + } else if ( hasCallback ) { + s.url += ( rquestion.test( url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; + } + + // Use data converter to retrieve json after script execution + s.converters["script json"] = function() { + if ( !responseContainer ) { + jQuery.error( callbackName + " was not called" ); + } + return responseContainer[ 0 ]; + }; + + // force json dataType + s.dataTypes[ 0 ] = "json"; + + // Install callback + window[ callbackName ] = function() { + responseContainer = arguments; + }; + + // Clean-up function (fires after converters) + jqXHR.always(function() { + // Restore preexisting value + window[ callbackName ] = overwritten; + + // Save back as free + if ( s[ callbackName ] ) { + // make sure that re-using the options doesn't screw things around + s.jsonpCallback = originalSettings.jsonpCallback; + + // save the callback name for future use + oldCallbacks.push( callbackName ); + } + + // Call if it was a function and we have a response + if ( responseContainer && jQuery.isFunction( overwritten ) ) { + overwritten( responseContainer[ 0 ] ); + } + + responseContainer = overwritten = undefined; + }); + + // Delegate to script + return "script"; + } +}); +// Install script dataType +jQuery.ajaxSetup({ + accepts: { + script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /javascript|ecmascript/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +}); + +// Handle cache's special case and global +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + s.global = false; + } +}); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function(s) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + + var script, + head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement; + + return { + + send: function( _, callback ) { + + script = document.createElement( "script" ); + + script.async = "async"; + + if ( s.scriptCharset ) { + script.charset = s.scriptCharset; + } + + script.src = s.url; + + // Attach handlers for all browsers + script.onload = script.onreadystatechange = function( _, isAbort ) { + + if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { + + // Handle memory leak in IE + script.onload = script.onreadystatechange = null; + + // Remove the script + if ( head && script.parentNode ) { + head.removeChild( script ); + } + + // Dereference the script + script = undefined; + + // Callback if not abort + if ( !isAbort ) { + callback( 200, "success" ); + } + } + }; + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709 and #4378). + head.insertBefore( script, head.firstChild ); + }, + + abort: function() { + if ( script ) { + script.onload( 0, 1 ); + } + } + }; + } +}); +var xhrCallbacks, + // #5280: Internet Explorer will keep connections alive if we don't abort on unload + xhrOnUnloadAbort = window.ActiveXObject ? function() { + // Abort all pending requests + for ( var key in xhrCallbacks ) { + xhrCallbacks[ key ]( 0, 1 ); + } + } : false, + xhrId = 0; + +// Functions to create xhrs +function createStandardXHR() { + try { + return new window.XMLHttpRequest(); + } catch( e ) {} +} + +function createActiveXHR() { + try { + return new window.ActiveXObject( "Microsoft.XMLHTTP" ); + } catch( e ) {} +} + +// Create the request object +// (This is still attached to ajaxSettings for backward compatibility) +jQuery.ajaxSettings.xhr = window.ActiveXObject ? + /* Microsoft failed to properly + * implement the XMLHttpRequest in IE7 (can't request local files), + * so we use the ActiveXObject when it is available + * Additionally XMLHttpRequest can be disabled in IE7/IE8 so + * we need a fallback. + */ + function() { + return !this.isLocal && createStandardXHR() || createActiveXHR(); + } : + // For all other browsers, use the standard XMLHttpRequest object + createStandardXHR; + +// Determine support properties +(function( xhr ) { + jQuery.extend( jQuery.support, { + ajax: !!xhr, + cors: !!xhr && ( "withCredentials" in xhr ) + }); +})( jQuery.ajaxSettings.xhr() ); + +// Create transport if the browser can provide an xhr +if ( jQuery.support.ajax ) { + + jQuery.ajaxTransport(function( s ) { + // Cross domain only allowed if supported through XMLHttpRequest + if ( !s.crossDomain || jQuery.support.cors ) { + + var callback; + + return { + send: function( headers, complete ) { + + // Get a new xhr + var handle, i, + xhr = s.xhr(); + + // Open the socket + // Passing null username, generates a login popup on Opera (#2865) + if ( s.username ) { + xhr.open( s.type, s.url, s.async, s.username, s.password ); + } else { + xhr.open( s.type, s.url, s.async ); + } + + // Apply custom fields if provided + if ( s.xhrFields ) { + for ( i in s.xhrFields ) { + xhr[ i ] = s.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( s.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( s.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !s.crossDomain && !headers["X-Requested-With"] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Need an extra try/catch for cross domain requests in Firefox 3 + try { + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + } catch( _ ) {} + + // Do send the request + // This may raise an exception which is actually + // handled in jQuery.ajax (so no try/catch here) + xhr.send( ( s.hasContent && s.data ) || null ); + + // Listener + callback = function( _, isAbort ) { + + var status, + statusText, + responseHeaders, + responses, + xml; + + // Firefox throws exceptions when accessing properties + // of an xhr when a network error occurred + // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) + try { + + // Was never called and is aborted or complete + if ( callback && ( isAbort || xhr.readyState === 4 ) ) { + + // Only called once + callback = undefined; + + // Do not keep as active anymore + if ( handle ) { + xhr.onreadystatechange = jQuery.noop; + if ( xhrOnUnloadAbort ) { + delete xhrCallbacks[ handle ]; + } + } + + // If it's an abort + if ( isAbort ) { + // Abort it manually if needed + if ( xhr.readyState !== 4 ) { + xhr.abort(); + } + } else { + status = xhr.status; + responseHeaders = xhr.getAllResponseHeaders(); + responses = {}; + xml = xhr.responseXML; + + // Construct response list + if ( xml && xml.documentElement /* #4958 */ ) { + responses.xml = xml; + } + + // When requesting binary data, IE6-9 will throw an exception + // on any attempt to access responseText (#11426) + try { + responses.text = xhr.responseText; + } catch( _ ) { + } + + // Firefox throws an exception when accessing + // statusText for faulty cross-domain requests + try { + statusText = xhr.statusText; + } catch( e ) { + // We normalize with Webkit giving an empty statusText + statusText = ""; + } + + // Filter status for non standard behaviors + + // If the request is local and we have data: assume a success + // (success with no data won't get notified, that's the best we + // can do given current implementations) + if ( !status && s.isLocal && !s.crossDomain ) { + status = responses.text ? 200 : 404; + // IE - #1450: sometimes returns 1223 when it should be 204 + } else if ( status === 1223 ) { + status = 204; + } + } + } + } catch( firefoxAccessException ) { + if ( !isAbort ) { + complete( -1, firefoxAccessException ); + } + } + + // Call complete if needed + if ( responses ) { + complete( status, statusText, responses, responseHeaders ); + } + }; + + if ( !s.async ) { + // if we're in sync mode we fire the callback + callback(); + } else if ( xhr.readyState === 4 ) { + // (IE6 & IE7) if it's in cache and has been + // retrieved directly we need to fire the callback + setTimeout( callback, 0 ); + } else { + handle = ++xhrId; + if ( xhrOnUnloadAbort ) { + // Create the active xhrs callbacks list if needed + // and attach the unload handler + if ( !xhrCallbacks ) { + xhrCallbacks = {}; + jQuery( window ).unload( xhrOnUnloadAbort ); + } + // Add to list of active xhrs callbacks + xhrCallbacks[ handle ] = callback; + } + xhr.onreadystatechange = callback; + } + }, + + abort: function() { + if ( callback ) { + callback(0,1); + } + } + }; + } + }); +} +var fxNow, timerId, + rfxtypes = /^(?:toggle|show|hide)$/, + rfxnum = new RegExp( "^(?:([-+])=|)(" + core_pnum + ")([a-z%]*)$", "i" ), + rrun = /queueHooks$/, + animationPrefilters = [ defaultPrefilter ], + tweeners = { + "*": [function( prop, value ) { + var end, unit, + tween = this.createTween( prop, value ), + parts = rfxnum.exec( value ), + target = tween.cur(), + start = +target || 0, + scale = 1, + maxIterations = 20; + + if ( parts ) { + end = +parts[2]; + unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + + // We need to compute starting value + if ( unit !== "px" && start ) { + // Iteratively approximate from a nonzero starting point + // Prefer the current property, because this process will be trivial if it uses the same units + // Fallback to end or a simple constant + start = jQuery.css( tween.elem, prop, true ) || end || 1; + + do { + // If previous iteration zeroed out, double until we get *something* + // Use a string for doubling factor so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + start = start / scale; + jQuery.style( tween.elem, prop, start + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // And breaking the loop if scale is unchanged or perfect, or if we've just had enough + } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations ); + } + + tween.unit = unit; + tween.start = start; + // If a +=/-= token was provided, we're doing a relative animation + tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end; + } + return tween; + }] + }; + +// Animations created synchronously will run synchronously +function createFxNow() { + setTimeout(function() { + fxNow = undefined; + }, 0 ); + return ( fxNow = jQuery.now() ); +} + +function createTweens( animation, props ) { + jQuery.each( props, function( prop, value ) { + var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( collection[ index ].call( animation, prop, value ) ) { + + // we're done with this property + return; + } + } + }); +} + +function Animation( elem, properties, options ) { + var result, + index = 0, + tweenerIndex = 0, + length = animationPrefilters.length, + deferred = jQuery.Deferred().always( function() { + // don't match elem in the :animated selector + delete tick.elem; + }), + tick = function() { + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + percent = 1 - ( remaining / animation.duration || 0 ), + index = 0, + length = animation.tweens.length; + + for ( ; index < length ; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ]); + + if ( percent < 1 && length ) { + return remaining; + } else { + deferred.resolveWith( elem, [ animation ] ); + return false; + } + }, + animation = deferred.promise({ + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { specialEasing: {} }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end, easing ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + // if we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + + for ( ; index < length ; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // resolve when we played the last frame + // otherwise, reject + if ( gotoEnd ) { + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + }), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length ; index++ ) { + result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + return result; + } + } + + createTweens( animation, props ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + jQuery.fx.timer( + jQuery.extend( tick, { + anim: animation, + queue: animation.opts.queue, + elem: elem + }) + ); + + // attach callbacks from options + return animation.progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( jQuery.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // not quite $.extend, this wont overwrite keys already present. + // also - reusing 'index' from above because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.split(" "); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length ; index++ ) { + prop = props[ index ]; + tweeners[ prop ] = tweeners[ prop ] || []; + tweeners[ prop ].unshift( callback ); + } + }, + + prefilter: function( callback, prepend ) { + if ( prepend ) { + animationPrefilters.unshift( callback ); + } else { + animationPrefilters.push( callback ); + } + } +}); + +function defaultPrefilter( elem, props, opts ) { + var index, prop, value, length, dataShow, tween, hooks, oldfire, + anim = this, + style = elem.style, + orig = {}, + handled = [], + hidden = elem.nodeType && isHidden( elem ); + + // handle queue: false promises + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always(function() { + // doing this makes sure that the complete handler will be called + // before this completes + anim.always(function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + }); + }); + } + + // height/width overflow pass + if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { + // Make sure that nothing sneaks out + // Record all 3 overflow attributes because IE does not + // change the overflow attribute when overflowX and + // overflowY are set to the same value + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Set display property to inline-block for height/width + // animations on inline elements that are having width/height animated + if ( jQuery.css( elem, "display" ) === "inline" && + jQuery.css( elem, "float" ) === "none" ) { + + // inline-level elements accept inline-block; + // block-level elements need to be inline with layout + if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) { + style.display = "inline-block"; + + } else { + style.zoom = 1; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + if ( !jQuery.support.shrinkWrapBlocks ) { + anim.done(function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + }); + } + } + + + // show/hide pass + for ( index in props ) { + value = props[ index ]; + if ( rfxtypes.exec( value ) ) { + delete props[ index ]; + if ( value === ( hidden ? "hide" : "show" ) ) { + continue; + } + handled.push( index ); + } + } + + length = handled.length; + if ( length ) { + dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} ); + if ( hidden ) { + jQuery( elem ).show(); + } else { + anim.done(function() { + jQuery( elem ).hide(); + }); + } + anim.done(function() { + var prop; + jQuery.removeData( elem, "fxshow", true ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + }); + for ( index = 0 ; index < length ; index++ ) { + prop = handled[ index ]; + tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 ); + orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop ); + + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = tween.start; + if ( hidden ) { + tween.end = tween.start; + tween.start = prop === "width" || prop === "height" ? 1 : 0; + } + } + } + } +} + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || "swing"; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + if ( tween.elem[ tween.prop ] != null && + (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { + return tween.elem[ tween.prop ]; + } + + // passing any value as a 4th parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails + // so, simple values such as "10px" are parsed to Float. + // complex values such as "rotate(1rad)" are returned as is. + result = jQuery.css( tween.elem, tween.prop, false, "" ); + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + // use step hook for back compat - use cssHook if its there - use .style if its + // available and use plain properties where available + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Remove in 2.0 - this supports IE8's panic based approach +// to setting things on disconnected nodes + +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.each([ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" || + // special check for .toggle( handler, handler, ... ) + ( !i && jQuery.isFunction( speed ) && jQuery.isFunction( easing ) ) ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +}); + +jQuery.fn.extend({ + fadeTo: function( speed, to, easing, callback ) { + + // show any hidden elements after setting opacity to 0 + return this.filter( isHidden ).css( "opacity", 0 ).show() + + // animate to the value specified + .end().animate({ opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations resolve immediately + if ( empty ) { + anim.stop( true ); + } + }; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each(function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = jQuery._data( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // start the next in the queue if the last step wasn't forced + // timers currently will call their complete callbacks, which will dequeue + // but only if they were gotoEnd + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + }); + } +}); + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + attrs = { height: type }, + i = 0; + + // if we include width, step value is 1 to do all cssExpand values, + // if we don't include width, step value is 2 to skip over Left and Right + includeWidth = includeWidth? 1 : 0; + for( ; i < 4 ; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +// Generate shortcuts for custom animations +jQuery.each({ + slideDown: genFx("show"), + slideUp: genFx("hide"), + slideToggle: genFx("toggle"), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +}); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : + opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; + + // normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p*Math.PI ) / 2; + } +}; + +jQuery.timers = []; +jQuery.fx = Tween.prototype.init; +jQuery.fx.tick = function() { + var timer, + timers = jQuery.timers, + i = 0; + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + // Checks the timer has not already been removed + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } +}; + +jQuery.fx.timer = function( timer ) { + if ( timer() && jQuery.timers.push( timer ) && !timerId ) { + timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); + } +}; + +jQuery.fx.interval = 13; + +jQuery.fx.stop = function() { + clearInterval( timerId ); + timerId = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + // Default speed + _default: 400 +}; + +// Back Compat <1.8 extension point +jQuery.fx.step = {}; + +if ( jQuery.expr && jQuery.expr.filters ) { + jQuery.expr.filters.animated = function( elem ) { + return jQuery.grep(jQuery.timers, function( fn ) { + return elem === fn.elem; + }).length; + }; +} +var rroot = /^(?:body|html)$/i; + +jQuery.fn.offset = function( options ) { + if ( arguments.length ) { + return options === undefined ? + this : + this.each(function( i ) { + jQuery.offset.setOffset( this, options, i ); + }); + } + + var docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft, + box = { top: 0, left: 0 }, + elem = this[ 0 ], + doc = elem && elem.ownerDocument; + + if ( !doc ) { + return; + } + + if ( (body = doc.body) === elem ) { + return jQuery.offset.bodyOffset( elem ); + } + + docElem = doc.documentElement; + + // Make sure it's not a disconnected DOM node + if ( !jQuery.contains( docElem, elem ) ) { + return box; + } + + // If we don't have gBCR, just use 0,0 rather than error + // BlackBerry 5, iOS 3 (original iPhone) + if ( typeof elem.getBoundingClientRect !== "undefined" ) { + box = elem.getBoundingClientRect(); + } + win = getWindow( doc ); + clientTop = docElem.clientTop || body.clientTop || 0; + clientLeft = docElem.clientLeft || body.clientLeft || 0; + scrollTop = win.pageYOffset || docElem.scrollTop; + scrollLeft = win.pageXOffset || docElem.scrollLeft; + return { + top: box.top + scrollTop - clientTop, + left: box.left + scrollLeft - clientLeft + }; +}; + +jQuery.offset = { + + bodyOffset: function( body ) { + var top = body.offsetTop, + left = body.offsetLeft; + + if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) { + top += parseFloat( jQuery.css(body, "marginTop") ) || 0; + left += parseFloat( jQuery.css(body, "marginLeft") ) || 0; + } + + return { top: top, left: left }; + }, + + setOffset: function( elem, options, i ) { + var position = jQuery.css( elem, "position" ); + + // set position first, in-case top/left are set even on static elem + if ( position === "static" ) { + elem.style.position = "relative"; + } + + var curElem = jQuery( elem ), + curOffset = curElem.offset(), + curCSSTop = jQuery.css( elem, "top" ), + curCSSLeft = jQuery.css( elem, "left" ), + calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, + props = {}, curPosition = {}, curTop, curLeft; + + // need to be able to calculate position if either top or left is auto and position is either absolute or fixed + if ( calculatePosition ) { + curPosition = curElem.position(); + curTop = curPosition.top; + curLeft = curPosition.left; + } else { + curTop = parseFloat( curCSSTop ) || 0; + curLeft = parseFloat( curCSSLeft ) || 0; + } + + if ( jQuery.isFunction( options ) ) { + options = options.call( elem, i, curOffset ); + } + + if ( options.top != null ) { + props.top = ( options.top - curOffset.top ) + curTop; + } + if ( options.left != null ) { + props.left = ( options.left - curOffset.left ) + curLeft; + } + + if ( "using" in options ) { + options.using.call( elem, props ); + } else { + curElem.css( props ); + } + } +}; + + +jQuery.fn.extend({ + + position: function() { + if ( !this[0] ) { + return; + } + + var elem = this[0], + + // Get *real* offsetParent + offsetParent = this.offsetParent(), + + // Get correct offsets + offset = this.offset(), + parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); + + // Subtract element margins + // note: when an element has margin: auto the offsetLeft and marginLeft + // are the same in Safari causing offset.left to incorrectly be 0 + offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0; + offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0; + + // Add offsetParent borders + parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0; + parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0; + + // Subtract the two offsets + return { + top: offset.top - parentOffset.top, + left: offset.left - parentOffset.left + }; + }, + + offsetParent: function() { + return this.map(function() { + var offsetParent = this.offsetParent || document.body; + while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) { + offsetParent = offsetParent.offsetParent; + } + return offsetParent || document.body; + }); + } +}); + + +// Create scrollLeft and scrollTop methods +jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) { + var top = /Y/.test( prop ); + + jQuery.fn[ method ] = function( val ) { + return jQuery.access( this, function( elem, method, val ) { + var win = getWindow( elem ); + + if ( val === undefined ) { + return win ? (prop in win) ? win[ prop ] : + win.document.documentElement[ method ] : + elem[ method ]; + } + + if ( win ) { + win.scrollTo( + !top ? val : jQuery( win ).scrollLeft(), + top ? val : jQuery( win ).scrollTop() + ); + + } else { + elem[ method ] = val; + } + }, method, val, arguments.length, null ); + }; +}); + +function getWindow( elem ) { + return jQuery.isWindow( elem ) ? + elem : + elem.nodeType === 9 ? + elem.defaultView || elem.parentWindow : + false; +} +// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods +jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { + jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { + // margin is only for outerHeight, outerWidth + jQuery.fn[ funcName ] = function( margin, value ) { + var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), + extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); + + return jQuery.access( this, function( elem, type, value ) { + var doc; + + if ( jQuery.isWindow( elem ) ) { + // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there + // isn't a whole lot we can do. See pull request at this URL for discussion: + // https://github.com/jquery/jquery/pull/764 + return elem.document.documentElement[ "client" + name ]; + } + + // Get document width or height + if ( elem.nodeType === 9 ) { + doc = elem.documentElement; + + // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest + // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it. + return Math.max( + elem.body[ "scroll" + name ], doc[ "scroll" + name ], + elem.body[ "offset" + name ], doc[ "offset" + name ], + doc[ "client" + name ] + ); + } + + return value === undefined ? + // Get width or height on the element, requesting but not forcing parseFloat + jQuery.css( elem, type, value, extra ) : + + // Set width or height on the element + jQuery.style( elem, type, value, extra ); + }, type, chainable ? margin : undefined, chainable, null ); + }; + }); +}); +// Expose jQuery to the global object +window.jQuery = window.$ = jQuery; + +// Expose jQuery as an AMD module, but only for AMD loaders that +// understand the issues with loading multiple versions of jQuery +// in a page that all might call define(). The loader will indicate +// they have special allowances for multiple jQuery versions by +// specifying define.amd.jQuery = true. Register as a named module, +// since jQuery can be concatenated with other files that may use define, +// but not use a proper concatenation script that understands anonymous +// AMD modules. A named AMD is safest and most robust way to register. +// Lowercase jquery is used because AMD module names are derived from +// file names, and jQuery is normally delivered in a lowercase file name. +// Do this after creating the global so that if an AMD module wants to call +// noConflict to hide this version of jQuery, it will work. +if ( typeof define === "function" && define.amd && define.amd.jQuery ) { + define( "jquery", [], function () { return jQuery; } ); +} + +})( window ); +if(!window['googleLT_']){window['googleLT_']=(new Date()).getTime();}if (!window['google']) { +window['google'] = {}; +} +if (!window['google']['loader']) { +window['google']['loader'] = {}; +google.loader.ServiceBase = 'https://www.google.com/uds'; +google.loader.GoogleApisBase = 'https://ajax.googleapis.com/ajax'; +google.loader.ApiKey = 'notsupplied'; +google.loader.KeyVerified = true; +google.loader.LoadFailure = false; +google.loader.Secure = true; +google.loader.GoogleLocale = 'www.google.com'; +google.loader.ClientLocation = null; +google.loader.AdditionalParams = ''; +(function() {var d=encodeURIComponent,g=window,h=document;function l(a,b){return a.load=b}var m="replace",n="charAt",q="getTime",r="setTimeout",u="push",v="indexOf",w="ServiceBase",x="name",y="length",z="prototype",A="loader",B="substring",C="join",D="toLowerCase";function E(a){return a in F?F[a]:F[a]=-1!=navigator.userAgent[D]()[v](a)}var F={};function G(a,b){var c=function(){};c.prototype=b[z];a.U=b[z];a.prototype=new c} +function H(a,b,c){var e=Array[z].slice.call(arguments,2)||[];return function(){return a.apply(b,e.concat(Array[z].slice.call(arguments)))}}function I(a){a=Error(a);a.toString=function(){return this.message};return a}function J(a,b){for(var c=a.split(/\./),e=g,f=0;f\x3c/script>"):(E("safari")||E("konqueror"))&&g[r](aa,10)),P[u](a)):Q(g,"load",a)};L("google.setOnLoadCallback",google.T); +function Q(a,b,c){if(a.addEventListener)a.addEventListener(b,c,!1);else if(a.attachEvent)a.attachEvent("on"+b,c);else{var e=a["on"+b];a["on"+b]=null!=e?ba([c,e]):c}}function ba(a){return function(){for(var b=0;b\x3c/script>'):"css"==a&&h.write('')}; +L("google.loader.writeLoadTag",google[A].d);google[A].Q=function(a){O=a};L("google.loader.rfm",google[A].Q);google[A].S=function(a){for(var b in a)"string"==typeof b&&b&&":"==b[n](0)&&!N[b]&&(N[b]=new T(b[B](1),a[b]))};L("google.loader.rpl",google[A].S);google[A].R=function(a){if((a=a.specs)&&a[y])for(var b=0;b",Gf="?",waa="@",Hf="A",xaa="APPLET",yaa="AREA",zaa="BASE",If="BR",Jf="BUTTON",Aaa="COL",Baa="COMMAND",Kf="CSS1Compat",Caa="Can't combine significant digits and minimum fraction digits",Lf="Column ",Daa="Const{",Mf="Container is not defined",Nf="DAY",Eaa="Date(",Of="December",Pf="E",Faa="EMBED",Gaa="Etc/GMT",Rf="F",Haa="FRAME",Sf="February",Iaa="G",Jaa="GMT",Kaa="H",Tf="HH:mm",Laa="HOUR",Uf="HR",Maa="IFRAME",Naa="IMG",Vf="INPUT",Oaa="ISINDEX",Paa="JavaScript",Qaa="K",Raa="KEYGEN", +Wf="L",Saa="LINK",Xf="M",Taa="META",Yf="MILLISECOND",Uaa="MINUTE",Zf="MMM d",$f="MONTH",ag="MSIE",Vaa="Moz",Waa="MozOpacity",bg="N",Xaa="NOFRAMES",Yaa="NOSCRIPT",cg="November",dg="O",Zaa="OBJECT",$aa="PARAM",eg="Q",aba="Q yyyy",fg="QUARTER",bba="Row ",gg="S",hg="SCRIPT",cba="SECOND",ig="SELECT",jg="SOURCE",dba="STYLE",eba="SVG",kg="Saturday",lg="September",fba="Style",mg="T",gba="TABLE",ng="TBODY",og="TD",pg="TEXTAREA",qg="TL",tg="TR",hba="TRACK",ug="Thursday",iba="Too many percent/permill",vg="Trident", +jba="Type mismatch. Value ",kba="UTC",lba="Uneven number of arguments",wg="W",mba="WBR",nba="WEEK",oba="Webkit",xg="Wednesday",pba="Width",yg="YEAR",zg="Z",qba="[",rba="[object Array]",sba="[object Function]",tba="[object Window]",uba="\\",vba="\\$1",Ag="\\\\",Bg="\\s",wba="\\u",xba="\\x08",Cg="]",yba="]+",zba="___clazz$",Aba="_bar_format_old_value",Dg="_default_",Eg="a",Bba="a String",Fg="absolute",Gg="action",Cba="alpha(opacity=",Dba="amp",Eba="an Array",Hg="area",Ig="aria-",Lg="array",Mg="auto", +Ng="b",Og="background-color:",Fba="bar.groupWidth",Pg="body",Qg="boolean",Gba="borderBottom",Hba="borderBottomWidth",Iba="borderLeft",Jba="borderLeftWidth",Kba="borderRight",Lba="borderRightWidth",Mba="borderTop",Nba="borderTopWidth",Rg="both",Sg="br",Tg="c",Oba="call",Pba="charteditor",Qba="class",Rba="className",Sba="clearMinutes",Tba="color:",Ug="column",Uba="columnFilters[",Vba="compare",Vg="d",Wg="data",Wba="data-",Xg="date",$g="datetime",Xba="decimalSymbol",Yba="desc",ah="direction",bh="display", +ch="div",Zba="document",dh="en",eh="f",fh="false",gh="filter",hh="fixed",ih="focus",$ba="for",aca="formatType",bca="fractionDigits",jh="full",kh="function",lh="g",cca="google-visualization-formatters-arrow-dr",dca="google-visualization-formatters-arrow-empty",eca="google-visualization-formatters-arrow-ug",fca="google.charts.",gca="google.loader.GoogleApisBase",hca="google.maps.DirectionsService",ica="google.visualization.",jca="google.visualization.ModulePath",kca="google.visualization.NumberFormat", +lca="google.visualization.Version",mca="groupingSymbol",nca="gt",mh="h",nh="h:mm a",oh="head",rh="height",oca="hex",sh="hidden",th="horizontal",uh="href",vh="html",wh="https",xh="iframe",yh="img",zh="inline",pca="innerText",Ah="input",Bh="k",Ch="left",Dh="link",Eh="long",qca="lt",Fh="m",Gh="maps",Hh="maxValue",Kh="medium",rca="meta",Lh="minValue",sca="ms",tca="named",uca="native code",vca="negativeColor",wca="negativeParens",xca="new ",O="none",Mh="null",Nh="number",Oh="o",Ph="object",Qh="on",Rh= +"opacity",yca="outerHTML",Sh="overflow",zca="paddingBottom",Aca="paddingLeft",Bca="paddingRight",Cca="paddingTop",Th="pattern",Dca="pixelHeight",Eca="pixelLeft",Fca="pixelWidth",Uh="position",Vh="prefix",P="px",Gca="quot",Wh="r",Xh="relative",Yh="rgb",Zh="role",$h="rtl",ai="s",Hca="scaleFactor",bi="script",ci="selection",Ica="sensor=false",di="short",ei="single",fi="solid",Jca="sortColumns",Kca="sortColumns[",Lca="sourceIndex",Mca="splice",gi="src",hi="static",ii="string",ji="style",Nca="stylesheet", +ki="suffix",Oca="tabIndex",Pca="tabindex",Qca="text/css",li="text/javascript",Rca="textContent",Sca="the wrong type of data",mi="time",Tca="timeZone",ni="timeofday",Uca="track",oi="transparent",pi="true",qi="type",Vca="type_error:Const",Wca="type_error:SafeHtml",Xca="type_error:SafeStyle",Yca="type_error:SafeUrl",Zca="type_error:TrustedResourceUrl",ri="unselectable",si="v",ti="value",$ca="valueType",ada="var ",bda="var _et_ = 1;",ui="vertical",vi="visible",cda="visualization",wi="w",xi="white",yi= +"width",zi="y",Ai="z",dda="zClosurez",eda="zoomButtonsOrder",Bi="{",sda="{0}",tda="{1}",uda="|[",Ci="}",Di="\u00a0",vda="\u00a4",wda="\u2030",R,Ei=Ei||{},Fi=this;function Gi(a){return void 0!==a}function Hi(a,b,c){a=a[zc](mf);c=c||Fi;a[0]in c||!c[id]||c[id](ada+a[0]);for(var d;a[J]&&(d=a[wb]());)!a[J]&&Gi(b)?c[d]=b:c=c[d]?c[d]:c[d]={}}function Ii(a,b){for(var c=a[zc](mf),d=b||Fi,e;e=c[wb]();)if(null!=d[e])d=d[e];else return null;return d}function Ji(){} +function Ki(a){a.ac=function(){return a.fga?a.fga:a.fga=new a}}function Li(a){var b=typeof a;if(b==Ph)if(a){if(a instanceof ga)return Lg;if(a instanceof ca)return b;var c=ca[K][qc][L](a);if(c==tba)return Ph;if(c==rba||typeof a[J]==Nh&&"undefined"!=typeof a[Ee]&&"undefined"!=typeof a[sc]&&!a[sc](Mca))return Lg;if(c==sba||"undefined"!=typeof a[L]&&"undefined"!=typeof a[sc]&&!a[sc](Oba))return kh}else return Mh;else if(b==kh&&"undefined"==typeof a[L])return Ph;return b} +function Mi(a){return null===a}function Ni(a){return null!=a}function Oi(a){return Li(a)==Lg}function Pi(a){var b=Li(a);return b==Lg||b==Ph&&typeof a[J]==Nh}function Qi(a){return Ri(a)&&typeof a[Rc]==kh}function Si(a){return typeof a==ii}function Ti(a){return typeof a==Qg}function Ui(a){return typeof a==Nh}function Vi(a){return Li(a)==kh}function Ri(a){var b=typeof a;return b==Ph&&null!=a||b==kh}function Wi(a){return a[xda]||(a[xda]=++yda)}var xda="closure_uid_"+(1E9*h[Pc]()>>>0),yda=0; +function zda(a,b,c){return a[L][Zc](a[fc],arguments)}function Ada(a,b,c){if(!a)throw m();if(2/g,Ida=/"/g,Jda=/'/g,Kda=/\x00/g,Lda=/[\x00&<>"']/;function Mda(a){return gj(a,We)?Zba in Fi?Nda(a):Oda(a):a} +function Nda(a){var b={"&":We,"<":Af,">":Ff,""":Me},c;c=Fi[ce][Vb](ch);return a[Ab](Pda,function(a,e){var f=b[a];if(f)return f;if(e[Ib](0)==Oe){var g=ha(pf+e[mc](1));fa(g)||(f=String[Gd](g))}f||(Xa(c,a+Ke),f=c[Yb][jd][qd](0,-1));return b[a]=f})}function Oda(a){return a[Ab](/&([^;]+);/g,function(a,c){switch(c){case Dba:return We;case qca:return Af;case nca:return Ff;case Gca:return Me;default:if(c[Ib](0)==Oe){var d=ha(pf+c[mc](1));if(!fa(d))return String[Gd](d)}return a}})}var Pda=/&([^;\s<&]+);?/g; +function hj(a,b){a[J]>b&&(a=a[we](0,b-3)+nf);return a}function gj(a,b){return-1!=a[zd](b)}function ij(a,b){return ga(b+1)[Fe](a)}function jj(a,b){var c=Gi(void 0)?a[Bb](void 0):String(a),d=c[zd](mf);-1==d&&(d=c[J]);return ij(pf,h.max(0,b-d))+c}function kj(a){return null==a?M:String(a)}function Qda(a){return ga[K][Fe][L](arguments,M)} +function lj(a,b){for(var c=0,d=ej(String(a))[zc](mf),e=ej(String(b))[zc](mf),f=h.max(d[J],e[J]),g=0;0==c&&gb?1:0}function nj(a){for(var b=0,c=0;cc?h.max(0,a[J]+c):c;if(Si(a))return Si(b)&&1==b[J]?a[zd](b,c):-1;for(;cc&&(c=h.max(0,a[J]+c));if(Si(a))return Si(b)&&1==b[J]?a[ne](b,c):-1;for(;0<=c;c--)if(c in a&&a[c]===b)return c;return-1},X=rj[Zb]?function(a,b,c){rj[Zb][L](a,b,c)}:function(a,b,c){for(var d= +a[J],e=Si(a)?a[zc](M):a,f=0;fb?null:Si(a)?a[Ib](b):a[b]} +function Bj(a,b,c){for(var d=a[J],e=Si(a)?a[zc](M):a,f=0;fc?null:Si(a)?a[Ib](c):a[c]}function Dj(a,b){return 0<=sj(a,b)}function Ej(a){return 0==a[J]}function Fj(a){if(!Oi(a))for(var b=a[J]-1;0<=b;b--)delete a[b];mb(a,0)}function Gj(a,b,c){Hj(a,c,0,b)} +function Ij(a,b){var c=sj(a,b),d;(d=0<=c)&&rj[Ee][L](a,c,1);return d}function Kj(a){return rj[Hb][Zc](rj,arguments)}function Lj(a){var b=a[J];if(0=arguments[J]?rj[qd][L](a,b):rj[qd][L](a,b,c)} +function Vda(a){for(var b={},c=0,d=0;d>1,n;n=c?b[L](e,a[l],l,a):b(d,a[l]);0b?1:a1*(a-0))return[];for(var c=0;c=f[J])return b;d[B](f[c])}b[B](d)}};function Zj(a,b,c){for(var d in a)b[L](c,a[d],d,a)}function ak(a,b,c){var d={},e;for(e in a)d[e]=b[L](c,a[e],e,a);return d}function bk(a,b){for(var c in a)if(b[L](void 0,a[c],c,a))return!0;return!1}function ck(a,b,c){for(var d in a)if(!b[L](c,a[d],d,a))return!1;return!0}function cea(a){var b=0,c;for(c in a)b++;return b}function dk(a){for(var b in a)return a[b]}function ek(a){var b=[],c=0,d;for(d in a)b[c++]=a[d];return b}function fk(a){var b=[],c=0,d;for(d in a)b[c++]=d;return b} +function gk(a,b){for(var c in a)if(a[c]==b)return!0;return!1}function hk(a){for(var b in a)return!1;return!0}function ik(a,b){b in a&&delete a[b]}function jk(a,b,c){if(b in a)throw m('The object already contains the key "'+b+Me);a[b]=c}function kk(a,b,c){return b in a?a[b]:c}function lk(a,b,c){return b in a?a[b]:a[b]=c}function dea(a,b){for(var c in a)if(!(c in b)||a[c]!==b[c])return!1;for(c in b)if(!(c in a))return!1;return!0}function mk(a){var b={},c;for(c in a)b[c]=a[c];return b} +function nk(a){var b=Li(a);if(b==Ph||b==Lg){if(a[Jc])return a[Jc]();var b=b==Lg?[]:{},c;for(c in a)b[c]=nk(a[c]);return b}return a}function ok(a){var b={},c;for(c in a)b[a[c]]=c;return b}var eea="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" ");function pk(a,b){for(var c,d,e=1;e]*>|&[^;]+;/g;function rk(a,b){return b?a[Ab](hea,M):a}var iea=/[A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff]/,jea=/^[^A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff]*[\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc]/,kea=/^http:\/\/.*/,lea=/^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_](Arab|Hebr|Thaa|Nkoo|Tfng))(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)/i; +function sk(){return lea[od](tk(Pba)||dh)}var mea=/\s+/,nea=/\d/;function oea(a,b){for(var c=0,d=0,e=!1,f=rk(a,b)[zc](mea),g=0;g.");if(a[He]()in Bea)throw m("Tag name <"+a+"> is not allowed for SafeHtml.");var d=null,e=Af+a;if(b)for(var f in b){if(!zea[od](f))throw m('Invalid attribute name "'+f+'".');var g=b[f];if(null!=g){var k,l=a;k=f;if(g instanceof uk)g=qea(g);else if(k[He]()==ji){if(!Ri(g))throw m('The "style" attribute requires goog.html.SafeStyle or map of style properties, '+typeof g+" given: "+g);if(!(g instanceof vk)){var l=M,n=void 0;for(n in g){if(!/^[-_a-zA-Z0-9]+$/[od](n))throw m("Name allows only [-_a-zA-Z0-9], got: "+ +n);var p=g[n];null!=p&&(p instanceof uk?p=qea(p):uea[od](p)||(p=dda),l+=n+xf+p+zf)}g=l?sea(l):tea}l=void 0;l=g instanceof vk&&g[Bc]===vk&&g.Lua===rea?g.K4:Xca;g=l}else{if(/^on/i[od](k))throw m('Attribute "'+k+'" requires goog.string.Const value, "'+g+'" given.');if(k[He]()in Aea)if(g instanceof yk)g=g instanceof yk&&g[Bc]===yk&&g.Nua===wea?g.aga:Zca;else if(g instanceof xk)g=g instanceof xk&&g[Bc]===xk&&g.Mua===vea?g.gF:Yca;else throw m('Attribute "'+k+'" on tag "'+l+'" requires goog.html.SafeUrl or goog.string.Const value, "'+ +g+'" given.');}g.iF&&(g=g.hF());k=k+Ef+fj(String(g))+Me;e+=Ke+k}}Gi(c)?Oi(c)||(c=[c]):c=[];!0===gea[a[He]()]?e+=Ff:(d=Ek(c),e+=Ff+Ak(d)+saa+a+Ff,d=d.ow());(a=b&&b.dir)&&(d=/^(ltr|rtl|auto)$/i[od](a)?0:null);return Ck(e,d)}function Ek(a){function b(a){Oi(a)?X(a,b):(a=Bk(a),d+=Ak(a),a=a.ow(),0==c?c=a:0!=a&&c!=a&&(c=null))}var c=0,d=M;X(arguments,b);return Ck(d,c)}var xea={};function Ck(a,b){var c=new zk;c.gF=a;c.Fga=b;return c}var Hk=Ck(M,0);function Ik(a){return function(){return a}}var Cea=Ik(!0),Jk=Ik(null);function Kk(a){return a}function Dea(a){var b;b=b||0;return function(){return a[Zc](this,ga[K][qd][L](arguments,0,b))}}function Eea(){return function(){return!Mi[Zc](this,arguments)}};function Lk(a,b,c){return h.min(h.max(a,b),c)}function Mk(a,b){var c=a%b;return 0>c*b?c+b:c}function Nk(a,b,c){return a+c*(b-a)}function Ok(a){return a*h.PI/180}function Pk(a,b){return b*h.cos(Ok(a))}function Qk(a,b){return b*h.sin(Ok(a))}function Rk(a,b,c,d){return Mk(180*h[Id](d-b,c-a)/h.PI,360)}function Sk(a){return 0==a?0:0>a?-1:1}function Tk(a){return xj(arguments,function(a,c){return a+c},0)}function Uk(a){return Tk[Zc](null,arguments)/arguments[J]}function Vk(a){return la(a)&&0==a%1} +function Wk(a){return la(a)&&!fa(a)};var Xk="StopIteration"in Fi?Fi.StopIteration:m("StopIteration");function Yk(){}Da(Yk[K],function(){throw Xk;});Yk[K].pt=function(){return this};function Zk(a){if(a instanceof Yk)return a;if(typeof a.pt==kh)return a.pt(!1);if(Pi(a)){var b=0,c=new Yk;Da(c,function(){for(;;){if(b>=a[J])throw Xk;if(b in a)return a[b++];b++}});return c}throw m("Not implemented");} +function $k(a,b,c){if(Pi(a))try{X(a,b,c)}catch(d){if(d!==Xk)throw d;}else{a=Zk(a);try{for(;;)b[L](c,a[yc](),void 0,a)}catch(e){if(e!==Xk)throw e;}}}function al(a,b,c){var d=0,e=a,f=c||1;1=e||0>f&&d<=e)throw Xk;var a=d;d+=f;return a});return g}function Fea(a,b,c){var d=Zk(a);a=new Yk;Da(a,function(){var a=d[yc]();return b[L](c,a,void 0,d)});return a} +function Gea(a){return Hea(arguments)}function Hea(a){var b=Zk(a);a=new Yk;var c=null;Da(a,function(){for(;;){if(null==c){var a=b[yc]();c=Zk(a)}try{return c[yc]()}catch(e){if(e!==Xk)throw e;c=null}}});return a}function Iea(a){if(Pi(a))return Lj(a);a=Zk(a);var b=[];$k(a,function(a){b[B](a)});return b}function Jea(a){try{return Zk(a)[yc]()}catch(b){if(b!=Xk)throw b;return null}};function bl(a,b){this.cb={};this.me=[];this.iz=this.Rb=0;var c=arguments[J];if(12*this.Rb&&cl(this),!0):!1}); +function cl(a){if(a.Rb!=a.me[J]){for(var b=0,c=0;b=c[J])throw Xk;var g=c[b++];return a?g:d[g]}});return g}; +function dl(a,b){return ca[K][Hc][L](a,b)};function Lea(a){return typeof a.Vb==kh?a.Vb():Pi(a)||Si(a)?a[J]:cea(a)}function el(a){if(typeof a.Qa==kh)return a.Qa();if(Si(a))return a[zc](M);if(Pi(a)){for(var b=[],c=a[J],d=0;db)return!1;!(a instanceof hl)&&5ka(a))?String(b):a}(),Vea={};function ul(a){return Vea[a]||(Vea[a]=0<=lj(tl,a))}function vl(a){return ol&&Wea>=a}var Xea=Fi[ce],Wea=Xea&&ol?Uea()||(Xea[te]==Kf?ja(tl,10):5):void 0;function wl(a,b){Xa(a,Ak(b))};function xl(a,b){this.x=Gi(a)?a:0;this.y=Gi(b)?b:0}R=xl[K];Ia(R,function(){return new xl(this.x,this.y)});function yl(a,b){return a==b?!0:a&&b?a.x==b.x&&a.y==b.y:!1}function zl(a,b){var c=a.x-b.x,d=a.y-b.y;return h[Kd](c*c+d*d)}function Al(a,b){return new xl(a.x-b.x,a.y-b.y)}function Bl(a,b){return new xl(a.x+b.x,a.y+b.y)}qa(R,function(){this.x=h[Cb](this.x);this.y=h[Cb](this.y);return this});ra(R,function(){this.x=h[Eb](this.x);this.y=h[Eb](this.y);return this}); +Wa(R,function(){this.x=h[D](this.x);this.y=h[D](this.y);return this});fb(R,function(a,b){a instanceof xl?(this.x+=a.x,this.y+=a.y):(this.x+=a,Ui(b)&&(this.y+=b));return this});Na(R,function(a,b){var c=Ui(b)?b:a;this.x*=a;this.y*=c;return this});function Cl(a,b){na(this,a);Ta(this,b)}function Dl(a,b){return a==b?!0:a&&b?a[r]==b[r]&&a[z]==b[z]:!1}R=Cl[K];Ia(R,function(){return new Cl(this[r],this[z])});function El(a){return h.min(a[r],a[z])}R.area=function(){return this[r]*this[z]};Va(R,function(){return!this.area()});qa(R,function(){na(this,h[Cb](this[r]));Ta(this,h[Cb](this[z]));return this});ra(R,function(){na(this,h[Eb](this[r]));Ta(this,h[Eb](this[z]));return this});Wa(R,function(){na(this,h[D](this[r]));Ta(this,h[D](this[z]));return this}); +Na(R,function(a,b){var c=Ui(b)?b:a;na(this,this[r]*a);Ta(this,this[z]*c);return this});var Yea=!ol||vl(9),Zea=!pl&&!ol||ol&&vl(9)||pl&&ul("1.9.1"),$ea=ol&&!ul(wf),afa=ol||nl||ql;function Fl(a){return a?new Gl(Hl(a)):Cda||(Cda=new Gl)}function Il(a){return Si(a)?ea[ud](a):a}function Jl(a,b,c){return Kl(ea,a,b,c)}function Ll(a,b){var c=b||ea;return c[pe]&&c[Ub]?c[pe](mf+a):Kl(ea,ff,a,b)}function Ml(a,b){var c=b||ea,d=null;return(d=c[pe]&&c[Ub]?c[Ub](mf+a):Kl(ea,ff,a,b)[0])||null} +function Kl(a,b,c,d){a=d||a;b=b&&b!=ff?b[De]():M;if(a[pe]&&a[Ub]&&(b||c))return a[pe](b+(c?mf+c:M));if(c&&a[Ed]){a=a[Ed](c);if(b){d={};for(var e=0,f=0,g;g=a[f];f++)b==g[Cd]&&(d[e++]=g);mb(d,e);return d}return a}a=a[kc](b||ff);if(c){d={};for(f=e=0;g=a[f];f++)b=g[ae],typeof b[zc]==kh&&Dj(b[zc](/\s+/),c)&&(d[e++]=g);mb(d,e);return d}return a}function Nl(a,b){Zj(b,function(b,d){d==ji?bb(a[w],b):d==Qba?pb(a,b):d==$ba?a.htmlFor=b:d in bfa?a[v](bfa[d],b):bj(d,Ig)||bj(d,Wba)?a[v](d,b):a[d]=b})} +var bfa={cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",frameborder:"frameBorder",height:rh,maxlength:"maxLength",role:Zh,rowspan:"rowSpan",type:qi,usemap:"useMap",valign:"vAlign",width:yi};function Ol(a){a=a[ce];a=a[te]==Kf?a[lc]:a[ke];return new Cl(a[be],a[re])}function cfa(a){return ql||a[te]!=Kf?a[ke]||a[lc]:a[lc]}function Pl(a){return a?a.parentWindow||a[Md]:ba}function Ql(a,b,c){return dfa(ea,arguments)} +function dfa(a,b){var c=b[0],d=b[1];if(!Yea&&d&&(d[Nd]||d[H])){c=[Af,c];d[Nd]&&c[B](daa,fj(d[Nd]),Me);if(d[H]){c[B](eaa,fj(d[H]),Me);var e={};pk(e,d);delete e[H];d=e}c[B](Ff);c=c[Fe](M)}c=a[Vb](c);d&&(Si(d)?pb(c,d):Oi(d)?pb(c,d[Fe](Ke)):Nl(c,d));2a} +function mm(a){if($ea&&pca in a)a=a[Wd][Ab](/(\r\n|\r|\n)/g,Je);else{var b=[];nm(a,b,!0);a=b[Fe](M)}a=a[Ab](/ \xAD /g,Ke)[Ab](/\xAD/g,M);a=a[Ab](/\u200B/g,M);$ea||(a=a[Ab](/ +/g,Ke));a!=Ke&&(a=a[Ab](/^\s*/,M));return a}function om(a){var b=[];nm(a,b,!1);return b[Fe](M)}function nm(a,b,c){if(!(a[Cd]in nfa))if(3==a[rd])c?b[B](String(a[jd])[Ab](/(\r\n|\r|\n)/g,M)):b[B](a[jd]);else if(a[Cd]in ofa)b[B](ofa[a[Cd]]);else for(a=a[Yb];a;)nm(a,b,c),a=a[ic]} +function ffa(a){if(a&&typeof a[J]==Nh){if(Ri(a))return typeof a[xd]==kh||typeof a[xd]==ii;if(Vi(a))return typeof a[xd]==kh}return!1}function rfa(a){return pm(a,function(a){return a[Cd]==eba&&!0},!0,void 0)}function pm(a,b,c,d){c||(a=a[Ce]);c=null==d;for(var e=0;a&&(c||e<=d);){if(b(a))return a;a=a[Ce];e++}return null}function qm(a){try{return a&&a[ub]}catch(b){}return null}function Gl(a){this.Ze=a||Fi[ce]||ea}R=Gl[K];R.pa=Fl;R.oc=function(){return this.Ze}; +R.a=function(a){return Si(a)?this.Ze[ud](a):a};function rm(a,b,c,d){return Kl(a.Ze,b,c,d)}R.nu=function(a,b){return Ml(a,b||this.Ze)};R.h9=function(a,b){return Ml(a,b||this.Ze)};R.Bw=Nl;R.m=function(a,b,c){return dfa(this.Ze,arguments)};R.createElement=function(a){return this.Ze[Vb](a)};R.createTextNode=function(a){return this.Ze[Jb](String(a))}; +R.hha=function(a,b,c){var d=this.Ze;c=!!c;for(var e=d[Vb](gba),f=e[q](d[Vb](ng)),g=0;g=this[G]&&a[kd]<=this[kd]&&a.top>=this.top&&a[Uc]<=this[Uc]:a.x>=this[G]&&a.x<=this[kd]&&a.y>=this.top&&a.y<=this[Uc]:!1}); +oa(R,function(a,b,c,d){Ri(a)?(this.top-=a.top,Ua(this,this[kd]+a[kd]),Ma(this,this[Uc]+a[Uc]),$a(this,this[G]-a[G])):(this.top-=a,Ua(this,this[kd]+b),Ma(this,this[Uc]+c),$a(this,this[G]-d));return this});function vm(a,b){$a(a,h.min(a[G],b[G]));a.top=h.min(a.top,b.top);Ua(a,h.max(a[kd],b[kd]));Ma(a,h.max(a[Uc],b[Uc]))}function wm(a,b){return a[G]<=b[kd]&&b[G]<=a[kd]&&a.top<=b[Uc]&&b.top<=a[Uc]} +qa(R,function(){this.top=h[Cb](this.top);Ua(this,h[Cb](this[kd]));Ma(this,h[Cb](this[Uc]));$a(this,h[Cb](this[G]));return this});ra(R,function(){this.top=h[Eb](this.top);Ua(this,h[Eb](this[kd]));Ma(this,h[Eb](this[Uc]));$a(this,h[Eb](this[G]));return this});Wa(R,function(){this.top=h[D](this.top);Ua(this,h[D](this[kd]));Ma(this,h[D](this[Uc]));$a(this,h[D](this[G]));return this}); +fb(R,function(a,b){a instanceof xl?($a(this,this[G]+a.x),Ua(this,this[kd]+a.x),this.top+=a.y,Ma(this,this[Uc]+a.y)):($a(this,this[G]+a),Ua(this,this[kd]+a),Ui(b)&&(this.top+=b,Ma(this,this[Uc]+b)));return this});Na(R,function(a,b){var c=Ui(b)?b:a;$a(this,this[G]*a);Ua(this,this[kd]*a);this.top*=c;Ma(this,this[Uc]*c);return this});function xm(a,b,c,d){$a(this,a);this.top=b;na(this,c);Ta(this,d)}R=xm[K];Ia(R,function(){return new xm(this[G],this.top,this[r],this[z])});function ym(a){return new um(a.top,a[G]+a[r],a.top+a[z],a[G])}function zm(a){return new xm(a[G],a.top,a[kd]-a[G],a[Uc]-a.top)}function Am(a,b){return a==b?!0:a&&b?a[G]==b[G]&&a[r]==b[r]&&a.top==b.top&&a[z]==b[z]:!1} +R.lA=function(a){var b=h.max(this[G],a[G]),c=h.min(this[G]+this[r],a[G]+a[r]);if(b<=c){var d=h.max(this.top,a.top);a=h.min(this.top+this[z],a.top+a[z]);if(d<=a)return $a(this,b),this.top=d,na(this,c-b),Ta(this,a-d),!0}return!1};function tfa(a,b){var c=h.max(a[G],b[G]),d=h.min(a[G]+a[r],b[G]+b[r]);if(c<=d){var e=h.max(a.top,b.top),f=h.min(a.top+a[z],b.top+b[z]);if(e<=f)return new xm(c,e,d-c,f-e)}return null} +R.qm=function(a){var b=tfa(this,a);if(b&&b[z]&&b[r]){var b=[],c=this.top,d=this[z],e=this[G]+this[r],f=this.top+this[z],g=a[G]+a[r],k=a.top+a[z];a.top>this.top&&(b[B](new xm(this[G],this.top,this[r],a.top-this.top)),c=a.top,d-=a.top-this.top);kthis[G]&&b[B](new xm(this[G],c,a[G]-this[G],d));g=a[G]+a[r]&&this.top<=a.top&&this.top+this[z]>=a.top+a[z]:a.x>=this[G]&&a.x<=this[G]+this[r]&&a.y>=this.top&&a.y<=this.top+this[z]});function ufa(a,b){var c=b.xa[be]||a[Wb]>a[re]||c==hh||c==Fg||c==Xh))return a;return null} +function Nm(a){for(var b=new um(0,da,da,0),c=Fl(a),d=c.oc()[ke],e=c.oc()[lc],f=cfa(c.Ze);a=xfa(a);)if(!(ol&&0==a[be]||ql&&0==a[re]&&a==d)&&a!=d&&a!=e&&Gm(a,Sh)!=vi){var g=Om(a),k=new xl(a[$b],a[ac]);g.x+=k.x;g.y+=k.y;b.top=h.max(b.top,g.y);Ua(b,h.min(b[kd],g.x+a[be]));Ma(b,h.min(b[Uc],g.y+a[re]));$a(b,h.max(b[G],g.x))}d=f[Tc];f=f[Ud];$a(b,h.max(b[G],d));b.top=h.max(b.top,f);c=c.lC();c=Ol(c||ba);Ua(b,h.min(b[kd],d+c[r]));Ma(b,h.min(b[Uc],f+c[z]));return 0<=b.top&&0<=b[G]&&b[Uc]>b.top&&b[kd]>b[G]?b: +null}function Om(a){var b=Hl(a);Gm(a,Uh);var c=new xl(0,0),d=Lm(b);if(a==d)return c;a=Mm(a);b=tm(Fl(b));c.x=a[G]+b.x;c.y=a.top+b.y;return c}function Pm(a,b){var c=Qm(a),d=Qm(b);return new xl(c.x-d.x,c.y-d.y)}function yfa(a){a=Mm(a);return new xl(a[G],a.top)}function Qm(a){if(1==a[rd])return yfa(a);var b=Vi(a.wua),c=a;a[Nb]&&a[Nb][J]?c=a[Nb][0]:b&&a.Aa[Nb]&&a.Aa[Nb][J]&&(c=a.Aa[Nb][0]);return new xl(c[Qd],c[Rd])} +function Rm(a,b,c){if(b instanceof Cl)c=b[z],b=b[r];else if(void 0==c)throw m("missing height argument");Sm(a,b);Ta(a[w],Jm(c,!0))}function Jm(a,b){typeof a==Nh&&(a=(b?h[D](a):a)+P);return a}function Sm(a,b){na(a[w],Jm(b,!0))}function Tm(a){return Um(a)}function Um(a){var b=zfa;if(Gm(a,bh)!=O)return b(a);var c=a[w],d=c[cd],e=c.visibility,f=c[tc];kb(c,sh);Ba(c,Fg);Qa(c,zh);a=b(a);Qa(c,d);Ba(c,f);kb(c,e);return a} +function zfa(a){var b=a[Gb],c=a[fd],d=ql&&!b&&!c;return Gi(b)&&!d||!a[vb]?new Cl(b,c):(a=Mm(a),new Cl(a[kd]-a[G],a[Uc]-a.top))}function Vm(a){var b=Om(a);a=Um(a);return new xm(b.x,b.y,a[r],a[z])}function Afa(a,b){var c=a[w];Rh in c?qb(c,b):Waa in c?c.MozOpacity=b:gh in c&&(c.filter=b===M?M:Cba+100*b+ef)}function Wm(a,b){Qa(a[w],b?M:O)} +function Xm(a){var b=Fl(void 0),c=null,c=b.oc();if(ol&&c.createStyleSheet)b=c=c.createStyleSheet(),ol&&Gi(b.cssText)?bb(b,a):Xa(b,a);else{var d=rm(b,oh)[0];d||(c=rm(b,Pg)[0],d=b.m(oh),c[Ce][Lb](d,c));var e=c=b.m(ji);ol&&Gi(e.cssText)?bb(e,a):Xa(e,a);b[q](d,c)}return c}function Ym(a){return $h==Gm(a,ah)}var Zm=pl?"MozUserSelect":ql?"WebkitUserSelect":null; +function $m(a,b,c){c=c?null:a[kc](ff);if(Zm){if(b=b?O:M,a[w][Zm]=b,c){a=0;for(var d;d=c[a];a++)d[w][Zm]=b}}else if(ol||nl)if(b=b?Qh:M,a[v](ri,b),c)for(a=0;d=c[a];a++)d[v](ri,b)}function an(a){var b=Hl(a),c=ol&&a[ve];if(c&&sm(Fl(b))&&c[r]!=Mg&&c[z]!=Mg&&!c.boxSizing)return b=bn(a,c[r],yi,Fca),a=bn(a,c[z],rh,Dca),new Cl(b,a);c=new Cl(a[Gb],a[fd]);b=cn(a);a=dn(a);return new Cl(c[r]-a[G]-b[G]-b[kd]-a[kd],c[z]-a.top-b.top-b[Uc]-a[Uc])} +function bn(a,b,c,d){if(/^\d+px?$/[od](b))return ja(b,10);var e=a[w][c],f=a.runtimeStyle[c];a.runtimeStyle[c]=a[ve][c];a[w][c]=b;b=a[w][d];a[w][c]=e;a.runtimeStyle[c]=f;return b}function en(a,b){var c=a[ve]?a[ve][b]:null;return c?bn(a,c,Ch,Eca):0}function cn(a){if(ol){var b=en(a,Aca),c=en(a,Bca),d=en(a,Cca);a=en(a,zca);return new um(d,c,a,b)}b=Fm(a,Aca);c=Fm(a,Bca);d=Fm(a,Cca);a=Fm(a,zca);return new um(ka(d),ka(c),ka(a),ka(b))}var Bfa={thin:2,medium:4,thick:6}; +function fn(a,b){if((a[ve]?a[ve][b+fba]:null)==O)return 0;var c=a[ve]?a[ve][b+pba]:null;return c in Bfa?Bfa[c]:bn(a,c,Ch,Eca)}function dn(a){if(ol&&!vl(9)){var b=fn(a,Iba),c=fn(a,Kba),d=fn(a,Mba);a=fn(a,Gba);return new um(d,c,a,b)}b=Fm(a,Jba);c=Fm(a,Lba);d=Fm(a,Nba);a=Fm(a,Hba);return new um(ka(d),ka(c),ka(a),ka(b))}function gn(a){var b={};X(a[zc](/\s*;\s*/),function(a){a=a[zc](/\s*:\s*/);2==a[J]&&(b[pj(a[0][He]())]=a[1])});return b};var Cfa=/^(?:([^:/?#.]+):)?(?:\/\/(?:([^/?#]*)@)?([^/#?]*?)(?::([0-9]+))?(?=[/#?]|$))?([^?#]+)?(?:\?([^#]*))?(?:#(.*))?$/;function hn(a){if(jn){jn=!1;var b=Fi[Fc];if(b){var c=b[Vc];if(c&&(c=kn(ln(3,c)))&&c!=b.hostname)throw jn=!0,m();}}return a[Pb](Cfa)}var jn=ql;function kn(a){return a?decodeURI(a):a}function ln(a,b){return hn(b)[a]||null} +function Dfa(a,b){for(var c=a[zc](We),d=0;dd)return null;var e=a[zd](We,d);if(0>e||e>c)e=c;d+=b[J]+1;return ma(a[mc](d,e-d)[Ab](/\+/g,Ke))}var Efa=/[?&]($|#)/; +function pn(a,b){for(var c=a[Kc](nn),d=0,e,f=[];0<=(e=mn(a,d,b,c));)f[B](a[we](d,e)),d=h.min(a[zd](We,e)+1||c,c);f[B](a[mc](d));return f[Fe](M)[Ab](Efa,Ue)}function qn(a,b,c){a=[pn(a,b),We,b];null!=c&&a[B](Df,aa(String(c)));a[1]&&(c=a[0],b=c[zd](Oe),0<=b&&(a[B](c[mc](b)),a[0]=c=c[mc](0,b)),b=c[zd](Gf),0>b?a[1]=Gf:b==c[J]-1&&(a[1]=void 0));return a[Fe](M)};var rn={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:Pe,blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9", +darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff", +gold:"#ffd700",goldenrod:"#daa520",gray:Qe,green:"#008000",greenyellow:"#adff2f",grey:Qe,honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa", +lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead", +navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d", +silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:Se,whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"};function sn(a){var b={};a=String(a);var c=a[Ib](0)==Oe?a:Oe+a;if(tn[od](c))return b.sc=un(c),db(b,oca),b;c=Ffa(a);if(c[J])return b.sc=vn(c),db(b,Yh),b;if(rn&&(c=rn[a[He]()]))return b.sc=c,db(b,tca),b;throw m(a+" is not a valid color string");}function wn(a){return!!(tn[od](a[Ib](0)==Oe?a:Oe+a)||Ffa(a)[J]||rn&&rn[a[He]()])}var Gfa=/#(.)(.)(.)/;function un(a){if(!tn[od](a))throw m(cf+a+"' is not a valid hex color");4==a[J]&&(a=a[Ab](Gfa,faa));return a[He]()} +function xn(a){a=un(a);return[ja(a[mc](1,2),16),ja(a[mc](3,2),16),ja(a[mc](5,2),16)]}function yn(a,b,c){a=ha(a);b=ha(b);c=ha(c);if(fa(a)||0>a||255b||255c||255=k?(d-e)/(2*k):(d-e)/(2-2*k));return[h[D](f+360)%360,g,k]}function An(a,b,c){0>c?c+=1:16*c?a+6*(b-a)*c:1>2*c?b:2>3*c?a+(b-a)*(2/3-c)*6:a} +function Ifa(a,b,c){var d=0,e=0,f=0;a/=360;if(0==b)d=e=f=255*c;else var g=f=0,g=.5>c?c*(1+b):c+b-b*c,f=2*c-g,d=255*An(f,g,a+1/3),e=255*An(f,g,a),f=255*An(f,g,a-1/3);return[h[D](d),h[D](e),h[D](f)]}var tn=/^#(?:[0-9a-f]{3}){1,2}$/i,Jfa=/^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i;function Ffa(a){var b=a[Pb](Jfa);if(b){a=ha(b[1]);var c=ha(b[2]),b=ha(b[3]);if(0<=a&&255>=a&&0<=c&&255>=c&&0<=b&&255>=b)return[a,c,b]}return[]}function zn(a){return 1==a[J]?pf+a:a} +function Bn(a,b,c){c=Lk(c,0,1);return[h[D](c*a[0]+(1-c)*b[0]),h[D](c*a[1]+(1-c)*b[1]),h[D](c*a[2]+(1-c)*b[2])]}function Cn(a,b){return Bn([0,0,0],a,b)}function Dn(a,b){return Bn([255,255,255],a,b)}function En(a,b){for(var c=[],d=0;db?e+=sf:256>b?e+=paa:4096>b&&(e+=pf);return In[a]=e+b[qc](16)}),Me)};var Jn=Fi[yd]&&Fi[yd][Pd]||Fn,Kn=Fi[yd]&&Fi[yd][nd]||Gn;function Ln(a){return Gn(Mn(a,Nn))}function On(a){Fn(a);return Qfa(a)}function Qfa(a){a=Xn(a);return eval(df+a+ef)}function Mn(a,b){a=b(a);var c=Li(a);if(c==Ph||c==Lg){var c=c==Lg?[]:{},d;for(d in a)if(!gj(d,zba)&&a[Hc](d)){var e=Mn(a[d],b);Gi(e)&&(c[d]=e)}}else c=a;return c}function Xn(a){return a[Ab](/"(Date\([\d,\s]*\))"/g,function(a,c){return xca+c})} +function Nn(a){Qi(a)&&(a=0!==a[ge]()?[a[Rc](),a[Vd](),a[Kb](),a[gc](),a[bd](),a[de](),a[ge]()]:0!==a[de]()||0!==a[bd]()||0!==a[gc]()?[a[Rc](),a[Vd](),a[Kb](),a[gc](),a[bd](),a[de]()]:[a[Rc](),a[Vd](),a[Kb]()],a=Eaa+a[Fe](kf)+ef);return a};function Yn(a,b){Ja(this,a=b};function bo(a,b){a&&(a.logicalname=b)}function Rfa(a){return(a=pm(a,function(a){return null!=a.logicalname},!0))?a.logicalname:Dg};function co(a){return a==O||a==M||a==oi?O:sn(a).sc}function eo(a){if(a==O)return O;a=xn(a);a=h[D]((a[0]+a[1]+a[2])/3);return yn(a,a,a)}function Sfa(a){a=mk(a);null==a[Xd]&&lb(a,!0);return a}function Tfa(a,b){var c=a.m(b[Nd],b[tb]);a.Bw(c,{style:b[w]});if(null!=b[Fb]){var d=Oi(b[Fb])?b[Fb]:[b[Fb]];X(d,function(b){if(Si(b))a[q](c,a[Jb](b));else b=Si(b[Fb])&&b.Goa?Tl(a.Ze,b[Fb]):Tfa(a,b),a[q](c,b)})}null!=b.id&&bo(c,b.id);return c};function fo(a,b){a=a||{};if(2==arguments[J]){var c=arguments[1],d;for(d in c)if(Oi(c[d]))a[d]=Lj(c[d]);else if(typeof a[d]===Ph&&null!=a[d])a[d]=fo(a[d],c[d]);else if(typeof c[d]===Ph&&null!=c[d])a[d]=fo({},c[d]);else if(null==a[d]||null!=c[d])a[d]=c[d]}else if(2a.end?b:a?a.end:null;return null!=d&&null!=a?new Yn(d,a):null}function io(a){if(0==a[J])return null;for(var b=a[0][Jc](),c=1;ca&&b[Hd](b[Rc]()-1900);return b}R=xo[K];R.Qfa=uo.FIRSTDAYOFWEEK;R.Rfa=uo.FIRSTWEEKCUTOFFDAY;Ia(R,function(){var a=new xo(this.vb);a.Qfa=this.Qfa;a.Rfa=this.Rfa;return a});R.getFullYear=function(){return this.vb[Rc]()};R.getYear=function(){return this[Rc]()};R.getMonth=function(){return this.vb[Vd]()};R.getDate=function(){return this.vb[Kb]()};ya(R,function(){return this.vb[jc]()});R.getDay=function(){return this.vb[vc]()};R.getUTCFullYear=function(){return this.vb[Qb]()}; +R.getUTCMonth=function(){return this.vb[Mc]()};R.getUTCDate=function(){return this.vb[ee]()};R.getUTCHours=function(){return this.vb[Be]()};R.getUTCMinutes=function(){return this.vb[Ae]()};R.getTimezoneOffset=function(){return this.vb[Ie]()};R.set=function(a){this.vb=new Date(a[Rc](),a[Vd](),a[Kb]())};R.setFullYear=function(a){this.vb[Hd](a)};R.setMonth=function(a){this.vb[Fd](a)};R.setDate=function(a){this.vb[Td](a)};R.setTime=function(a){this.vb[Wc](a)};R.setUTCFullYear=function(a){this.vb.setUTCFullYear(a)}; +R.setUTCMonth=function(a){this.vb[qe](a)};R.setUTCDate=function(a){this.vb.setUTCDate(a)};R.add=function(a){if(a.years||a.months){var b=this[Vd]()+a.months+12*a.years,c=this[Nc]()+h[Eb](b/12),b=b%12;0>b&&(b+=12);var d=h.min(wo(c,b),this[Kb]());this[Td](1);this[Hd](c);this[Fd](b);this[Td](d)}a.days&&(a=new Date((new Date(this[Nc](),this[Vd](),this[Kb](),12))[jc]()+864E5*a.days),this[Td](1),this[Hd](a[Rc]()),this[Fd](a[Vd]()),this[Td](a[Kb]()),yo(this,a[Kb]()))}; +R.bya=function(){return[this[Rc](),jj(this[Vd]()+1,2),jj(this[Kb](),2)][Fe](M)+M};ab(R,function(a){return!(!a||this[Nc]()!=a[Nc]()||this[Vd]()!=a[Vd]()||this[Kb]()!=a[Kb]())});Aa(R,function(){return this.bya()});function yo(a,b){a[Kb]()!=b&&a.vb.setUTCHours(a.vb[Be]()+(a[Kb]()=(e||30)&&(!d||b<=d))||a&&(b=a[re],b>=(e||30)&&(!d||b<=d))?b:c||200}function sga(a){var b=tga,c=a&&a.colors;c&&0!=c[J]||(c=(a=a&&a[F])?[a]:b);return c} +function up(){var a=Ii(jca);if(null!=a)return a;a=Ii(gca);null!=a||(a=laa);var b=Ii(lca);null!=b||(b=raa);return a+maa+b}function uga(){if(0==ea[kc](oh)[J]){var a=ea[kc](vh)[0],b=ea[kc](Pg)[0],c=ea[Vb](oh);a[Lb](c,b)}return ea[kc](oh)[0]}function vp(a){a=up()+a;for(var b=ea[kc](Saa),c=0;cc?eca:dca;a[Qc](d,b,Rba,f)}});var yga={zza:Qg,RAa:Nh,uBa:ii,Gwa:Xg,CBa:ni,Hwa:$g};var zga={KAa:Yf,fBa:cba,LAa:Uaa,hAa:Laa,Wza:Nf,NBa:nba,NAa:$f,bBa:fg,RBa:yg};function Bp(a){switch(a){case Yf:return 1;case cba:return 1E3;case Uaa:return 6E4;case Laa:return 36E5;case Nf:return 864E5;case nba:return 6048E5;case $f:return 2629746E3;case fg:return 7889238E3;case yg:return 31556952E3}return 0};function Cp(){}function Dp(a){if(typeof a==Nh){var b=new Cp;b.Aga=a;var c;c=a;if(0==c)c=Gaa;else{var d=[Gaa,0>c?lf:hf];c=h.abs(c);d[B](h[Eb](c/60)%100);c%=60;0!=c&&d[B](xf,jj(c,2));c=d[Fe](M)}b.Bga=c;0==a?a=kba:(c=[kba,0>a?hf:lf],a=h.abs(a),c[B](h[Eb](a/60)%100),a%=60,0!=a&&c[B](xf,a),a=c[Fe](M));b.p5=[a,a];b.pE=[];return b}b=new Cp;b.Bga=a.id;b.Aga=-a.std_offset;b.p5=a[hc];b.pE=a.transitions;return b}R=Cp[K]; +R.getDaylightAdjustment=function(a){a=Date.UTC(a[Qb](),a[Mc](),a[ee](),a[Be](),a[Ae]())/36E5;for(var b=0;b=this.pE[b];)b+=2;return 0==b?0:this.pE[b-1]};R.getGMTString=function(a){a=this.getOffset(a);var b=[Jaa];b[B](0>=a?hf:lf);a=h.abs(a);b[B](jj(h[Eb](a/60)%100,2),xf,jj(a%60,2));return b[Fe](M)};R.getLongName=function(a){return this.p5[this.isDaylightTime(a)?3:1]};R.getOffset=function(a){return this.Aga-this.getDaylightAdjustment(a)}; +R.getRFCTimeZoneString=function(a){a=-this.getOffset(a);var b=[0>a?lf:hf];a=h.abs(a);b[B](jj(h[Eb](a/60)%100,2),jj(a%60,2));return b[Fe](M)};R.getShortName=function(a){return this.p5[this.isDaylightTime(a)?2:0]};R.getTimeZoneId=function(){return this.Bga};R.isDaylightTime=function(a){return 0a)b=this.vf.DATEFORMATS[a];else if(8>a)b=this.vf.TIMEFORMATS[a-4];else if(12>a)b=this.vf.DATETIMEFORMATS[a-8],b=b[Ab](tda,this.vf.DATEFORMATS[a-8]),b=b[Ab](sda,this.vf.TIMEFORMATS[a-8]);else{this.bU(10);return}this.tt(b)};function Fp(a,b){var c;c=String(b);var d=a.vf||uo;if(void 0!==d.mva){for(var e=[],f=0;f=g?String[Gd](d.mva+g-48):c[Ib](f))}c=e[Fe](M)}return c} +function Gp(a){if(!(a[gc]&&a[de]&&a[bd]))throw m("The date to format has no time (probably a goog.date.Date). Use Date or goog.date.DateTime, or use a pattern without time fields.");} +function Bga(a,b,c,d,e,f){var g=b[J];switch(b[Ib](0)){case Iaa:return c=0c&&(c=-c),2==g&&(c%=100),Fp(a,jj(c,g));case Xf:t:switch(c=d[Vd](),g){case 5:a=a.vf.NARROWMONTHS[c];break t;case 4:a=a.vf.MONTHS[c];break t;case 3:a=a.vf.SHORTMONTHS[c];break t;default:a=Fp(a,jj(c+1,g))}return a;case Bh:return Gp(e),Fp(a,jj(e[gc]()||24,g));case gg:return c=e[jc]()%1E3/1E3,Fp(a,c[Bb](h.min(3,g))[mc](2)+(3g?1:0];case mh:return Gp(e),Fp(a,jj(e[gc]()%12||12,g));case Qaa:return Gp(e),Fp(a,jj(e[gc]()%12,g));case Kaa:return Gp(e),Fp(a,jj(e[gc](),g));case Tg:t:switch(c=d[vc](),g){case 5:a=a.vf.STANDALONENARROWWEEKDAYS[c];break t;case 4:a=a.vf.STANDALONEWEEKDAYS[c];break t;case 3:a=a.vf.STANDALONESHORTWEEKDAYS[c];break t;default:a=Fp(a,jj(c,1))}return a;case Wf:t:switch(c=d[Vd](),g){case 5:a=a.vf.STANDALONENARROWMONTHS[c]; +break t;case 4:a=a.vf.STANDALONEMONTHS[c];break t;case 3:a=a.vf.STANDALONESHORTMONTHS[c];break t;default:a=Fp(a,jj(c+1,g))}return a;case eg:return c=h[Eb](d[Vd]()/3),4>g?a.vf.SHORTQUARTERS[c]:a.vf.QUARTERS[c];case Vg:return Fp(a,jj(d[Kb](),g));case Fh:return Gp(e),Fp(a,jj(e[bd](),g));case ai:return Gp(e),Fp(a,jj(e[de](),g));case si:return a=f||Dp(c[Ie]()),a.getTimeZoneId();case wi:return c=new Date(e[Rc](),e[Vd](),e[Kb]()),b=a.vf.FIRSTDAYOFWEEK||0,c=c[md]()+864E5*(((a.vf.FIRSTWEEKCUTOFFDAY||3)-b+ +7)%7-((c[vc]()+6)%7-b+7)%7),c=h[Eb](h[D]((c-(new Date((new Date(c))[Rc](),0,1))[md]())/864E5)/7)+1,Fp(a,jj(c,g));case Ai:return a=f||Dp(c[Ie]()),4>g?a.getShortName(c):a.getLongName(c);case zg:return b=f||Dp(c[Ie]()),4>g?b.getRFCTimeZoneString(c):Fp(a,b.getGMTString(c));default:return M}};var Cga={YEAR_FULL:zi,YEAR_FULL_WITH_ERA:"y G",YEAR_MONTH_ABBR:"MMM y",YEAR_MONTH_FULL:"MMMM y",MONTH_DAY_ABBR:Zf,MONTH_DAY_FULL:"MMMM dd",MONTH_DAY_SHORT:"M/d",MONTH_DAY_MEDIUM:"MMMM d",MONTH_DAY_YEAR_MEDIUM:"MMM d, y",WEEKDAY_MONTH_DAY_MEDIUM:"EEE, MMM d",WEEKDAY_MONTH_DAY_YEAR_MEDIUM:"EEE, MMM d, y",DAY_ABBR:Vg},Hp=Cga,Hp=Cga;var Dga={Vva:{1E3:{other:"0K"},1E4:{other:"00K"},1E5:{other:"000K"},1E6:{other:"0M"},1E7:{other:"00M"},1E8:{other:"000M"},1E9:{other:"0B"},1E10:{other:"00B"},1E11:{other:"000B"},1E12:{other:"0T"},1E13:{other:"00T"},1E14:{other:"000T"}},Uva:{1E3:{other:"0 thousand"},1E4:{other:"00 thousand"},1E5:{other:"000 thousand"},1E6:{other:"0 million"},1E7:{other:"00 million"},1E8:{other:"000 million"},1E9:{other:"0 billion"},1E10:{other:"00 billion"},1E11:{other:"000 billion"},1E12:{other:"0 trillion"},1E13:{other:"00 trillion"}, +1E14:{other:"000 trillion"}}},Ip=Dga,Ip=Dga;function Ega(a){var b=Jp.Ewa,c=[pf];a=Kp[a][0]&7;if(0d&&k++;break;case pf:if(0d&&k++;break;case jf:k=0;break;case mf:if(0<=d)throw m('Multiple decimal separators in pattern "'+a+Me);d=e+f+g;break;case Pf:if(this.JT)throw m('Multiple exponential symbols in pattern "'+a+Me);this.JT=!0;this.OT=0;b[0]+1e+f||1>this.OT)throw m('Malformed exponential pattern "'+a+Me);n=!1;break;default:b[0]--,n=!1}0==f&&0d&&0e+f)||0==k)throw m('Malformed pattern "'+a+Me);g=e+f+g;this.uz=0<=d?g-d:0;0<=d&&(this.ot=e+f-d,0>this.ot&&(this.ot=0));this.$o=(0<=d?d:g)-e;this.JT&&(this.FT=e+this.$o,0==this.uz&&0==this.$o&&(this.$o=1));this.Z2=h.max(0,k);this.rda=0==d||d==g;c= +b[0]-c;this.WK=Np(this,a,b);b[0]this.Uv[J]?f=!1:this.pz[J]=C)x+=C,l=!0;else if(A==p[Ib](0)){if(g||k)break;x+=mf;g=!0}else if(A==t[Ib](0)&&(Di!=t[Ib](0)||c[0]+1=d?0:Pp(d)).divisorBase,e/=h.pow(10,c),Qp(this,e),d/=h.pow(10,c),d=Qp(this,d),c=Iga(this,c+Pp(d.qea)));a/=h.pow(10,c.divisorBase);b[B](c.prefix);d=0>a||0==a&&0>1/a;b[B](d?this.Uv:this.pz);if(la(a))if(a=a*(d?-1:1)*this.rj,this.JT)if(0==a)Rp(this,a,this.$o,b),Jga(this,0,b);else{e=h.log(a)/h.log(10);e=h[Eb](e+2E-15);a/=h.pow(10,e);var f=this.$o;if(1 +this.$o){for(;0!=e%this.FT;)a*=10,e--;f=1}else 1>this.$o?(e++,a/=10):(e-=this.$o-1,a*=h.pow(10,this.$o-1));Rp(this,a,f,b);Jga(this,e,b)}else Rp(this,a,this.$o,b);else b[B](Jp.h4);b[B](d?this.nE:this.WK);b[B](c.suffix);return b[Fe](M)});function Qp(a,b){var c=h.pow(10,a.uz),d=0>=a.Bz?h[D](b*c):h[D](Kga(b*c,a.Bz,a.uz)),e;la(d)?(e=h[Eb](d/c),c=h[Eb](d-e*c)):(e=b,c=0);return{qea:e,Jua:c}} +function Rp(a,b,c,d){if(a.ot>a.uz)throw m("Min value must be less than max value");b=Qp(a,b);var e=h.pow(10,a.uz),f=b.qea,g=b.Jua,k=0==f?0:Pp(f)+1,l=0b+1;)c--;for(f=1;fb?(b=-b,c[B](Jp.sva)):a.sda&&c[B](Jp.tva);b=M+b;for(var d=Mp?pf:Jp.y4,e=b[J];ea)return a-48;var b=Jp.y4[se](0);return b<=a&&ab)return Op;b=h.min(14,b);c=c[h.pow(10,b)];if(!c)return Op;c=c.other;return c&&c!=pf?(c=/([^0]*)(0+)(.*)/[xb](c))?{prefix:c[1],suffix:c[3],divisorBase:b-(c[2][J]-1)}:Op:Op}function Pp(a){for(var b=0;1<=(a/=10);)b++;return b}function Kga(a,b,c){if(!a)return a;b=b-Pp(a)-1;if(b<-c)return c=h.pow(10,c),h[D](a/c)*c;c=h.pow(10,b);return h[D](a*c)/c};ta(Ep[K],Ep[K][Rb]);Ep.Format={FULL_DATE:0,LONG_DATE:1,MEDIUM_DATE:2,SHORT_DATE:3,FULL_TIME:4,LONG_TIME:5,MEDIUM_TIME:6,SHORT_TIME:7,FULL_DATETIME:8,LONG_DATETIME:9,MEDIUM_DATETIME:10,SHORT_DATETIME:11};var Sp=Hp;Lp.Format={Iwa:1,Rwa:2,XL:3,Dwa:4,Cwa:5,Bwa:6};ta(Lp[K],Lp[K][Rb]);Lp.setEnforceAsciiDigits=function(a){Mp=a};Lp.isEnforceAsciiDigits=function(){return Mp};var Tp=Jp;Cp.createTimeZone=Dp;function Up(){this.pn=null}wa(Up[K],function(a){if(Ui(a)){var b=this.L();return 0>a&&a>=b?-1:a}if(!this.pn){this.pn={};for(var b=this.L(),c=0;c=this.RI)throw m("Scale factor must be a positive number.");}W(Yp,Vp); +var Sga={decimal:Lp[Ld].Iwa,scientific:Lp[Ld].Rwa,percent:Lp[Ld].XL,currency:Lp[Ld].Dwa,"short":Lp[Ld].Cwa,"long":Lp[Ld].Bwa},Tga=!1,Qga=Tp.DECIMAL_SEP,Rga=Tp.GROUP_SEP,Zp=Tp.DECIMAL_PATTERN;ta(Yp[K],function(a,b){if(a.G(b)==Nh)for(var c=0;cd&&a[Qc](c,b,ji,Tba+this.gca+zf)}}}); +Yp[K].EV=function(a){var b=null,b=a/this.RI;if(null===this.ud){if(fa(this.Lz))return String(a);this.yfa&&(b=h.abs(b));var c=b;0==this.Lz&&(c=h[D](c));b=[];0>c&&(c=-c,b[B](lf));var d=h.pow(10,this.Lz),e=h[D](c*d),c=String(h[Eb](e/d)),d=String(e%d);if(3a&&(b= +df+b+ef)}else c=new Lp(this.ud),a=Lp.isEnforceAsciiDigits(),Lp.setEnforceAsciiDigits(!Tga),b=c[Rb](b),b=this.zfa+b+this.Bfa,Lp.setEnforceAsciiDigits(a);return b};function $p(a){if(!a)throw m("Data table is not defined.");if(!Vi(a.fz)){var b=Sca;Oi(a)?b=Eba:Si(a)&&(b=Bba);throw m("You called the draw() method with "+b+" rather than a DataTable or DataView");}}function Uga(a){return null==a?null:Vi(a.fz)?a:Oi(a)?Vga(a):new aq(a)} +function Wga(a){var b={};if(Li(a)!=Ph||Qi(a))b.v=null!=a?a:null;else{b.v="undefined"==typeof a.v?null:a.v;if(null!=a.f)if(typeof a.f===ii)b.f=a.f;else throw m("Formatted value ('f'), if specified, must be a string.");if(null!=a.p)if(typeof a.p===Ph)b.p=a.p;else throw m("Properties ('p'), if specified, must be an object.");}return b} +function Xga(a,b,c){if(typeof b==Ph&&Ug in b){if(Yba in b&&typeof b.desc!=Qg)throw m('Property "desc" in '+c+" must be boolean.");if(Vba in b&&!Vi(b[uc]))throw m('Property "compare" in '+c+" must be a function.");}else throw m(c+' must be an object with a "column" property.');bq(a,b.column)} +function Yga(a,b,c){function d(d,e){for(var f=0;fc[J])throw m("sortColumns is an empty array. Must have at least one element.");for(var f={},g=[],k=0;kb||b>=c)throw m("Invalid row index "+b+". Should be in the range [0-"+(c-1)+"].");}else throw m("Table has no rows.");} +function bq(a,b){a[dc](b);if(Ui(b))eq(a,b);else if(-1===a[dc](b))throw m('Invalid column id "'+b+Me);}function eq(a,b){var c=a.L();if(0b||b>=c)throw m("Invalid column index "+b+". Should be an integer in the range [0-"+(c-1)+"].");}else throw m("Table has no columns.");}function fq(a,b,c){a=a.G(b);if(!Zga(c,a))throw m(jba+c+caa+a+" in column index "+b);} +function Zga(a,b){if(null==a)return!0;var c=typeof a;switch(b){case Nh:if(c==Nh)return!0;break;case ii:if(c==ii)return!0;break;case Qg:if(c==Qg)return!0;break;case Xg:case $g:if(Qi(a))return!0;break;case ni:if(Pi(a)&&0a[J]){for(var c=!0,d=0;da[0]||0>a[1]||59a[2]||59a[3]||999a;a++){if(b[a]b[J]?0:b[3];c=4>c[J]?0:c[3];return bcq(d,k,e)?e=k:0>cq(d,f,k)&&(f=k));return{min:e,max:f}} +function aha(a,b){for(var c=Yga(a,function(b,c){return a[I](b,c)},b),d=[],e=a.O(),f=0;fcq(k,g,e.minValue)||null!=e.maxValue&&0b)throw m("Invalid value for numOrArray: "+b+". If numOrArray is a number it should be a nonnegative integer.");c=Xj(null,b)}else throw m("Invalid value for numOrArray. Should be a number or an array of arrays of cells.");for(var d=[],e=0;e=b||(this.Cc=[],dq(this,a),a+b>this.Lf[J]&&(b=this.Lf[J]-a),this.Lf[Ee](a,b))};R.ey=function(a){this.uha(a,1)}; +R.tha=function(a,b){if(!(0>=b)){this.Cc=[];eq(this,a);a+b>this.If[J]&&(b=this.If[J]-a);this.If[Ee](a,b);this.pn=null;for(var c=0;c=e&&(f=f||a.pq(b),e=f.max,d=f.min);d==e&&(0==d?e=1:0=b)&&(null==c||a=this.E4&&(this.E4=1);this.Hua=xn(sn(d).sc);this.Iua=xn(sn(e).sc)} +W(nq,kq);nq[K].getBackgroundColor=function(a){if(!Ui(a))return M;a=Bn(this.Hua,this.Iua,1-(a-this.UN)/this.E4);return yn(a[0],a[1],a[2])};function oq(){this.hT=[]}oq[K].addRange=function(a,b,c,d){this.hT[B](new kq(a,b,c,d))};oq[K].exa=function(a,b,c,d,e){this.hT[B](new nq(a,b,c,d,e))}; +ta(oq[K],function(a,b){var c=a.G(b);if(c==Nh||c==ii||c==Xg||c==$g||c==ni)for(c=0;c",Jha='