diff --git a/CMakeLists.txt b/CMakeLists.txt index f6c250a9..2e564887 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ ENABLE_TESTING() PROJECT(Fail*) -set(PROJECT_VERSION "0.0.1" CACHE STRING "Fail* version number") +set(PROJECT_VERSION "1.0.1" CACHE INTERNAL "Fail* version number" FORCE) #### Put all resulting library files in /lib #### SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..3549a48d --- /dev/null +++ b/COPYING @@ -0,0 +1,40 @@ +FAIL* - FAult Injection Leveraged + +Copyright (c) 2011-2014 Horst Schirmeier +Copyright (c) 2011-2013 Adrian Böckenkamp +Copyright (c) 2011-2014 Richard Hellwig +Copyright (c) 2011-2014 Martin Hoffmann +Copyright (c) 2012-2013 Martin Unzner +Copyright (c) 2013-2014 Christian Dietrich +Copyright (c) 2013-2014 Lars Rademacher +Copyright (c) 2012-2014 Christoph Borchert +Copyright (c) 2013-2014 Björn Döbel +Copyright (c) 2012-2013 Tobias Friemel +Copyright (c) 2013-2014 Michael Lenz +Copyright (c) 2013-2014 Florian Lukas +Copyright (c) 2012 Robby Zippel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +================================================================ + +Along the FAIL* source code, the source code of several other open source +projects is included in this source tree: + + - Bochs: GPLv2 or later + - Gem5: BSD/MIT with some files in LGPL + - OpenOCD: GPLv2 or later + - elfinfo: GPLv2 or later + - gzstream: GPLv2 or later + - optionparser: MIT diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..94a9ed02 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README b/README deleted file mode 100644 index 7ff4cad1..00000000 --- a/README +++ /dev/null @@ -1,6 +0,0 @@ -This is an import of the old danceos svn repository. The Fail* development -started with rev 187, but this git import only contains revisions 956 and newer -due to directory structure changes. - -Imported from external gitsvn checkout. -http://www.kernel.org/pub/software/scm/git/docs/howto/using-merge-subtree.html diff --git a/README.md b/README.md new file mode 100644 index 00000000..c560e732 --- /dev/null +++ b/README.md @@ -0,0 +1,212 @@ +FAIL* - FAult Injection Leveraged +======================================= + +FAIL* is a fault-injection (FI) framework that provides support for +detailed fault-injection campaigns. It provides carefully-chosen +abstractions simplifying both the implementation of different +simulator/hardware target backends and the reuse of experiment code, +while retaining the ability for deep target-state access for +specialized FI experiments. + +The FI experiments are expressed with C++ and programmed against the +FAIL* API which provides full access to the internal state of the +system-under-test. Currently, several hardware/simulator based +backends are available: + +- [Bochs](http://bochs.sourceforge.net): Bochs is an x86 + simulator. FAIL* can run and inject bare-metal system images. This + backend is the most mature and well tested one for undertaking large + fault-injection campaigns with several millions of injected faults. + +- [Gem5](http://www.gem5.org): Gem5 is a simulator for the ARM + platform, which is supported by FAIL. For Gem5, FAIL supports the + simulation of the Panda Board, which contains an ARM A9 core. + +- [OpenOCD](http://openocd.org/): The OpenOCD project provides a + unified debugging interface for real embedded ARM platforms. FAIL + uses this interface to inject faults onto a real hardware + platform. Several techniques, like SmartHopping, were developed to + make campaigns with real hardware faster and more feasible. + +- Support for other platforms were developed, but are not as mature as + the other backends: The Trace32 simulator backend for TriCore; An + x86 backend using QEMU. + +During the FI experiment, FAIL provides an interface for triggering +actions on certain instructions, instruction ranges, memory +reads/writes, interrupts, IO operations and timer events. As well the +state of the registers as the main memory of the system-under-test can +be manipulated. + +Building FAIL* +-------------- + +Since FAIL* is a complex research project with many dependencies, +which are listed in `doc/how-to-build.txt`, we provide several +[Docker.io](http://www.docker.com) images that contain all +requirements to build and run a FI campaign with FAIL. After +installing and starting docker on your system, you have to type in the +root directory of the git archive: + + cd scripts/docker; make + +As a result, you get three docker images: + +- **fail-base**: The docker image contains all requirements to build + FAIL*. This docker image is built on top of ubuntu 14.10 and + provides access via SSH (User: fail; Password: fail). + +- **fail-generic-tracing**: Upon the fail-base image, this images + provides the tooling to generate golden-run traces of the + system-under-test. These traces contain all instruction pointer and + memory events of the golden run. The FAIL toolchain can record, + show, and import those traces to an MySQL database. + +- **fail-demo**: This image contains as well an generic FAIL + experiment, a simple system-under-test, and scripts to run an first + FI campaign within less than 20 minutes. This image has to be + connected to a MySQL docker image. + +Using FAIL* +----------- + +After building the docker images, you can run the FAIL demonstration +image by typing: + + cd scripts/docker + docker pull mysql + make run-fail-db + make run-fail-demo + make ssh-fail-demo + +The last command starts a SSH connection to the demonstration +system. Username, as well as password is 'fail'. In the default +configuration, no SSH port is exposed to your normal network +interface. After the connection, you should start in the +`~/fail-targets` directory, which contains a clone of +[https://github.com/danceos/fail-targets](https://github.com/danceos/fail-targets). + +The demo system-under test is built and traced with: + + make + make trace-main + +The golden run is traced with: + + make import-main + +The fault injection itself is separated into a server process and many +injection workers. Both can be started at once with: + + make server-main & + make client-main + +The results can be displayed on the console or with an browser-based +viewer. By default, port 5000 is exposed to the machine running the +docker instance. + + make result-main + make resultbrowser + + +Mailing list +------------ +The Fail* developers, and some of its previous and current users, can be +contacted on the +[fail@lists.cs.tu-dortmund.de](mailto:fail@lists.cs.tu-dortmund.de) +mailing list +([subscribe!](https://postamt.cs.uni-dortmund.de/mailman/listinfo/fail)). + +Publications about FAIL* +------------------------ + + - H. Schirmeier, M. Hoffmann, R. Kapitza, D. Lohmann, and + O. Spinczyk. FAIL*: Towards a versatile fault-injection experiment + framework. In G. Mühl, J. Richling, and A. Herkersdorf, editors, + 25th International Conference on Architecture of Computing Systems + (ARCS '12), Workshop Proceedings, volume 200 of Lecture Notes in + Informatics, pages 201–210. German Society of Informatics, + Mar. 2012. + [PDF](http://danceos.org/publications/VERFE-2012-Schirmeier.pdf) + +Selected publications using FAIL* +--------------------------------- + +- M. Hoffmann, F. Lukas, C. Dietrich, and D. Lohmann. dOSEK: The design and + implementation of a dependability-oriented static embedded kernel. In + Proceedings of the 21st IEEE Real-Time and Embedded Technology and + Applications (RTAS '15), Los Alamitos, CA, USA, Apr. 2015. IEEE Computer + Society Press. + +- M. Hoffmann, P. Ulbrich, C. Dietrich, H. Schirmeier, D. Lohmann, and W. + Schröder-Preikschat. Experiences with software-based soft-error mitigation + using AN codes. Software Quality Journal, pages 1–27, 2015. + +- I. Stilkerich, P. Taffner, C. Erhardt, C. Dietrich, C. Wawersich, and + M. Stilkerich. Team Up: Cooperative Memory Management in Embedded + Systems. In Proceedings of the 2014 Conference on Compilers, + Architectures and Synthesis for Embedded Systems (CASES '14). ACM, + October 2014. + +- H. Schirmeier, C. Borchert, and O. Spinczyk. Rapid fault-space exploration by + evolutionary pruning. In Proceedings of the 33rd International Conference on + Computer Safety, Reliability and Security (SAFECOMP '14), Lecture Notes in + Computer Science, pages 17–32. Springer-Verlag, Sept. 2014. + +- M. Hoffmann, C. Borchert, C. Dietrich, H. Schirmeier, R. Kapitza, O. + Spinczyk, and D. Lohmann. Effectiveness of fault detection mechanisms in + static and dynamic operating system designs. In Proceedings of the 17th IEEE + International Symposium on Object-Oriented Real-Time Distributed Computing + (ISORC '14), pages 230–237. IEEE Computer Society Press, June 2014. + +- H. Schirmeier, L. Rademacher, and O. Spinczyk. Smart-hopping: Highly efficient + ISA-level fault injection on real hardware. In Proceedings of the 19th IEEE + European Test Symposium (ETS '14), pages 69–74. IEEE Computer Society Press, + May 2014. + +- M. Hoffmann, P. Ulbrich, C. Dietrich, H. Schirmeier, D. Lohmann, and W. + Schröder-Preikschat. A practitioner's guide to software-based soft-error + mitigation using AN-codes. In Proceedings of the 15th IEEE International + Symposium on High Assurance Systems Engineering (HASE '14), pages 33–40, + Miami, Florida, USA, Jan. 2014. IEEE Computer Society Press. + +- C. Borchert, H. Schirmeier, and O. Spinczyk. Return-address + protection in C/C++ code by dependability aspects. In Proceedings of + the 2nd GI Workshop on Software-Based Methods for Robust Embedded + Systems (SOBRES '13), Lecture Notes in Informatics. German Society + of Informatics, Sept. 2013. + +- M. Hoffmann, C. Dietrich, and D. Lohmann. Failure by design: + Influence of the RTOS interface on memory fault resilience. In + Proceedings of the 2nd GI Workshop on Software-Based Methods for + Robust Embedded Systems (SOBRES '13), Lecture Notes in + Informatics. German Society of Informatics, Sept. 2013. + +- I. Stilkerich, M. Strotz, C. Erhardt, M. Hoffmann, D. Lohmann, F. + Scheler, and W. Schröder-Preikschat. A JVM for Soft-Error-Prone + Embedded Systems. In Proceedings of the 2013 ACM SIGPLAN/SIGBED + Conference on Languages, Compilers and Tools for Embedded Systems + (LCTES '13), pages 21–32, June 2013. + +- C. Borchert, H. Schirmeier, and O. Spinczyk. Generative + software-based memory error detection and correction for operating + system data structures. In Proceedings of the 43nd IEEE/IFIP + International Conference on Dependable Systems and Networks (DSN + '13). IEEE Computer Society Press, June 2013. + +- H. Schirmeier, I. Korb, O. Spinczyk, and M. Engel. Efficient online + memory error assessment and circumvention for Linux with RAMpage. + International Journal of Critical Computer-Based Systems, + 4(3):227–247, 2013. Special Issue on PRDC 2011 Dependable Architecture + and Analysis. + +- B. Döbel, H. Schirmeier, and M. Engel. Investigating the limitations + of PVF for realistic program vulnerability assessment. In Proceedings + of the 5rd HiPEAC Workshop on Design for Reliability (DFR '13), + Berlin, Germany, Jan. 2013. + +- C. Borchert, H. Schirmeier, and O. Spinczyk. Protecting the dynamic + dispatch in C++ by dependability aspects. In Proceedings of the 1st + GI Workshop on Software-Based Methods for Robust Embedded Systems + (SOBRES '12), Lecture Notes in Informatics, pages 521–535. German + Society of Informatics, Sept. 2012. diff --git a/cmake/bochs.cmake b/cmake/bochs.cmake index 25697045..dda6c097 100644 --- a/cmake/bochs.cmake +++ b/cmake/bochs.cmake @@ -85,10 +85,11 @@ if(BUILD_BOCHS) # Use cmake's external project feature to build fail library include(ExternalProject) + set_property(DIRECTORY PROPERTY EP_STEP_TARGETS configure) ExternalProject_Add( libfailbochs_external SOURCE_DIR ${bochs_src_dir} - CONFIGURE_COMMAND ${bochs_src_dir}/configure ${bochs_configure_params} --prefix=${bochs_install_prefix} + CONFIGURE_COMMAND MAKEFLAGS="" ${bochs_src_dir}/configure ${bochs_configure_params} --prefix=${bochs_install_prefix} PREFIX ${bochs_src_dir} BUILD_COMMAND $(MAKE) -C ${bochs_src_dir} ${bochs_build_CXX} ${bochs_build_LIBTOOL} libfailbochs.a ## Put install command here, to prevent cmake calling make install @@ -110,7 +111,12 @@ if(BUILD_BOCHS) # FIXME: see FIXME above #target_link_libraries(fail-client libfailbochs fail ${bochs_library_dependencies}) target_link_libraries(fail-client ${bochs_src_dir}/libfailbochs.a fail ${bochs_library_dependencies}) + add_dependencies(libfailbochs_external-configure fail-protoc) + add_dependencies(libfailbochs_external libfailbochs_external-configure) add_dependencies(fail-client libfailbochs_external) + add_dependencies(fail-sal libfailbochs_external-configure) + add_dependencies(fail-comm libfailbochs_external-configure) + add_dependencies(fail-util libfailbochs_external-configure) # /FIXME install(TARGETS fail-client RUNTIME DESTINATION bin) diff --git a/configurations/x86_pruning.sh b/configurations/x86_pruning.sh index d9322309..8e60c1ba 100755 --- a/configurations/x86_pruning.sh +++ b/configurations/x86_pruning.sh @@ -2,12 +2,17 @@ ## A cmake configuration call for a FailBochs pruning EXP=$1 FAILPATH=$(dirname $0)/.. -if [ -z $1 ] -then - echo "Experiment not set. Usage: $0 " - echo "Existing experiments:" - find ${FAILPATH}/src/experiments -maxdepth 1 -mindepth 1 -type d -printf \-\>\ %P\\n | sort +if [ -z $1 ]; then + echo "Experiment not set. Usage: $0 " + echo "Existing experiments:" + find ${FAILPATH}/src/experiments -maxdepth 1 -mindepth 1 -type d -printf \-\>\ %P\\n | sort else -cmake ${FAILPATH} -DBUILD_BOCHS:BOOL=ON -DBUILD_X86:BOOL=ON -DCONFIG_BOCHS_NO_ABORT:BOOL=ON -DCONFIG_EVENT_BREAKPOINTS:BOOL=ON -DCONFIG_EVENT_BREAKPOINTS_RANGE:BOOL=ON -DCONFIG_EVENT_INTERRUPT:BOOL=ON -DCONFIG_EVENT_IOPORT:BOOL=ON -DCONFIG_EVENT_MEMREAD:BOOL=ON -DCONFIG_EVENT_MEMWRITE:BOOL=ON -DCONFIG_EVENT_TRAP:BOOL=ON -DCONFIG_SR_RESTORE:BOOL=ON -DCONFIG_SR_SAVE:BOOL=ON -D"bochs_configure_params:STRING=--enable-a20-pin;--enable-x86-64;--enable-cpu-level=6;--enable-ne2000;--enable-acpi;--enable-pci;--enable-usb;--enable-trace-cache;--enable-fast-function-calls;--enable-host-specific-asms;--enable-disasm;--enable-readline;--enable-clgd54xx;--enable-fpu;--enable-vmx=2;--enable-monitor-mwait;--enable-cdrom;--enable-sb16=linux;--enable-gdb-stub;--with-nogui" -DEXPERIMENTS_ACTIVATED:STRING=${EXP} -DBUILD_IMPORT_TRACE:BOOL=ON -DBUILD_PRUNE_TRACE:BOOL=ON -DBUILD_LLVM_DISASSEMBLER=ON + CONFIG='-DBUILD_BOCHS:BOOL=ON -DBUILD_X86:BOOL=ON -DCONFIG_BOCHS_NO_ABORT:BOOL=ON -DCONFIG_EVENT_BREAKPOINTS:BOOL=ON -DCONFIG_EVENT_BREAKPOINTS_RANGE:BOOL=ON -DCONFIG_EVENT_INTERRUPT:BOOL=ON -DCONFIG_EVENT_IOPORT:BOOL=ON -DCONFIG_EVENT_MEMREAD:BOOL=ON -DCONFIG_EVENT_MEMWRITE:BOOL=ON -DCONFIG_EVENT_TRAP:BOOL=ON -DCONFIG_SR_RESTORE:BOOL=ON -DCONFIG_SR_SAVE:BOOL=ON -Dbochs_configure_params:STRING="--enable-a20-pin;--enable-x86-64;--enable-cpu-level=6;--enable-ne2000;--enable-acpi;--enable-pci;--enable-usb;--enable-trace-cache;--enable-fast-function-calls;--enable-host-specific-asms;--enable-disasm;--enable-readline;--enable-clgd54xx;--enable-fpu;--enable-vmx=2;--enable-monitor-mwait;--enable-cdrom;--enable-sb16=linux;--enable-gdb-stub;--with-nogui" -DEXPERIMENTS_ACTIVATED:STRING='${EXP}' -DBUILD_IMPORT_TRACE:BOOL=ON -DBUILD_PRUNE_TRACE:BOOL=ON -DBUILD_LLVM_DISASSEMBLER=ON' + + if [ -e "${FAILPATH}/src/experiments/${EXP}/config.cmake" ]; then + CONFIG="-C ${FAILPATH}/src/experiments/${EXP}/config.cmake -DEXPERIMENTS_ACTIVATED:STRING=${EXP}" + fi + + cmake ${CONFIG} ${FAILPATH} fi diff --git a/doc/how-to-build.txt b/doc/how-to-build.txt index 17cf4212..5622867e 100644 --- a/doc/how-to-build.txt +++ b/doc/how-to-build.txt @@ -8,21 +8,27 @@ Required for Fail*: - libprotobuf-dev - libpcl1-dev - libboost-thread-dev libboost-system-dev libboost-regex-dev - - libdwarf - - libelf + - libdwarf-dev + - libelf-dev - protobuf-compiler - cmake 2.8.2 (2.8.11 preferred) - - cmake-curses-gui + - fontconfig1-dev + - zlib1g-dev - binutils-dev, on newer systems libiberty-dev - AspectC++ (ag++, ac++): AspectC++ 1.1 or newer is known to work and can be obtained from ; nightlies can be downloaded from . Make sure you use the 64-bit version if running in a 64-bit environment. - optional: - * LLVM 3.3 (needed for several importers in tools/import-trace) + * LLVM 3.3 or 3.4 (needed for several importers in tools/import-trace) (compiles/links with 3.1 or 3.2, but fails to properly import information from ELF binaries not compiled with -ffunction-sections) + - built with "make REQUIRES_RTTI=1" (the Debian/Ubuntu packages already + come built this way) + - details below * a MySQL 5.0+ or MariaDB 5.1+ (MariaDB 5.5 recommended) server + - optional: cmake-curses-gui + Required for the Bochs simulator backend: @@ -268,3 +274,20 @@ Database backend setup: MySQL / MariaDB + +========================================================================================= +Building LLVM from sources +========================================================================================= +If your Linux distribution does not provide a library package for LLVM 3.3 or +newer, and you need LLVM support in Fail*, you may need to build LLVM from the +sources and install it, e.g., locally in your home. + + 1. Download the source tarball of LLVM 3.4 from http://llvm.org (or use the git + repository http://llvm.org/git/llvm.git and checkout release_34) + 2. Configure as needed. On mixed 32/64-bit systems (userland/kernel), + prefixing with "linux32" may be necessary: + $ linux32 ./configure --prefix=$(echo ~/localroot/usr) --enable-optimized --disable-assertions --disable-werror + If you have an old version of clang installed, you may need to convince the + configure script to use gcc/g++ instead: + $ CC=gcc CXX=g++ ./configure --prefix=... + 3. Build with "make REQUIRES_RTTI=1", install. diff --git a/doc/how-to-use.txt b/doc/how-to-use.txt index 25029122..57784c53 100644 --- a/doc/how-to-use.txt +++ b/doc/how-to-use.txt @@ -53,6 +53,34 @@ based on the "${PREFIX}/share/doc/bochs/bochsrc-sample.txt" template (or Example experiments and code snippets ========================================================================================= +Experiment "weather-monitor": +********************************************************************** +An example of a DatabaseCampaign with separate experiment. + 1. Add "weather-monitor" to EXPERIMENTS_ACTIVATED, + add "tracing" to PLUGINS_ACTIVATED + 2. Enable BUILD_IMPORT_TRACE, BUILD_PRUNE_TRACE, CONFIG_EVENT_BREAKPOINTS, + CONFIG_EVENT_BREAKPOINTS_RANGE, CONFIG_EVENT_GUESTSYS, CONFIG_EVENT_MEMREAD, + CONFIG_EVENT_MEMWRITE, CONFIG_EVENT_TRAP, CONFIG_SR_RESTORE and CONFIG_SR_SAVE + The options BUILD_BOCHS, BUILD_X86 are needed as well, but are defaults. + 3. In weather-monitor/experimentInfo.hpp set "PREREQUISITES" to 1 and build + Fail*/Bochs using e.g. fail/scripts/rebuild-bochs.sh (-> how-to-build.txt). + Upon minor changes (i.e. not e.g. to aspects), append " -" to the call to + the script. This will rebuild only parts that changed. + 4. Enter experiment_targets/weathermonitor and run: + find . -name "*.bz2" -execdir bunzip2 -k {} + + This extracts all the bzipped files in place while keeping the archives. + 5. In order to record a trace, run the following: + fail-client -q -Wf,--benchmark=weather -Wf,--variant=vanilla + "variant" is used to find the .elf/.vmi inside oostubs/! + The resulting trace thereafter lies within prerequisites/, it's name + being VARIANT.trace + 6. Use "import-trace" (using correct -b & -v, -t is VARIANT.trace) to get the + trace into the database and "prune-trace" to (obviously) prune the data. + 7. Change PREREQUISITES (see 5) back to "0" and rebuild Fail*/Bochs. + 8. Run the "weather-monitor-server" (Don't forget -v & -b!) and "fail-client -q" + from within experiment_targets/weathermonitor/. + You'll need several clients to finish the campaign. + Experiment "hsc-simple": ********************************************************************** A simple standalone experiment (without a separate campaign). To compile this @@ -169,6 +197,37 @@ instantiating the generic DatabaseCampaign. The general workflow is as follows: created result table with columns corresponding to the fields in the Result group of the protobuf message. +Experiment "weather-monitor" with gem5: +********************************************************************** +This experiment simulates a simple weather-station. +To compile this experiment, the following steps are required: + + 1. Adapt fail/src/experiments/weather-monitor/experimentInfo.hpp + 2. Enter ${FAIL_DIR}/build/ + 3. Add "weather-monitor" to ccmake's EXPERIMENTS_ACTIVATED. + 4. Add "tracing" to ccmake's PLUGINS_ACTIVATED. + 5. Enable BUILD_ARM, BUILD_GEM5, BUILD_IMPORT_TRACE, BUILD_PRUNE_TRACE, + CONFIG_EVENT_BREAKPOINTS, CONFIG_EVENT_BREAKPOINTS_RANGE, CONFIG_EVENT_GUESTSYS, + CONFIG_EVENT_MEMREAD, CONFIG_EVENT_MEMWRITE, CONFIG_EVENT_TRAP, CONFIG_SR_RESTORE + and CONFIG_SR_SAVE. + 6. Enable STEP1 in fail/src/experiments/weather-monitor/experiment.cc + 7. Build Fail* and gem5, see "how-to-build.txt" for details. + 8. Start the gem5-fail-client by typing + "../scripts/run-gem5.sh ../../experiment_targets/weathermonitor_arm/weather.elf + weathermonitor_arm/weather.elf" + 9. Import the trace with + "import-trace -t trace.tc.weather -d YOUR_DB -v baseline -b weather -i + BasicImporter -e ../../experiment_targets/weathermonitor_arm/weather.elf + --faultspace-rightmargin W" + 10. Prune the trace with + "prune-trace -d YOUR_DB -v baseline -b weather" + 11. Enable STEP3 in fail/src/experiments/weather-monitor/experiment.cc + 12. Build Fail* and gem5, see "how-to-build.txt" for details. + 13. Start the campaign-server + "bin/weather-monitor-server -v baseline -b weather" + 14. Start the gem5-fail-client by typing + "../scripts/run-gem5.sh ../../experiment_targets/weathermonitor_arm/weather.elf + ========================================================================================= Parallelization ========================================================================================= @@ -206,6 +265,7 @@ themselves, they contain some documentation): - multiple-clients.sh: Is run on an experiment host by runcampaign.sh, starts several instances of client.sh in a tmux session. - client.sh: (Repeatedly) Runs a single fail-client instance. + - run-gem5.sh: Runs a single gem5-fail-client instance. Some useful things to note: @@ -240,6 +300,11 @@ Steps to run an experiment with gem5: 4. Run gem5 in $FAIL_DIR/simulators/gem5/ with: $ M5_PATH=$SYSTEM build/ARM/gem5.debug configs/example/fs.py --bare-metal --kernel kernelname +Step 4 has been encapsulated in a shell script: + 1. Enter ${FAIL_DIR}/build/ + 2. Run the run-gem5.sh script with the path of the elf-binary + ../scripts/run-gem5.sh path-to-elf-binary + ========================================================================================= Steps to run an experiment with the pandaboard/openocd backend: ========================================================================================= diff --git a/scripts/.gitignore b/scripts/.gitignore new file mode 100644 index 00000000..c9ec5b57 --- /dev/null +++ b/scripts/.gitignore @@ -0,0 +1 @@ +!*/Makefile diff --git a/scripts/client.sh b/scripts/client.sh index ee502047..3bf0a404 100755 --- a/scripts/client.sh +++ b/scripts/client.sh @@ -51,7 +51,7 @@ do #nice -n 19 ./bochs -q 2>&1 | tee log.$$.txt | fgrep Result #nice -n 18 ./bochs -q 2>&1 | fgrep Result nice -n 18 ./fail-client -q >/dev/null 2>&1 - if [ $? -eq 1 ] + if [ $? -gt 0 ] # exit on any error then break fi diff --git a/scripts/docker/Makefile b/scripts/docker/Makefile new file mode 100644 index 00000000..4371f289 --- /dev/null +++ b/scripts/docker/Makefile @@ -0,0 +1,19 @@ +all: + docker build -t danceos/fail-base fail-base + docker build -t danceos/fail-generic-tracing fail-generic-tracing + docker build -t danceos/fail-demo fail-demo + + +run-fail-db: + docker run --name fail-db \ + -e MYSQL_ROOT_PASSWORD=fail \ + -e MYSQL_USER=fail \ + -e MYSQL_PASSWORD=fail \ + -e MYSQL_DATABASE=fail \ + -d mysql + +run-fail-demo: + docker run --name fail-demo -p 127.0.0.1:5000:5000 --link fail-db:mysql -d danceos/fail-demo + +ssh-fail-demo: + ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no fail@$$(docker inspect --format "{{ .NetworkSettings.IPAddress }}" fail-demo) diff --git a/scripts/docker/fail-base/Dockerfile b/scripts/docker/fail-base/Dockerfile new file mode 100644 index 00000000..27760842 --- /dev/null +++ b/scripts/docker/fail-base/Dockerfile @@ -0,0 +1,59 @@ +# Set the base image to Ubuntu Utopic (14.10) +FROM ubuntu:utopic + +MAINTAINER Christian Dietrich + +# Install Packages required to build FAIL* +RUN apt-get update +RUN apt-get install -y \ + binutils-dev \ + build-essential \ + cmake \ + git \ + libboost-regex-dev \ + libboost-system-dev \ + libboost-thread-dev \ + libdwarf-dev \ + libelf-dev \ + libfontconfig1-dev \ + libiberty-dev \ + libmysqlclient-dev \ + libpcl1-dev \ + libprotobuf-dev \ + libsvga1-dev \ + llvm-3.4-dev \ + screen \ + protobuf-compiler \ + wget \ + openssh-server \ + vim \ + zlib1g-dev + +# Add a user for compiling FAIL* +RUN useradd fail; mkdir /home/fail; chown fail /home/fail +RUN echo 'fail:fail' | chpasswd; chsh fail --shell /bin/bash +RUN adduser fail sudo + +# SSH login fix. Otherwise user is kicked off after login +RUN mkdir /var/run/sshd +RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd + +ENV NOTVISIBLE "in users profile" +RUN echo "export VISIBLE=now" >> /etc/profile + +USER fail +ENV HOME /home/fail +WORKDIR /home/fail + +# Get AspectC++ v1.2 for 64 Bit +RUN wget http://www.aspectc.org/releases/1.2/ac-bin-linux-x86-64bit-1.2.tar.gz +RUN tar xvzf ac-bin-linux-x86-64bit-1.2.tar.gz; mkdir bin; mv aspectc++/ac++ aspectc++/ag++ bin/; rm -rf aspectc++ +ENV PATH /home/fail/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +# Clone FAIL* +RUN git clone https://github.com/danceos/fail.git +WORKDIR fail + +USER root +EXPOSE 22 +CMD ["/usr/sbin/sshd", "-D"] diff --git a/scripts/docker/fail-demo/Dockerfile b/scripts/docker/fail-demo/Dockerfile new file mode 100644 index 00000000..e51abd69 --- /dev/null +++ b/scripts/docker/fail-demo/Dockerfile @@ -0,0 +1,45 @@ +# Inherit from docker container that has the fail source code +# prepared, including all tools which are needed to build FAIL*. The +# generic-tracing experiment was already built and the binaries are in +# place (~fail/bin/*) + +FROM danceos/fail-generic-tracing +MAINTAINER Christian Dietrich + +# Install Additional Packages +RUN apt-get install -y \ + python-minimal \ + grub-common \ + xorriso \ + grub-pc-bin \ + mysql-client \ + python-flask \ + python-mysqldb \ + python-yaml + + +# Passwort for MySQL Daemon +ADD my.cnf /home/fail/.my.cnf +RUN chown fail /home/fail/.my.cnf + +USER fail +WORKDIR /home/fail +RUN echo 'export PATH=$HOME/bin:$PATH' >> ~/.profile;\ + echo 'cd $HOME/fail-targets' >> ~/.profile + +RUN git clone https://github.com/danceos/fail-targets.git + +WORKDIR fail +RUN mkdir build; cd build; ../configurations/x86_pruning.sh generic-experiment +WORKDIR build + +# Make FAIL* +RUN make -j$(getconf _NPROCESSORS_ONLN) || make -j$(getconf _NPROCESSORS_ONLN) +RUN ln -s /home/fail/fail/build/bin/fail-client /home/fail/bin/generic-experiment-client; \ + ln -s /home/fail/fail/build/bin/generic-experiment-server /home/fail/bin/; \ + ln -s /home/fail/fail/tools/analysis/resultbrowser/run.py /home/fail/bin/resultbrowser + +# For the resultbrowser, we expose port 5000 to the outside world. +EXPOSE 5000 + +USER root diff --git a/scripts/docker/fail-demo/my.cnf b/scripts/docker/fail-demo/my.cnf new file mode 100644 index 00000000..ed356aed --- /dev/null +++ b/scripts/docker/fail-demo/my.cnf @@ -0,0 +1,5 @@ +[client] +host=mysql +user=fail +password=fail +database=fail diff --git a/scripts/docker/fail-generic-tracing/Dockerfile b/scripts/docker/fail-generic-tracing/Dockerfile new file mode 100644 index 00000000..aa67c31a --- /dev/null +++ b/scripts/docker/fail-generic-tracing/Dockerfile @@ -0,0 +1,25 @@ +# Inherit from docker container that has the fail source code prepared, +# including all tools which are needed to build FAIL* +FROM danceos/fail-base +MAINTAINER Christian Dietrich + +USER fail + +# Configure the Weather Monitor Experiment +ENV PATH /home/fail/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +WORKDIR /home/fail/fail +RUN mkdir build-tracer; cd build-tracer; ../configurations/x86_pruning.sh generic-tracing +WORKDIR build-tracer + +# Make FAIL* +RUN make -j$(getconf _NPROCESSORS_ONLN) || make -j$(getconf _NPROCESSORS_ONLN) + +RUN ln -s /home/fail/fail/build-tracer/bin/fail-client /home/fail/bin/fail-x86-tracing; \ + ln -s /home/fail/fail/build-tracer/bin/import-trace /home/fail/bin/; \ + ln -s /home/fail/fail/build-tracer/bin/prune-trace /home/fail/bin/; \ + ln -s /home/fail/fail/build-tracer/bin/dump-trace /home/fail/bin/; \ + ln -s /home/fail/fail/build-tracer/bin/convert-trace /home/fail/bin/; \ + cp /home/fail/fail/tools/bochs-experiment-runner/bochs-experiment-runner.py /home/fail/bin/bochs-experiment-runner.py; \ + chmod a+x /home/fail/bin/bochs-experiment-runner.py; + +USER root diff --git a/scripts/fail-cleanup-db.sh b/scripts/fail-cleanup-db.sh new file mode 100755 index 00000000..66ca12d9 --- /dev/null +++ b/scripts/fail-cleanup-db.sh @@ -0,0 +1,149 @@ +#!/bin/bash + +# +# This script removes dangling rows from the database, for example 'trace' +# entries with a variant_id not mentioned in the 'variants' table, or result +# rows referencing a nonexistent 'fsppilot' entry. IOW, this script enforces +# referential integrity as it would be maintained by foreign key constraints +# (that can only be used with InnoDB tables). +# + +if [ -z "$1" -o -z "$2" ] +then + echo "usage: $0 dbname resulttable" >&2 + exit 1 +fi +DB=$1 +RESULT=$2 +MYSQL=mysql + +function table_exists() +{ + N=$(echo "SHOW TABLES LIKE '$1'" | $MYSQL $DB | wc -l) + [ $N -gt 0 ] + return +} + +if table_exists trace +then + echo -n "removing widowed entries in trace ..." + echo " "$( + $MYSQL $DB < variantlist = db->get_variants(variants, variants_exclude, benchmarks, benchmarks_exclude); + + // Which Pilots were already processed? + load_completed_pilots(variantlist); + for (std::vector::const_iterator it = variantlist.begin(); it != variantlist.end(); ++it) { + // Push all other variants to the queue if (!run_variant(*it)) { log_send << "run_variant failed for " << it->variant << "/" << it->benchmark < &variants) { + // If no variants were given, do nothing + if (variants.size() == 0) + return; + // load list of partially or completely finished pilots + std::stringstream variant_str; + bool comma = false; + for (std::vector::const_iterator it = variants.begin(); + it != variants.end(); ++it) { + if (comma) variant_str << ", "; + variant_str << it->id; + comma = true; // Next time we need a comma + } + log_send << "loading completed pilot IDs ..." << std::endl; + std::stringstream sql; - sql << "SELECT pilot_id, COUNT(*) FROM " << db_connect.result_table() + sql << "SELECT pilot_id, COUNT(*) FROM fsppilot p" + << " JOIN " << db_connect.result_table() << " r ON r.pilot_id = p.id" + << " WHERE variant_id in (" << variant_str.str() << ")" << " GROUP BY pilot_id "; MYSQL_RES *ids = db->query_stream(sql.str().c_str()); - log_send << "loading completed pilot IDs ..." << std::endl; MYSQL_ROW row; unsigned rowcount = 0; while ((row = mysql_fetch_row(ids)) != 0) { diff --git a/src/core/cpn/DatabaseCampaign.hpp b/src/core/cpn/DatabaseCampaign.hpp index 11f4a8f7..977c120b 100644 --- a/src/core/cpn/DatabaseCampaign.hpp +++ b/src/core/cpn/DatabaseCampaign.hpp @@ -29,7 +29,7 @@ class DatabaseCampaign : public Campaign { int fspmethod_id; // !< Which fspmethod should be put out to the clients void collect_result_thread(); - void load_completed_pilots(); + void load_completed_pilots(std::vector &); unsigned existing_results_for_pilot(unsigned pilot_id); #ifndef __puma diff --git a/src/core/efw/CMakeLists.txt b/src/core/efw/CMakeLists.txt index e0e2fe2c..b13748e4 100644 --- a/src/core/efw/CMakeLists.txt +++ b/src/core/efw/CMakeLists.txt @@ -4,10 +4,12 @@ set(SRCS ExperimentFlow.hpp JobClient.hpp JobClient.cc + DatabaseExperiment.hpp + DatabaseExperiment.cc ) add_library(fail-efw ${SRCS}) -add_dependencies(fail-efw fail-comm) +add_dependencies(fail-efw fail-protoc) target_link_libraries(fail-efw fail-comm) target_link_libraries(fail-efw fail-util) # WallclockTimer diff --git a/src/core/efw/DatabaseExperiment.cc b/src/core/efw/DatabaseExperiment.cc new file mode 100644 index 00000000..24c9234e --- /dev/null +++ b/src/core/efw/DatabaseExperiment.cc @@ -0,0 +1,183 @@ +#include +#include + +#include +#include "sal/SALConfig.hpp" +#include "sal/Memory.hpp" +#include "sal/Listener.hpp" +#include "efw/DatabaseExperiment.hpp" +#include +#include +#include "comm/DatabaseCampaignMessage.pb.h" +#include "sal/bochs/BochsListener.hpp" +#include +#include + + +using namespace std; +using namespace fail; +using namespace google::protobuf; + +// Check if configuration dependencies are satisfied: +#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) + #error This experiment needs: breakpoints, restore. Enable these in the configuration. +#endif + +DatabaseExperiment::~DatabaseExperiment() { + delete this->m_jc; +} + +unsigned DatabaseExperiment::injectBitFlip(address_t data_address, unsigned bitpos){ + unsigned int value, injectedval; + + value = m_mm.getByte(data_address); + injectedval = value ^ (1 << bitpos); + m_mm.setByte(data_address, injectedval); + + m_log << "INJECTION at: 0x" << hex<< setw(2) << setfill('0') << data_address + << " value: 0x" << setw(2) << setfill('0') << value << " -> 0x" + << setw(2) << setfill('0') << (unsigned) m_mm.getByte(data_address) << endl; + + return value; +} + +template +T * protobufFindSubmessageByTypename(Message *msg, const std::string &name) { + T * submessage = 0; + const Descriptor *msg_type = msg->GetDescriptor(); + const Message::Reflection *ref = msg->GetReflection(); + const Descriptor *database_desc = + DescriptorPool::generated_pool()->FindMessageTypeByName(name); + assert(database_desc != 0); + + size_t count = msg_type->field_count(); + + for (unsigned i = 0; i < count; i++) { + const FieldDescriptor *field = msg_type->field(i); + assert(field != 0); + if (field->message_type() == database_desc) { + submessage = dynamic_cast(ref->MutableMessage(msg, field)); + assert(submessage != 0); + break; + } + } + return submessage; +} + + +bool DatabaseExperiment::run() +{ + m_log << "STARTING EXPERIMENT" << endl; + + if (!this->cb_start_experiment()) { + m_log << "Initialization failed. Exiting." << endl; + simulator.terminate(1); + } + + unsigned executed_jobs = 0; + + while (executed_jobs < 25 || m_jc->getNumberOfUndoneJobs() > 0) { + m_log << "asking jobserver for parameters" << endl; + ExperimentData * param = this->cb_allocate_experiment_data(); + if (!m_jc->getParam(*param)){ + m_log << "Dying." << endl; // We were told to die. + simulator.terminate(1); + } + m_current_param = param; + + DatabaseCampaignMessage * fsppilot = + protobufFindSubmessageByTypename(¶m->getMessage(), "DatabaseCampaignMessage"); + assert (fsppilot != 0); + + unsigned injection_instr = fsppilot->injection_instr(); + address_t data_address = fsppilot->data_address(); + unsigned width = fsppilot->data_width(); + + for (unsigned bit_offset = 0; bit_offset < width * 8; ++bit_offset) { + // 8 results in one job + Message *outer_result = cb_new_result(param); + m_current_result = outer_result; + DatabaseExperimentMessage *result = + protobufFindSubmessageByTypename(outer_result, "DatabaseExperimentMessage"); + result->set_bitoffset(bit_offset); + m_log << "restoring state" << endl; + // Restore to the image, which starts at address(main) + simulator.restore(cb_state_directory()); + executed_jobs ++; + + m_log << "Trying to inject @ instr #" << dec << injection_instr << endl; + + simulator.clearListeners(); + + // Generate an experiment listener, that matches on any IP + // event. It is used to forward to the injection + // point. The +1 is needed, since even for the zeroth + // dynamic instruction we need at least one breakpoint + // event. + BPSingleListener bp; + bp.setWatchInstructionPointer(ANY_ADDR); + bp.setCounter(injection_instr + 1); + simulator.addListener(&bp); + + if (!this->cb_before_fast_forward()) { + continue; + } + fail::BaseListener * listener; + while (true) { + listener = simulator.resume(); + if (listener == &bp) { + break; + } else { + bool should_continue = this->cb_during_fast_forward(listener); + if (!should_continue) + break; // Stop fast forwarding + } + } + if (!this->cb_after_fast_forward(listener)) { + continue; // Continue to next injection experiment + } + + address_t injection_instr_absolute = fsppilot->injection_instr_absolute(); + bool found_eip; + for (int i = 0; i < BX_SMP_PROCESSORS; i++) { + address_t eip = simulator.getCPU(i).getInstructionPointer(); + if (eip == injection_instr_absolute) { + found_eip = true; + } + } + if (!found_eip) { + m_log << "Invalid Injection address != 0x" << injection_instr_absolute << std::endl; + simulator.terminate(1); + } + + simulator.clearListeners(); + + /// INJECT BITFLIP: + result->set_original_value(injectBitFlip(data_address, bit_offset)); + + if (!this->cb_before_resume()) { + continue; // Continue to next experiment + } + + m_log << "Resuming till the crash" << std::endl; + // resume and wait for results + while (true) { + listener = simulator.resume(); + bool should_continue = this->cb_during_resume(listener); + if (!should_continue) + break; + } + m_log << "Resume done" << std::endl; + this->cb_after_resume(listener); + + simulator.clearListeners(); + } + m_jc->sendResult(*param); + this->cb_free_experiment_data(param); + } + // Explicitly terminate, or the simulator will continue to run. + simulator.terminate(); + return false; +} + + diff --git a/src/core/efw/DatabaseExperiment.hpp b/src/core/efw/DatabaseExperiment.hpp new file mode 100644 index 00000000..f60ddf9a --- /dev/null +++ b/src/core/efw/DatabaseExperiment.hpp @@ -0,0 +1,150 @@ +#ifndef __DATABASE_EXPERIMENT_HPP__ +#define __DATABASE_EXPERIMENT_HPP__ + +#include +#include "efw/ExperimentFlow.hpp" +#include "efw/JobClient.hpp" +#include "util/Logger.hpp" +#include +#include + +namespace fail { +class ExperimentData; + +class DatabaseExperiment : public fail::ExperimentFlow { + fail::JobClient *m_jc; + + unsigned injectBitFlip(fail::address_t data_address, unsigned bitpos); + + /** + The current experiment data as returned by the job client. This + allocated by cb_allocate_experiment_data() + */ + ExperimentData *m_current_param; + google::protobuf::Message *m_current_result; + +public: + DatabaseExperiment(const std::string &name) + : m_log(name, false), m_mm(fail::simulator.getMemoryManager()) { + + /* The fail server can be set with an environent variable, + otherwise the JOBSERVER configured by cmake ist used */ + char *server_host = getenv("FAIL_SERVER_HOST"); + if (server_host != NULL){ + this->m_jc = new fail::JobClient(std::string(server_host)); + } else { + this->m_jc = new fail::JobClient(); + } + } + + virtual ~DatabaseExperiment(); + + bool run(); + + +protected: + fail::Logger m_log; + fail::MemoryManager& m_mm; + + /** Returns the currently running experiment message as returned + * by the job client + */ + ExperimentData * get_current_experiment_data() { return m_current_param; } + + /** Returns the currently result message, that was allocated by + * cb_allocate_new_result. + */ + google::protobuf::Message * get_current_result() { return m_current_result; } + + + ////////////////////////////////////////////////////////////////// + // Can be overwritten by experiment + ////////////////////////////////////////////////////////////////// + + /** + * Get path to the state directory + */ + virtual std::string cb_state_directory() { return "state"; } + + /** + * Callback that is called, before the actual experiment + * starts. Simulation is terminated on false. + * @param The current result message + * @return \c true on success, \c false otherwise + */ + virtual bool cb_start_experiment() { return true; }; + + /** + * Allocate enough space to hold the incoming ExperimentData + * message. The can be accessed during the experiment through + * get_current_experiment_data() + */ + virtual ExperimentData* cb_allocate_experiment_data() = 0; + virtual void cb_free_experiment_data(ExperimentData *) {}; + + + /** + * Allocate a new result slot in the given experiment data. The + * returned pointer can be obtained by calling + * get_current_result() + */ + virtual google::protobuf::Message* cb_new_result(ExperimentData*) = 0; + + /** + * Callback that is called before the fast forward is done. This + * can be used to add additional event listeners during the fast + * forward phase. If returning false, the experiment is canceled. + * @return \c true on success, \c false otherwise + */ + virtual bool cb_before_fast_forward() { return true; }; + + /** + * Callback that is called during the fast forward, when an event + * has triggered, but it was not the fast forward listener. This + * can be used to collect additional information during the fast + * forward If returning false, the fast forwarding is stopped. + * + * @return \c true on should continue, \c false stop ff + */ + virtual bool cb_during_fast_forward(fail::BaseListener *) { return false; }; + + /** + * Callback that is called after the fast forward, with the last + * triggered event forward If returning false, the experiment is + * canceled. + * + * @return \c true on success, \c false otherwise + */ + virtual bool cb_after_fast_forward(fail::BaseListener *) { return true; }; + + /** + * Callback that is called before the resuming till crash has + * started. This is called after the fault was injected. Here the + * end listeners should be installed. Returns true on + * success. Otherwise the experiment is canceled. + + * @return \c true on success, \c false otherwise + */ + virtual bool cb_before_resume() = 0; + + /** + * Callback that is called during the resume-till-crash phase, + * when an event has triggered, This can be used to collect + * additional information during the resuming phse. If returning + * false, the resuming has finished and the experiment has stopped. + * + * @return \c true on should continue ff, \c false stop ff + */ + virtual bool cb_during_resume(fail::BaseListener *) { return false; }; + + /** + * Callback that is called after the resume-till-crash phase with + * the last triggered listener. This callback should collect all data and + * + */ + virtual void cb_after_resume(fail::BaseListener *) = 0; +}; + +} + +#endif // __DATABASE_EXPERIMENT_HPP__ diff --git a/src/core/sal/Listener.hpp b/src/core/sal/Listener.hpp index af9b750d..37b2bdab 100644 --- a/src/core/sal/Listener.hpp +++ b/src/core/sal/Listener.hpp @@ -749,9 +749,20 @@ public: void setId(timer_id_t id) { m_Data.setId(id); } /** * Retrieves the timer's timeout value. - * @return the timout in microseconds + * @return the timeout in microseconds */ unsigned getTimeout() const { return m_Timeout; } + /** + * Set the timeout value. Returns the old timeout value. Be aware, + * that this method might have no effects, after the listener was added. + * @return the old timeout in microseconds + */ + unsigned setTimeout(unsigned timeout) { + unsigned tmp = m_Timeout; + m_Timeout = timeout; + return tmp; + } + }; } // end-of-namespace: fail diff --git a/src/core/sal/bochs/IOPortCom.ah b/src/core/sal/bochs/IOPortCom.ah index a0bb35fc..26a0ab0a 100644 --- a/src/core/sal/bochs/IOPortCom.ah +++ b/src/core/sal/bochs/IOPortCom.ah @@ -12,29 +12,33 @@ #include "../SALInst.hpp" #include "BochsHelpers.hpp" -// TODO: ATM only capturing bytewise output (most common, I suppose) +// FIXME ATM only capturing the first byte of a multi-byte in/out aspect IOPortCom { - pointcut outInstruction() = "% ...::bx_cpu_c::OUT_DXAL(...)"; + pointcut devices_outp() = "% ...::bx_devices_c::outp(...)"; - advice execution (outInstruction()) : after () + advice call (devices_outp()) && within ("...::bx_cpu_c") : before () { - unsigned rDX = getCPU(tjp->that())->gen_reg[2].word.rx; // port number - unsigned char rAL = getCPU(tjp->that())->gen_reg[0].word.byte.rl; // data - - // Detect the CPU that triggered the change: + unsigned port = *(tjp->arg<0>()); + unsigned data = *(tjp->arg<1>()); + + // detect the CPU that triggered the access fail::ConcreteCPU& triggerCPU = fail::simulator.detectCPU(getCPU(tjp->that())); - fail::simulator.onIOPort(&triggerCPU, rAL, rDX, true); + // forward to SimulatorController + fail::simulator.onIOPort(&triggerCPU, data, port, true); } - pointcut inInstruction() = "% ...::bx_cpu_c::IN_ALDX(...)"; + pointcut devices_inp() = "% ...::bx_devices_c::inp(...)"; - advice execution (inInstruction()) : after () + advice call (devices_inp()) && within ("...::bx_cpu_c") : after () { - unsigned rDX = getCPU(tjp->that())->gen_reg[2].word.rx; // port number - unsigned char rAL = getCPU(tjp->that())->gen_reg[0].word.byte.rl; // data + unsigned port = *(tjp->arg<0>()); + unsigned data = *(tjp->result()); + + // detect the CPU that triggered the access fail::ConcreteCPU& triggerCPU = fail::simulator.detectCPU(getCPU(tjp->that())); - fail::simulator.onIOPort(&triggerCPU, rAL, rDX, false); + // forward to SimulatorController + fail::simulator.onIOPort(&triggerCPU, data, port, false); } }; diff --git a/src/core/util/CMakeLists.txt b/src/core/util/CMakeLists.txt index b8cd483d..1b03c610 100644 --- a/src/core/util/CMakeLists.txt +++ b/src/core/util/CMakeLists.txt @@ -91,4 +91,5 @@ target_link_libraries(memorymap-test fail-util) add_test(NAME memorymap-test WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/testing COMMAND memorymap-test) add_executable(sumtree-test testing/SumTreeTest.cc) +target_link_libraries(sumtree-test fail-util) add_test(NAME sumtree-test WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/testing COMMAND sumtree-test) diff --git a/src/core/util/CommandLine.cc b/src/core/util/CommandLine.cc index 33f6c333..6116beb0 100644 --- a/src/core/util/CommandLine.cc +++ b/src/core/util/CommandLine.cc @@ -43,8 +43,13 @@ bool CommandLine::parse() { option::Descriptor desc = {0, 0, 0, 0, 0, 0}; this->options.push_back(desc); - // Generate the options stats - option::Stats stats(this->options.data(), argv.size(), argv.data()); + // Copy argv to preserve original argument order + // (for proper re-parsing after adding more options) + argv_reordered = argv; + + // Generate the options stats (GNU mode) + option::Stats stats(true, this->options.data(), + argv_reordered.size(), argv_reordered.data()); if (parsed_options) delete[] parsed_options; @@ -56,9 +61,9 @@ bool CommandLine::parse() { parsed_options = new option::Option[stats.options_max]; parsed_buffer = new option::Option[stats.buffer_max]; - m_parser = new option::Parser(this->options.data(), argv.size(), argv.data(), - parsed_options, parsed_buffer); - + m_parser = new option::Parser(true, this->options.data(), + argv_reordered.size(), argv_reordered.data(), + parsed_options, parsed_buffer); // Pop the terminating entry this->options.pop_back(); diff --git a/src/core/util/CommandLine.hpp b/src/core/util/CommandLine.hpp index 21dfd2a3..a89ad9c8 100644 --- a/src/core/util/CommandLine.hpp +++ b/src/core/util/CommandLine.hpp @@ -30,7 +30,7 @@ public: private: static CommandLine m_instance; - std::vector argv; + std::vector argv, argv_reordered; std::vector options; option::Option *parsed_options, *parsed_buffer; option::Parser *m_parser; diff --git a/src/core/util/DatabaseProtobufAdapter.cc b/src/core/util/DatabaseProtobufAdapter.cc index cd7cf0f7..6c4a0c29 100644 --- a/src/core/util/DatabaseProtobufAdapter.cc +++ b/src/core/util/DatabaseProtobufAdapter.cc @@ -133,9 +133,11 @@ void DatabaseProtobufAdapter::TypeBridge_string::bind(MYSQL_BIND *bind, const go /* Handle the NULL case */ if (insert_null(bind, msg)) return; + buffer = ref->GetString(*msg, desc); + bind->buffer_type = MYSQL_TYPE_STRING; - bind->buffer = (void *) ref->GetString(*msg, desc).c_str(); - bind->buffer_length = ref->GetString(*msg, desc).length(); + bind->buffer = (void *) buffer.c_str(); + bind->buffer_length = buffer.length(); } void DatabaseProtobufAdapter::TypeBridge_enum::bind(MYSQL_BIND *bind, const google::protobuf::Message *msg) { const google::protobuf::Reflection *ref = msg->GetReflection(); diff --git a/src/core/util/DatabaseProtobufAdapter.hpp b/src/core/util/DatabaseProtobufAdapter.hpp index 6f0f8ad1..ca9bffd2 100644 --- a/src/core/util/DatabaseProtobufAdapter.hpp +++ b/src/core/util/DatabaseProtobufAdapter.hpp @@ -80,7 +80,7 @@ class DatabaseProtobufAdapter { TypeBridge_uint32(const google::protobuf::FieldDescriptor *desc) : TypeBridge(desc){}; - virtual std::string sql_type() { return "INT"; }; + virtual std::string sql_type() { return "INT UNSIGNED"; }; virtual int element_size() { return 4; }; virtual void copy_to(const google::protobuf::Message *msg, int i, void *); virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg); @@ -101,7 +101,7 @@ class DatabaseProtobufAdapter { TypeBridge_uint64(const google::protobuf::FieldDescriptor *desc) : TypeBridge(desc){}; - virtual std::string sql_type() { return "BIGINT"; }; + virtual std::string sql_type() { return "BIGINT UNSIGNED"; }; virtual int element_size() { return 8; }; virtual void copy_to(const google::protobuf::Message *msg, int i, void *); virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg); @@ -138,6 +138,7 @@ class DatabaseProtobufAdapter { }; struct TypeBridge_string : TypeBridge { + std::string buffer; TypeBridge_string(const google::protobuf::FieldDescriptor *desc) : TypeBridge(desc){}; virtual std::string sql_type() { return "TEXT"; }; diff --git a/src/core/util/DwarfReader.cc b/src/core/util/DwarfReader.cc index aa7f612f..0a56e4ff 100644 --- a/src/core/util/DwarfReader.cc +++ b/src/core/util/DwarfReader.cc @@ -1,6 +1,8 @@ #include +#include #include #include +#include #include "DwarfReader.hpp" #include "libdwarf.h" @@ -128,8 +130,10 @@ bool DwarfReader::read_source_files(const std::string& fileName,std::list(addr) << " line source:" << normalize(lineSource) << endl; @@ -171,14 +183,20 @@ bool DwarfReader::read_source_files(const std::string& fileName,std::list& addrToLineList) { +bool DwarfReader::read_mapping(std::string fileName, std::list& lineMapping) { + // temporary mapping of instruction address to (file, line) + // => static instruction addresses are sorted ascendingly for the whole binary + // (i.e. all instructions from all CUs!) + std::map instr_to_sourceline; // Open The file int fd=open(fileName.c_str(),O_RDONLY); @@ -200,10 +218,13 @@ bool DwarfReader::read_mapping(std::string fileName, std::list& addr // Iterator over the headers Dwarf_Unsigned header; + // iterate compilation unit headers while (dwarf_next_cu_header(dbg,0,0,0,0,&header,0)==DW_DLV_OK) { // Access the die Dwarf_Die die; + // XXX: "if there are no sibling headers, die" | semantics unclear! if (dwarf_siblingof(dbg,0,&die,0)!=DW_DLV_OK) { + close(fd); return false; } @@ -211,6 +232,7 @@ bool DwarfReader::read_mapping(std::string fileName, std::list& addr Dwarf_Line* lineBuffer; Dwarf_Signed lineCount; if (dwarf_srclines(die,&lineBuffer,&lineCount,0)!=DW_DLV_OK) { + close(fd); continue; //return false; } @@ -218,24 +240,30 @@ bool DwarfReader::read_mapping(std::string fileName, std::list& addr for (int index=0;index& addr // Shut down libdwarf if (dwarf_finish(dbg,0)!=DW_DLV_OK) { + close(fd); return false; } + // iterate instr_to_sourceline to determine the "line_range_size" for mapping + std::map::iterator it; + for (it = instr_to_sourceline.begin(); it != instr_to_sourceline.end(); it++) { + unsigned addr = it->first; + SourceLine sl = it->second; + + /* Default the linetable's address range (->"size") to the maximum + * possible value. This results in the last linetable entry having + * maximum range. This entry will either be a dummy or a function's + * epilogue, both of which are irrelevant for our (current) use cases. + * All other entries' sizes are set properly. */ + DwarfLineMapping mapping(addr, (std::numeric_limits::max() - addr), + sl.line_number, sl.source_file); + if (!lineMapping.empty()) { + DwarfLineMapping& back = lineMapping.back(); + back.line_range_size = addr - back.absolute_addr; + } + lineMapping.push_back(mapping); + } + close(fd); return true; } diff --git a/src/core/util/DwarfReader.hpp b/src/core/util/DwarfReader.hpp index bda3dc2e..c8894f71 100644 --- a/src/core/util/DwarfReader.hpp +++ b/src/core/util/DwarfReader.hpp @@ -7,6 +7,26 @@ namespace fail { +// temporary wrapper object for (file, linenumber) +class SourceLine { +public: + std::string source_file; + unsigned line_number; + + SourceLine(std::string source, unsigned line) : source_file(source), line_number(line) {} +}; + +// wrapper object for insertion into DB +class DwarfLineMapping { +public: + unsigned absolute_addr; + unsigned line_range_size; + unsigned line_number; + std::string line_source; + + DwarfLineMapping(unsigned addr, unsigned size, unsigned number, std::string src) + : absolute_addr(addr), line_range_size(size), line_number(number), line_source(src){} +}; /** * This source code is based on bcov 0.2. @@ -15,23 +35,16 @@ namespace fail { * GNU GENERAL PUBLIC LICENSE */ - struct addrToLine { - int absoluteAddr; - int lineNumber; - std::string lineSource; - }; - - /** - * \class DwarfReader - * ToDO - */ - - class DwarfReader { +/** +* \class DwarfReader +* ToDO +*/ +class DwarfReader { public: bool read_source_files(const std::string& fileName, std::list& lines); - bool read_mapping(std::string fileName, std::list& addrToLineList); + bool read_mapping(std::string fileName, std::list& lineMapping); }; } // end-of-namespace fail diff --git a/src/core/util/MemoryMap.cc b/src/core/util/MemoryMap.cc index 4429cf1b..b0155e9d 100644 --- a/src/core/util/MemoryMap.cc +++ b/src/core/util/MemoryMap.cc @@ -19,11 +19,15 @@ bool MemoryMap::readFromFile(char const * const filename) unsigned count = 0; while (getline(file, buf)) { + std::string addr, len; std::stringstream ss(buf, std::ios::in); - ss >> guest_addr >> guest_len; + ss >> addr >> len; + guest_addr = strtoul(addr.c_str(), NULL, 0); + guest_len = strtoul(len.c_str(), NULL, 0); add(guest_addr, guest_len); count++; } + // assertion kept from original code; usually something's fishy if the file // contains no entries assert(count > 0); diff --git a/src/core/util/llvmdisassembler/CMakeLists.txt b/src/core/util/llvmdisassembler/CMakeLists.txt index 80f52b1d..3fe2a89e 100644 --- a/src/core/util/llvmdisassembler/CMakeLists.txt +++ b/src/core/util/llvmdisassembler/CMakeLists.txt @@ -11,8 +11,7 @@ set(SRCS include(FindLLVM) -# compiling without -fno-rtti fails even when LLVM is not built with that flag -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LLVM_CXX_FLAGS} -fno-rtti" ) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LLVM_CXX_FLAGS}" ) add_library(fail-llvmdisassembler ${SRCS}) target_link_libraries(fail-llvmdisassembler fail-sal) diff --git a/src/core/util/llvmdisassembler/LLVMtoFailTranslator.cpp b/src/core/util/llvmdisassembler/LLVMtoFailTranslator.cpp index 77a642dc..75aa444f 100644 --- a/src/core/util/llvmdisassembler/LLVMtoFailTranslator.cpp +++ b/src/core/util/llvmdisassembler/LLVMtoFailTranslator.cpp @@ -49,7 +49,10 @@ LLVMtoFailTranslator* LLVMtoFailTranslator::createFromBinary(const std::string e llvm::InitializeAllDisassemblers(); OwningPtr binary; - assert(createBinary(elf_path, binary) == 0); + llvm::error_code ret = createBinary(elf_path, binary); + assert (ret == 0); + (void) ret; // unused in release builds + assert (binary.get() != NULL); #ifndef __puma LLVMDisassembler disas(dyn_cast(binary.get())); @@ -57,4 +60,4 @@ LLVMtoFailTranslator* LLVMtoFailTranslator::createFromBinary(const std::string e #else return 0; #endif -} \ No newline at end of file +} diff --git a/src/core/util/llvmdisassembler/testing/llvmDisTest.cc b/src/core/util/llvmdisassembler/testing/llvmDisTest.cc index f2a1fc59..9f02ab12 100644 --- a/src/core/util/llvmdisassembler/testing/llvmDisTest.cc +++ b/src/core/util/llvmdisassembler/testing/llvmDisTest.cc @@ -1,4 +1,3 @@ -#ifndef __puma #include "../LLVMDisassembler.hpp" using namespace llvm; @@ -69,4 +68,3 @@ int main(int argc, char* argv[]) { std::cout << std::endl; } } -#endif diff --git a/src/core/util/testing/SumTreeTest.cc b/src/core/util/testing/SumTreeTest.cc index ad9d717b..e4880632 100644 --- a/src/core/util/testing/SumTreeTest.cc +++ b/src/core/util/testing/SumTreeTest.cc @@ -1,10 +1,12 @@ #include "util/SumTree.hpp" +#include "util/Logger.hpp" #include -#define LOG std::cerr using std::endl; +fail::Logger LOG("SumTreeTest"); + struct Pilot { uint32_t id; uint32_t instr2; diff --git a/src/core/util/testing/memorymap-test.cc b/src/core/util/testing/memorymap-test.cc index ba8cc4ab..bdea091c 100644 --- a/src/core/util/testing/memorymap-test.cc +++ b/src/core/util/testing/memorymap-test.cc @@ -1,6 +1,7 @@ #include #include #include +#include #include "util/MemoryMap.hpp" using namespace fail; @@ -16,6 +17,7 @@ uint32_t outside[] = { 0, 10, 16, 1, 20, 1, 25, 10 }; void test_failed(std::string msg) { cerr << "MemoryMap test failed (" << msg << ")!" << endl; + abort(); } // pass by value intentional @@ -98,6 +100,7 @@ int main() char const *filename_tmp = "tmp.memorymap"; char const *filename_test1 = "test1.memorymap"; char const *filename_test2 = "test2.memorymap"; + char const *filename_test3 = "test3.memorymap"; for (unsigned i = 0; i < LEN(inside); i += 2) { mm.add(inside[i], inside[i+1]); @@ -125,4 +128,8 @@ int main() mm.clear(); mm.readFromFile(filename_test2); test(mm); + + mm.clear(); + mm.readFromFile(filename_test3); + test(mm); } diff --git a/src/core/util/testing/test3.memorymap b/src/core/util/testing/test3.memorymap new file mode 100644 index 00000000..7c6dc0a7 --- /dev/null +++ b/src/core/util/testing/test3.memorymap @@ -0,0 +1,3 @@ +012 0x6 +0x11 3 +21 0x4 diff --git a/src/experiments/cored-tester/CMakeLists.txt b/src/experiments/cored-tester/CMakeLists.txt new file mode 100644 index 00000000..8b046fb9 --- /dev/null +++ b/src/experiments/cored-tester/CMakeLists.txt @@ -0,0 +1,37 @@ +set(EXPERIMENT_NAME cored-tester) +set(EXPERIMENT_TYPE CoredTester) +configure_file(../instantiate-experiment.ah.in + ${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY +) + +## Setup desired protobuf descriptions HERE ## +set(MY_PROTOS + cored-tester.proto +) + +set(MY_CAMPAIGN_SRCS + experiment.hpp + experiment.cc + campaign.hpp + campaign.cc +) + +#### PROTOBUFS #### +find_package(Protobuf REQUIRED) +include_directories(${PROTOBUF_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/../../core/comm) +PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS}) + +## Build library +add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS}) +add_dependencies(fail-${EXPERIMENT_NAME} fail-comm) +target_link_libraries(fail-${EXPERIMENT_NAME} fail-comm) +target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY} fail-llvmdisassembler) + +## This is the example's campaign server distributing experiment parameters +add_executable(${EXPERIMENT_NAME}-server main.cc) +target_link_libraries(${EXPERIMENT_NAME}-server -Wl,--start-group fail-${EXPERIMENT_NAME} fail-sal fail-util fail-cpn fail-comm ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY} -lmysqlclient -Wl,--end-group) +install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin) + diff --git a/src/experiments/cored-tester/campaign.cc b/src/experiments/cored-tester/campaign.cc new file mode 100644 index 00000000..d2335667 --- /dev/null +++ b/src/experiments/cored-tester/campaign.cc @@ -0,0 +1,20 @@ +#include +#include + +#include "campaign.hpp" +#include "cpn/CampaignManager.hpp" +#include "util/Logger.hpp" +#include "util/ElfReader.hpp" +#include "util/ProtoStream.hpp" +#include "sal/SALConfig.hpp" + +using namespace std; +using namespace fail; +using namespace google::protobuf; + +void CoredTesterCampaign::cb_send_pilot(DatabaseCampaignMessage pilot) { + CoredTesterExperimentData *data = new CoredTesterExperimentData; + data->msg.mutable_fsppilot()->CopyFrom(pilot); + campaignmanager.addParam(data); +} + diff --git a/src/experiments/cored-tester/campaign.hpp b/src/experiments/cored-tester/campaign.hpp new file mode 100644 index 00000000..f54a8ce6 --- /dev/null +++ b/src/experiments/cored-tester/campaign.hpp @@ -0,0 +1,30 @@ +#ifndef __DCIAOCAMPAIGN_HPP__ +#define __DCIAOCAMPAIGN_HPP__ + +#include "cpn/DatabaseCampaign.hpp" +#include "comm/ExperimentData.hpp" +#include "cored-tester.pb.h" +#include "util/ElfReader.hpp" +#include + +class CoredTesterExperimentData : public fail::ExperimentData { +public: + CoredTesterProtoMsg msg; + CoredTesterExperimentData() : fail::ExperimentData(&msg) {} +}; + +class CoredTesterCampaign : public fail::DatabaseCampaign { + virtual const google::protobuf::Descriptor * cb_result_message() + { return google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("CoredTesterProtoMsg"); } + + virtual void cb_send_pilot(DatabaseCampaignMessage pilot); + virtual int expected_number_of_results(std::string variant, std::string benchmark) { + if (benchmark.find("jump") != std::string::npos) + return 1; + else + return 8; + } + +}; + +#endif // __KESOREFCAMPAIGN_HPP__ diff --git a/src/experiments/cored-tester/cored-tester.proto b/src/experiments/cored-tester/cored-tester.proto new file mode 100644 index 00000000..5131b60d --- /dev/null +++ b/src/experiments/cored-tester/cored-tester.proto @@ -0,0 +1,39 @@ +import "DatabaseCampaignMessage.proto"; + +message CoredTesterProtoMsg { + required DatabaseCampaignMessage fsppilot = 1; + + repeated group Result = 2 { + enum ResultType { + /* Test did the right thing */ + OK = 1; + OK_DETECTED_ERROR = 3; + + /* Test did the wrong thing */ + SDC_WRONG_RESULT = 4; + + /* Test detected the error */ + ERR_TRAP = 5; + ERR_TIMEOUT = 6; + + ERR_ASSERT_UNKOWN = 7; + ERR_ASSERT_SYSTEM_STATE = 8; + ERR_ASSERT_CFG_REGION = 9; + ERR_ASSERT_SPURIOUS = 10; + + UNKNOWN = 20; + NOINJECTION = 21; + } + + required int32 bitoffset = 1 [(sql_primary_key) = true]; + required ResultType resulttype = 2; + required uint32 experiment_number = 3; + + /* At which point in time did the crash occur */ + optional uint64 time_crash = 4; + + optional uint32 original_value = 5; + + optional string details = 6; + } +} diff --git a/src/experiments/cored-tester/experiment.cc b/src/experiments/cored-tester/experiment.cc new file mode 100644 index 00000000..0e8a486d --- /dev/null +++ b/src/experiments/cored-tester/experiment.cc @@ -0,0 +1,586 @@ +#undef NDEBUG +#include +#include +#include +#include + +#include +#include + +#include +#include "experiment.hpp" +#include "sal/SALConfig.hpp" +#include "sal/SALInst.hpp" +#include "sal/Memory.hpp" +#include "sal/Listener.hpp" + +#include "sal/bochs/BochsListener.hpp" +#include "sal/bochs/BochsMemory.hpp" +#include "sal/bochs/BochsCPU.hpp" +#include +#include +#include +#include + +#include "util/llvmdisassembler/LLVMtoFailTranslator.hpp" +#include "util/llvmdisassembler/LLVMtoFailBochs.hpp" + +#include "campaign.hpp" +#include "cored-tester.pb.h" + +#include "../plugins/randomgenerator/RandomGenerator.hpp" +#include "../plugins/checkpoint/Checkpoint.hpp" + +using namespace std; +using namespace fail; + +#define SAFESTATE (1) + +// Check if configuration dependencies are satisfied: +#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) || \ + !defined(CONFIG_SR_SAVE) +#error This experiment needs: breakpoints, traps, save, and restore. Enable these in the configuration. +#endif +#if !defined(CONFIG_EVENT_MEMREAD) || !defined(CONFIG_EVENT_MEMWRITE) +#error This experiment needs: MemRead and MemWrite. Enable these in the configuration. +#endif + +void CoredTester::redecodeCurrentInstruction() { + /* Flush Instruction Caches and Prefetch queue */ + BX_CPU_C *cpu_context = simulator.getCPUContext(); + cpu_context->invalidate_prefetch_q(); + cpu_context->iCache.flushICacheEntries(); + + + guest_address_t pc = simulator.getCPU(0).getInstructionPointer(); + bxInstruction_c *currInstr = simulator.getCurrentInstruction(); + //unsigned length_in_bytes = currInstr->ilen(); + + m_log << "REDECODE INSTRUCTION @ IP 0x" << std::hex << pc << endl; + + Bit32u eipBiased = pc + cpu_context->eipPageBias; + Bit8u instr_plain[15]; + + MemoryManager& mm = simulator.getMemoryManager(); + for(unsigned i=0; ieipPageWindowSize - eipBiased; + int ret; +#if BX_SUPPORT_X86_64 + if (cpu_context->cpu_mode == BX_MODE_LONG_64) + ret = cpu_context->fetchDecode64(instr_plain, currInstr, remainingInPage); + else +#endif + ret = cpu_context->fetchDecode32(instr_plain, currInstr, remainingInPage); + if (ret < 0) { + // handle instrumentation callback inside boundaryFetch + cpu_context->boundaryFetch(instr_plain, remainingInPage, currInstr); + } +} + + +unsigned CoredTester::injectBitFlip(address_t data_address, unsigned data_width, unsigned bitpos) { + /* First 32 Registers, this might neeed adaption */ + if (data_address < (32 << 8)) { + LLVMtoFailTranslator::reginfo_t reginfo = LLVMtoFailTranslator::reginfo_t::fromDataAddress(data_address, data_width); + + unsigned int value, injectedval; + + value = m_ltof->getRegisterContent(simulator.getCPU(0), reginfo); + injectedval = value ^ (1 << bitpos); + m_ltof->setRegisterContent(simulator.getCPU(0), reginfo, injectedval); + + m_log << "INJECTING register (" << dec << reginfo.id + << " offset " << (int) reginfo.offset + << ") bitpos: " << bitpos + << " value: 0x" << hex << setw(2) << setfill('0') << value << " -> 0x" << setw(2) << setfill('0') << injectedval + << dec << endl; + if (reginfo.id == RID_PC) + redecodeCurrentInstruction(); + + return value; + } else { + unsigned int value, injectedval; + + MemoryManager& mm = simulator.getMemoryManager(); + if(!mm.isMapped(data_address)) { + m_log << "DATA_ADDRESS NOT MAPPED" << endl; + return 0; + } + + value = mm.getByte(data_address); + injectedval = value ^ (1 << bitpos); + mm.setByte(data_address, injectedval); + + m_log << "INJECTION at: 0x" << hex << setw(2) << setfill('0') << data_address + << " value: 0x" << setw(2) << setfill('0') << value << " -> 0x" << setw(2) << setfill('0') << injectedval << endl; + + /* If it is the current instruction redecode it */ + guest_address_t pc = simulator.getCPU(0).getInstructionPointer(); + m_log << "IP: 0x" << std::hex << pc << std::endl; + bxInstruction_c *currInstr = simulator.getCurrentInstruction(); + assert(currInstr != NULL && "FATAL ERROR: current instruction was NULL (not expected)!"); + unsigned length_in_bytes = currInstr->ilen(); + + if (currInstr == NULL || (pc <= data_address && data_address <= (pc + currInstr->ilen()))) { + redecodeCurrentInstruction(); + } + + return value; + } +} + + +void handleEvent(CoredTesterProtoMsg_Result& result, CoredTesterProtoMsg_Result_ResultType restype, const std::string &msg) { + cout << msg << endl; + result.set_resulttype(restype); + result.set_details(msg); +} + + +std::string handleMemoryAccessEvent(fail::MemAccessListener* l_mem) { + stringstream sstr; + + sstr << "mem access ("; + switch (l_mem->getTriggerAccessType()) { + case MemAccessEvent::MEM_READ: + sstr << "r"; + break; + case MemAccessEvent::MEM_WRITE: + sstr << "w"; + break; + default: + break; + } + sstr << ") @ 0x" << hex << l_mem->getTriggerAddress(); + sstr << "; ip @ 0x" << hex << l_mem->getTriggerInstructionPointer(); + + return sstr.str(); +} + + +const ElfSymbol& CoredTester::getELFSymbol(const std::string name) { + const ElfSymbol &symbol = m_elf.getSymbol(name); + if (!symbol.isValid()) { + m_log << "Couldn't find symbol: " << name << std::endl; + simulator.terminate(1); + } + + return symbol; +} + + +bool CoredTester::run() { + m_log << "STARTING EXPERIMENT" << endl; + + // seed random number generator + timeval start; + gettimeofday(&start, NULL); + srand(start.tv_usec); + + // get symbols + const ElfSymbol &s_trace_end_marker = getELFSymbol("test_finish"); + BPSingleListener l_trace_end_marker(s_trace_end_marker.getAddress()); + + const ElfSymbol &s_stext_app = getELFSymbol("_stext_application"); + const ElfSymbol &s_etext_app = getELFSymbol("_etext_application"); + + const ElfSymbol &s_panic_handler = getELFSymbol("irq_handler_2"); + + const ElfSymbol &s_fail_trace = getELFSymbol("fail_trace"); + MemAccessListener l_fail_trace(s_fail_trace.getAddress()); + + const ElfSymbol &s_random_source = m_elf.getSymbol("random_source"); + + const ElfSymbol &s_color_assert_port = m_elf.getSymbol("color_assert_port"); + MemAccessListener l_color_assert_port(s_color_assert_port, MemAccessEvent::MEM_WRITE); + + // allowed regions + address_t text_tasks_start = s_stext_app.getAddress(); + address_t text_tasks_end = s_etext_app.getAddress(); + + m_log << "not injecting in application: " << std::hex << text_tasks_start << " -- " << text_tasks_end << std::endl; + + // listeners for traps, code region + //InterruptListener l_interrupt(2); // NMI interrupt + //TrapListener l_trap(2); // NMI trap? + BPSingleListener l_panic(s_panic_handler.getAddress()); + m_log << "PANIC handler @ " << std::hex << s_panic_handler.getAddress() << std::endl; + + unsigned i_timeout = 50 * 1000; + TimerListener l_timeout(i_timeout); // 1s in microseconds + TimerListener l_timeout_hard(1 * 1000 * 1000); // 1s in microseconds + + // initialize LLVM disassembler + m_ltof = LLVMtoFailTranslator::createFromBinary(m_elf.getFilename()); + + // memory manager + MemoryManager& mm = simulator.getMemoryManager(); + + // job client with environment parameters + char* server = getenv("FAIL_SERVER_HOST"); + if(server == NULL) server = (char*) SERVER_COMM_HOSTNAME; + char* cport = getenv("FAIL_SERVER_PORT"); + int port = (cport != NULL) ? atoi(cport) : SERVER_COMM_TCP_PORT; + fail::JobClient jobclient(server, port); + + // execute jobs + unsigned executed_jobs = 0; + while (executed_jobs < 25 || jobclient.getNumberOfUndoneJobs() > 0) { + // get next parameters from jobserver + m_log << "asking jobserver for parameters" << endl; + CoredTesterExperimentData param; + if(!jobclient.getParam(param)){ + m_log << "Dying." << endl; // We were told to die. + simulator.terminate(0); + } + + // extract parameters + unsigned injection_instr = param.msg.fsppilot().injection_instr(); + address_t data_address = param.msg.fsppilot().data_address(); + unsigned data_width = param.msg.fsppilot().data_width(); + + // detect wheter we should inject the PC + bool pc_injection = param.msg.fsppilot().benchmark().find("jump") != std::string::npos; + + // setup experiments + int experiments = pc_injection ? 1 : 8; + + // run experiments + for (int experiment_id = 0; experiment_id < experiments; ++experiment_id) { + CoredTesterProtoMsg_Result *result = 0; + + // restore to the image + m_log << "restoring state" << endl; + simulator.clearListeners(this); + simulator.restore("state"); + m_log << "state restored" << endl; + executed_jobs++; + + // Check for Read Only Memory + if (0x100000 <= data_address && data_address < 0x200000) { + result = param.msg.add_result(); + handleEvent(*result, result->NOINJECTION, "ROM"); + + result->set_experiment_number(0); + result->set_bitoffset(experiment_id); + result->set_original_value(0); + continue; // Produce experiments results + } + + // Extract stack ranges for checkpoint plugin + Checkpoint::range_vector check_ranges; + ElfReader::symbol_iterator it = m_elf.sym_begin(); + for( ; it != m_elf.sym_end(); ++it) { + const std::string name = it->getName(); + + size_t pos = name.rfind("_stack"); + if((pos == std::string::npos) || (pos != (name.size() - 6))) continue; + + const ElfSymbol &s_end = m_elf.getSymbol(name); // *it ? + const std::string ptr_name = "OS_" + name + "ptr"; + stringstream ptrstr; + ptrstr << "_ZN4arch"; + ptrstr << ptr_name.size(); + ptrstr << ptr_name; + ptrstr << "E"; + const ElfSymbol &s_sptr = m_elf.getSymbol(ptrstr.str()); + if(!s_sptr.isValid()) { + m_log << "no stack end symbol for " << name << " (" << ptrstr.str() << "), skipping!" << std::endl; + continue; + } + + m_log << "found task stack symbol: " << name << std::endl; + + Checkpoint::indirectable_address_t start = std::make_pair(s_sptr.getAddress(), true); + Checkpoint::indirectable_address_t end = std::make_pair(s_end.getEnd(), false); + check_ranges.push_back(std::make_pair(start, end)); + } + + // Init Plugins + Checkpoint cpoint(check_ranges, "checkpoint.trace"); + + RandomGenerator* rgen; + if (s_random_source.isValid()) { + const unsigned seed = 12342; + rgen = new RandomGenerator(s_random_source, seed); + simulator.addFlow(rgen); + } + + // fast forward to injection address + m_log << "Trying to inject @ instr #" << dec << injection_instr << endl; + simulator.clearListeners(this); + simulator.addListener(&l_fail_trace); + + BPSingleListener bp; + bp.setWatchInstructionPointer(ANY_ADDR); + // TODO: why does this need a +1? + bp.setCounter(injection_instr+1); + simulator.addListener(&bp); + + fail::BaseListener * listener = simulator.resume(); + bool ok = true; + + while ( ok && (listener == &l_fail_trace) ) { + // m_log << "CP IP 0x" << std::hex << simulator.getCPU(0).getInstructionPointer() << std::endl; + ok = cpoint.check(s_fail_trace, l_fail_trace.getTriggerInstructionPointer()) == Checkpoint::IDENTICAL; + if(ok) listener = simulator.addListenerAndResume(&l_fail_trace); + } + + unsigned experiment_number = cpoint.getCount(); + + if(!ok) { + result = param.msg.add_result(); + handleEvent(*result, result->NOINJECTION, "CHECKPOINT FAIL BEFORE INJECTION?!"); + + result->set_experiment_number((unsigned int) experiment_number); + result->set_bitoffset(experiment_id); + result->set_original_value(0); + + break; + } + if (listener != &bp) { + result = param.msg.add_result(); + handleEvent(*result, result->NOINJECTION, "WTF"); + + result->set_experiment_number((unsigned int) experiment_number); + result->set_bitoffset(experiment_id); + result->set_original_value(0); + + break; + } + + // program counter sanity check + if (param.msg.fsppilot().has_injection_instr_absolute()) { + address_t PC = param.msg.fsppilot().injection_instr_absolute(); + if (simulator.getCPU(0).getInstructionPointer() != PC) { + m_log << "Invalid injection address EIP=0x" + << std::hex << simulator.getCPU(0).getInstructionPointer() + << " != injection_instr_absolute=0x" << PC << std::endl; + simulator.terminate(1); + } + } + + m_log << "Trace " << std::dec << experiment_number << std::endl; + result = param.msg.add_result(); + result->set_experiment_number((unsigned int) experiment_number); + result->set_bitoffset(experiment_id); + result->set_original_value(0); + + // abort if outside targeted region + address_t PC = simulator.getCPU(0).getInstructionPointer(); + //if(PC < min_code || PC > max_code) { + if(PC < text_tasks_end && PC >= text_tasks_start) { + std::stringstream ss; + ss << "0x" << hex << PC; + ss << " inside task text: "; + ss << "0x" << hex << text_tasks_start << " - 0x" << hex << text_tasks_end; + handleEvent(*result, result->NOINJECTION, ss.str()); + continue; // next experiment + } + + // perform injection + if (pc_injection) { + // jump to "data" address + address_t current_PC = simulator.getCPU(0).getInstructionPointer(); + address_t new_PC = param.msg.fsppilot().data_address(); + m_log << "jump from 0x" << hex << current_PC << " to 0x" << new_PC << std::endl; + simulator.getCPU(0).setRegisterContent(simulator.getCPU(0).getRegister(RID_PC), new_PC); + + // set program counter + result->set_bitoffset(0); + result->set_original_value(current_PC); + redecodeCurrentInstruction(); + } else { + // inject random bitflip + // experiment_id == bitpos + result->set_original_value(injectBitFlip(data_address, data_width, experiment_id)); + } + + + // add listeners + simulator.clearListeners(this); + simulator.addListener(&l_panic); + simulator.addListener(&l_timeout); + simulator.addListener(&l_fail_trace); + simulator.addListener(&l_color_assert_port); + simulator.addListener(&l_trace_end_marker); + + // BPSingleListener single_step; + // single_step.setWatchInstructionPointer(ANY_ADDR); + // simulator.addListener(&single_step); + // fail::BaseListener* ll = simulator.resume(); + // while (ll == &single_step || ll == &l_fail_trace) { + // if (ll == &l_fail_trace) { + // Checkpoint::check_result res = cpoint.check(s_fail_trace, l_fail_trace.getTriggerInstructionPointer()); + + // if(res == Checkpoint::DIFFERENT_IP) { + // std::stringstream ss; + // ss << "different IP"; + // ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer(); + // ss << " (checkpoint " << std::dec << cpoint.getCount() << ")"; + // std::cout << ss.str() << endl; + // break; + // } else if(res == Checkpoint::DIFFERENT_VALUE) { + // std::stringstream ss; + // ss << "different value"; + // ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer(); + // ss << " (checkpoint " << std::dec << cpoint.getCount() << ")"; + // std::cout << ss.str() << endl; + // break; + // } else if(res == Checkpoint::DIFFERENT_DIGEST) { + // std::stringstream ss; + // ss << "different digest"; + // ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer(); + // ss << " (checkpoint " << std::dec << cpoint.getCount() << ")"; + // std::cout << ss.str() << endl; + // break; + // } else if(res == Checkpoint::INVALID) { + // std::stringstream ss; + // ss << "invalid checkpoint"; + // ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer(); + // ss << " (checkpoint " << std::dec << cpoint.getCount() << ")"; + // std::cout << ss.str() << endl; + // break; + // } + // } + + // std::stringstream ss; + // ss << "@ IP " << std::hex << simulator.getCPU(0).getInstructionPointer(); + // const ElfSymbol &sym = m_elf.getSymbol(simulator.getCPU(0).getInstructionPointer()); + // ss << " " << sym.getName(); + // std::cout << ss.str() << endl; + // ll = simulator.addListenerAndResume(ll); + // } + + // std::cout << (ll == &l_color_assert_port) << " COLOR ASSERT" << endl; + + // //continue; + // simulator.terminate(0); + + // resume and wait for results + m_log << "Resuming till the crash (time: " << simulator.getTimerTicks() << ")"<< std::endl; + bool reached_check_start = false; + fail::BaseListener* l = simulator.resume(); + + while(l == &l_fail_trace) { + Checkpoint::check_result res = cpoint.check(s_fail_trace, l_fail_trace.getTriggerInstructionPointer()); + if(res == Checkpoint::DIFFERENT_IP) { + std::stringstream ss; + ss << "different IP"; + ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer(); + ss << " (checkpoint " << std::dec << cpoint.getCount() << ")"; + handleEvent(*result, result->SDC_WRONG_RESULT, ss.str()); + break; + } else if(res == Checkpoint::DIFFERENT_VALUE) { + std::stringstream ss; + ss << "different value"; + ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer(); + ss << " (checkpoint " << std::dec << cpoint.getCount() << ")"; + handleEvent(*result, result->SDC_WRONG_RESULT, ss.str()); + break; + } else if(res == Checkpoint::DIFFERENT_DIGEST) { + std::stringstream ss; + ss << "different digest"; + ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer(); + ss << " (checkpoint " << std::dec << cpoint.getCount() << ")"; + handleEvent(*result, result->SDC_WRONG_RESULT, ss.str()); + break; + } else if(res == Checkpoint::INVALID) { + std::stringstream ss; + ss << "invalid checkpoint"; + ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer(); + ss << " (checkpoint " << std::dec << cpoint.getCount() << ")"; + handleEvent(*result, result->SDC_WRONG_RESULT, ss.str()); + break; + } + + // Reset the soft timeout listener + simulator.removeListener(&l_timeout); + simulator.addListener(&l_timeout); + assert(l_timeout.getTimeout() == i_timeout); + + l = simulator.addListenerAndResume(&l_fail_trace); + } + + // End of Injection Phase. Now we have crashed + m_log << "Crashed (time: " << simulator.getTimerTicks() << ")"<< std::endl; + result->set_time_crash(simulator.getTimerTicks()); + + if(l == &l_fail_trace) { + // already reported invalid checkpoint + } else if(l == &l_trace_end_marker) { + // trace ended successfully + std::stringstream ss; + ss << "correct end after " << cpoint.getCount() << " checkpoints"; + handleEvent(*result, result->OK, ss.str()); + } else if (l == &l_panic) { + // error detected + stringstream sstr; + sstr << "PANIC"; + + // CoRedOS specific trap information + const Register *reg_eax = simulator.getCPU(0).getRegister(RID_CAX); + uint32_t trap = simulator.getCPU(0).getRegisterContent(reg_eax); + sstr << " trap " << dec << trap; + + //address_t sp = simulator.getCPU(0).getStackPointer(); + //if(mm.isMapped(sp)) { + // uint32_t ip; + // mm.getBytes(sp, 4, &ip); + // sstr << " @ 0x" << hex << ip; + + const Register *reg_esi = simulator.getCPU(0).getRegister(RID_CSI); + address_t sp = simulator.getCPU(0).getRegisterContent(reg_esi) + 4; + if(mm.isMapped(sp) && mm.isMapped(sp+1) && mm.isMapped(sp+2) && mm.isMapped(sp+3)) { + + uint32_t ip; + mm.getBytes(sp, 4, &ip); + sstr << " from 0x" << hex << ip; + } + + handleEvent(*result, result->OK_DETECTED_ERROR, sstr.str()); + } else if ( l == &l_color_assert_port ) { + // A colored assert has occured + uint32_t color = 0; + mm.getBytes(s_color_assert_port.getAddress(), 4, &color); + std::stringstream ss; + ss << "@ IP" << std::hex << simulator.getCPU(0).getInstructionPointer(); + + if (color == 0xb83829de) { + handleEvent(*result, result->ERR_ASSERT_UNKOWN, ss.str()); + } else if (color == 0xf4d9f7ca) { + handleEvent(*result, result->ERR_ASSERT_CFG_REGION, ss.str()); + } else if (color == 0x9451210d) { + handleEvent(*result, result->ERR_ASSERT_SYSTEM_STATE, ss.str()); + } else { + handleEvent(*result, result->ERR_ASSERT_SPURIOUS, ss.str()); + } + } else if ( l == &l_timeout || l == &l_timeout_hard) { + // timeout, probably infinite loop + handleEvent(*result, result->ERR_TIMEOUT, ""); + } else { + // what happened? + handleEvent(*result, result->UNKNOWN, "WTF"); + } + + // For RandomJump do only one experiment not 8 + if (pc_injection) break; + } + + // send results + jobclient.sendResult(param); + } + + // explicitly terminate, or the simulator will continue to run + simulator.terminate(); +} + diff --git a/src/experiments/cored-tester/experiment.hpp b/src/experiments/cored-tester/experiment.hpp new file mode 100644 index 00000000..a173089c --- /dev/null +++ b/src/experiments/cored-tester/experiment.hpp @@ -0,0 +1,33 @@ +#ifndef __CORED_TESTER_EXPERIMENT_HPP__ +#define __CORED_TESTER_EXPERIMENT_HPP__ + + +#include "sal/SALInst.hpp" +#include "efw/ExperimentFlow.hpp" +#include "efw/JobClient.hpp" +#include "util/Logger.hpp" +#include "util/ElfReader.hpp" +#include +#include +#include "util/llvmdisassembler/LLVMtoFailTranslator.hpp" + +class CoredTester : public fail::ExperimentFlow { +public: + +private: + fail::Logger m_log; + fail::MemoryManager& m_mm; + fail::ElfReader m_elf; + fail::LLVMtoFailTranslator* m_ltof; + + unsigned injectBitFlip(fail::address_t data_address, unsigned data_width, unsigned bitpos); + void redecodeCurrentInstruction(); + const fail::ElfSymbol& getELFSymbol(const std::string name); + +public: + CoredTester() : m_log("CoredTester", false), m_mm(fail::simulator.getMemoryManager()) {} + + bool run(); +}; + +#endif diff --git a/src/experiments/cored-tester/main.cc b/src/experiments/cored-tester/main.cc new file mode 100644 index 00000000..6bf0c12f --- /dev/null +++ b/src/experiments/cored-tester/main.cc @@ -0,0 +1,20 @@ +#include +#include + +#include "cpn/CampaignManager.hpp" +#include "util/CommandLine.hpp" +#include "campaign.hpp" + +int main(int argc, char **argv) +{ + fail::CommandLine &cmd = fail::CommandLine::Inst(); + for (int i = 1; i < argc; ++i) + cmd.add_args(argv[i]); + + CoredTesterCampaign c; + if (fail::campaignmanager.runCampaign(&c)) { + return 0; + } else { + return 1; + } +} diff --git a/src/experiments/cored-tracing/CMakeLists.txt b/src/experiments/cored-tracing/CMakeLists.txt new file mode 100644 index 00000000..45f10904 --- /dev/null +++ b/src/experiments/cored-tracing/CMakeLists.txt @@ -0,0 +1,18 @@ +set(EXPERIMENT_NAME cored-tracing) +set(EXPERIMENT_TYPE CoRedTracing) +configure_file(../instantiate-experiment.ah.in + ${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY +) + +set(MY_CAMPAIGN_SRCS + experiment.hpp + experiment.cc +) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +## Build library +add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS}) + +add_dependencies(fail-${EXPERIMENT_NAME} fail-comm) +target_link_libraries(fail-${EXPERIMENT_NAME} fail-tracing fail-randomgenerator fail-checkpoint fail-comm) \ No newline at end of file diff --git a/src/experiments/cored-tracing/experiment.cc b/src/experiments/cored-tracing/experiment.cc new file mode 100644 index 00000000..e7e2aef7 --- /dev/null +++ b/src/experiments/cored-tracing/experiment.cc @@ -0,0 +1,292 @@ +#include +#include + +#include "sal/SALInst.hpp" +#include "sal/Register.hpp" +#include "sal/Listener.hpp" +#include "experiment.hpp" +#include "util/CommandLine.hpp" +#include "util/gzstream/gzstream.h" + +// required (enabled) plugins +#include "../plugins/tracing/TracingPlugin.hpp" +#include "../plugins/randomgenerator/RandomGenerator.hpp" +#include "../plugins/checkpoint/Checkpoint.hpp" + +using namespace std; +using namespace fail; + +void CoRedTracing::parseOptions() { + CommandLine &cmd = CommandLine::Inst(); + cmd.addOption("", "", Arg::None, "USAGE: fail-client -Wf,[option] -Wf,[option] ... \n\n"); + CommandLine::option_handle HELP = cmd.addOption("h", "help", Arg::None, "-h,--help \tPrint usage and exit"); + + + CommandLine::option_handle ELF_FILE = cmd.addOption("", "elf-file", Arg::Required, + "--elf-file \tELF Binary File (default: $FAIL_ELF_PATH)"); + CommandLine::option_handle START_SYMBOL = cmd.addOption("s", "start-symbol", Arg::Required, + "-s,--start-symbol \tELF symbol to start tracing (default: main)"); + CommandLine::option_handle STOP_SYMBOL = cmd.addOption("e", "end-symbol", Arg::Required, + "-e,--end-symbol \tELF symbol to end tracing"); + CommandLine::option_handle SAVE_SYMBOL = cmd.addOption("S", "save-symbol", Arg::Required, + "-S,--save-symbol \tELF symbol to save the state of the machine (default: main)\n"); + CommandLine::option_handle STATE_FILE = cmd.addOption("f", "state-file", Arg::Required, + "-f,--state-file \tFile/dir to save the state to (default: state)"); + CommandLine::option_handle TRACE_FILE = cmd.addOption("t", "trace-file", Arg::Required, + "-t,--trace-file \tFile to save the execution trace to (default: trace.pb)\n"); + + CommandLine::option_handle FULL_TRACE = cmd.addOption("", "full-trace", Arg::None, "--full-trace \tDo a full trace (more data, default: off)"); + CommandLine::option_handle MEM_SYMBOL = cmd.addOption("m", "memory-symbol", Arg::Required, + "-m,--memory-symbol \tELF symbol(s) to trace accesses (default: all mem read/writes are traced)"); + CommandLine::option_handle MEM_REGION = cmd.addOption("M", "memory-region", Arg::Required, + "-M,--memory-region \trestrict memory region which is traced" + " (Possible formats: 0x
, 0x
:0x
, 0x
:)"); + + if (!cmd.parse()) { + cerr << "Error parsing arguments." << endl; + exit(-1); + } + + if (cmd[HELP]) { + cmd.printUsage(); + exit(0); + } + + if (cmd[ELF_FILE].count() > 0) + elf_file = cmd[ELF_FILE].first()->arg; + else { + char * elfpath = getenv("FAIL_ELF_PATH"); + if (elfpath == NULL) { + m_log << "FAIL_ELF_PATH not set :( (alternative: --elf-file) " << std::endl; + exit(-1); + } + + elf_file = elfpath; + } + m_elf = new ElfReader(elf_file.c_str()); + + if (cmd[START_SYMBOL].count() > 0) + start_symbol = cmd[START_SYMBOL].first()->arg; + else + start_symbol = "main"; + + if (cmd[STOP_SYMBOL].count() > 0) + stop_symbol = std::string(cmd[STOP_SYMBOL].first()->arg); + else { + m_log << "You have to give an end symbol (-e,--end-symbol)!" << std::endl; + exit(EXIT_FAILURE); + } + + if (cmd[SAVE_SYMBOL].count() > 0) + save_symbol = std::string(cmd[SAVE_SYMBOL].first()->arg); + else + save_symbol = "main"; + + if (cmd[STATE_FILE].count() > 0) + state_file = std::string(cmd[STATE_FILE].first()->arg); + else + state_file = "state"; + + if (cmd[TRACE_FILE].count() > 0) + trace_file = std::string(cmd[TRACE_FILE].first()->arg); + else + trace_file = "trace.pb"; + + use_memory_map = false; + + if (cmd[MEM_SYMBOL].count() > 0) { + use_memory_map = true; + option::Option *opt = cmd[MEM_SYMBOL].first(); + + while (opt != 0) { + const ElfSymbol &symbol = m_elf->getSymbol(opt->arg); + assert(symbol.isValid()); + + m_log << "Adding '" << opt->arg << "' == 0x" << std::hex << symbol.getAddress() + << "+" << std::dec << symbol.getSize() << " to trace map" << std::endl; + traced_memory_map.add(symbol.getAddress(), symbol.getSize()); + + opt = opt->next(); + } + } + + if (cmd[MEM_REGION].count() > 0) { + use_memory_map = true; + option::Option *opt = cmd[MEM_REGION].first(); + + while (opt != 0) { + char *endptr; + guest_address_t begin = strtol(opt->arg, &endptr, 16); + guest_address_t size; + if (endptr == opt->arg) { + m_log << "Couldn't parse " << opt->arg << std::endl; + exit(-1); + } + + char delim = *endptr; + if (delim == 0) { + size = 1; + } else if (delim == ':') { + char *p = endptr +1; + size = strtol(p, &endptr, 16) - begin; + if (p == endptr || *endptr != 0) { + m_log << "Couldn't parse " << opt->arg << std::endl; + exit(-1); + } + } else if (delim == '+') { + char *p = endptr +1; + size = strtol(p, &endptr, 10); + if (p == endptr || *endptr != 0) { + m_log << "Couldn't parse " << opt->arg << std::endl; + exit(-1); + } + } else { + m_log << "Couldn't parse " << opt->arg << std::endl; + exit(-1); + } + + traced_memory_map.add(begin, size); + + m_log << "Adding " << opt->arg << " 0x" << std::hex << begin + << "+" << std::dec << size << " to trace map" << std::endl; + + opt = opt->next(); + } + } + + if (cmd[FULL_TRACE]) { + this->full_trace = true; + } + + assert(m_elf->getSymbol(start_symbol).isValid()); + assert(m_elf->getSymbol(stop_symbol).isValid()); + assert(m_elf->getSymbol(save_symbol).isValid()); + + m_log << "start symbol: " << start_symbol << " 0x" << std::hex << m_elf->getSymbol(start_symbol).getAddress() << std::endl; + m_log << "save symbol: " << save_symbol << " 0x" << std::hex << m_elf->getSymbol(save_symbol).getAddress() << std::endl; + m_log << "stop symbol: " << stop_symbol << " 0x" << std::hex << m_elf->getSymbol(stop_symbol).getAddress() << std::endl; + + m_log << "state file: " << state_file << std::endl; + m_log << "trace file: " << trace_file << std::endl; + m_log << "full-trace: " << this->full_trace << std::endl; + + +} + +bool CoRedTracing::run() +{ + parseOptions(); + + BPSingleListener l_start_symbol(m_elf->getSymbol(start_symbol).getAddress()); + BPSingleListener l_save_symbol (m_elf->getSymbol(save_symbol).getAddress()); + BPSingleListener l_stop_symbol (m_elf->getSymbol(stop_symbol).getAddress()); + + + //////////////////////////////////////////////////////////////// + // STEP 1: run until interesting function starts, start the tracing + simulator.addListenerAndResume(&l_start_symbol); + m_log << start_symbol << " reached, start tracing" << std::endl; + + // restrict memory access logging to injection target + TracingPlugin tp; + tp.setFullTrace(this->full_trace); + + if (use_memory_map) { + m_log << "Use restricted memory map for tracing" << std::endl; + tp.restrictMemoryAddresses(&traced_memory_map); + } + + ogzstream of(trace_file.c_str()); + if (of.bad()) { + m_log << "Couldn't open trace file: " << trace_file << std::endl; + exit(-1); + } + tp.setTraceFile(&of); + + // this must be done *after* configuring the plugin: + simulator.addFlow(&tp); + + //////////////////////////////////////////////////////////////// + // STEP 2: continue to the save point, and save state + if (start_symbol != save_symbol) { + simulator.addListenerAndResume(&l_save_symbol); + } + m_log << start_symbol << " reached, save state" << std::endl; + simulator.save(state_file); + + + //////////////////////////////////////////////////////////////// + // Step 3: add plugins + // symbol to trigger checkpoints + const ElfSymbol &s_fail_trace = m_elf->getSymbol("fail_trace"); + + Checkpoint *cpoint; + if(s_fail_trace.isValid()) { + Checkpoint::range_vector check_ranges; + + ElfReader::symbol_iterator it = m_elf->sym_begin(); + for( ; it != m_elf->sym_end(); ++it) { + const std::string name = it->getName(); + + size_t pos = name.rfind("_stack"); + if((pos == std::string::npos) || (pos != (name.size() - 6))) continue; + + const ElfSymbol &s_end = m_elf->getSymbol(name); // *it ? + const std::string ptr_name = "OS_" + name + "ptr"; + stringstream ptrstr; + ptrstr << "_ZN4arch"; + ptrstr << ptr_name.size(); + ptrstr << ptr_name; + ptrstr << "E"; + const ElfSymbol &s_sptr = m_elf->getSymbol(ptrstr.str()); + if(!s_sptr.isValid()) { + m_log << "no stack end symbol for " << name << " (" << ptrstr.str() << "), skipping!" << std::endl; + continue; + } + + m_log << "found task stack symbol: " << name << std::endl; + + Checkpoint::indirectable_address_t start = std::make_pair(s_sptr.getAddress(), true); + Checkpoint::indirectable_address_t end = std::make_pair(s_end.getEnd(), false); + check_ranges.push_back(std::make_pair(start, end)); + } + + cpoint = new Checkpoint(s_fail_trace, check_ranges, "checkpoint.trace"); + simulator.addFlow(cpoint); + } else { + m_log << "Checkpoint plugin NOT added to simulation" << std::endl; + } + + // symbol to read random values from + const ElfSymbol &s_random_source = m_elf->getSymbol("random_source"); + RandomGenerator *rgen; + if (s_random_source.isValid()) { + const unsigned seed = 12342; + rgen = new RandomGenerator(s_random_source, seed); + simulator.addFlow(rgen); + } else { + m_log << "Randomgenerator plugin NOT added to simulation" << std::endl; + } + + + //////////////////////////////////////////////////////////////// + // Step 4: Continue to the stop point + simulator.addListener(&l_stop_symbol); + simulator.resume(); + + //////////////////////////////////////////////////////////////// + // Step 5: tear down the tracing + + simulator.removeFlow(&tp); + // serialize trace to file + if (of.fail()) { + m_log << "failed to write " << trace_file << std::endl; + return false; + } + of.close(); + + simulator.clearListeners(); + simulator.terminate(); + + return true; +} diff --git a/src/experiments/cored-tracing/experiment.hpp b/src/experiments/cored-tracing/experiment.hpp new file mode 100644 index 00000000..5a076000 --- /dev/null +++ b/src/experiments/cored-tracing/experiment.hpp @@ -0,0 +1,37 @@ +#ifndef __CORED_TRACING_HPP__ +#define __CORED_TRACING_HPP__ + +#include "efw/ExperimentFlow.hpp" +#include "util/Logger.hpp" +#include "util/ElfReader.hpp" +#include "util/MemoryMap.hpp" +#include +#include + + + +class CoRedTracing : public fail::ExperimentFlow { + std::string start_symbol; + std::string stop_symbol; + std::string save_symbol; + + std::string state_file; + std::string trace_file; + std::string elf_file; + + bool use_memory_map; + fail::MemoryMap traced_memory_map; + + bool full_trace; + + fail::Logger m_log; + fail::ElfReader *m_elf; + +public: + void parseOptions(); + bool run(); + + CoRedTracing() : full_trace(false), m_log("CoRedTracing", false) {}; +}; + +#endif // __CORED_TRACING_HPP__ \ No newline at end of file diff --git a/src/experiments/ezs-logger/CMakeLists.txt b/src/experiments/ezs-logger/CMakeLists.txt index 9dbdcb77..e283756d 100644 --- a/src/experiments/ezs-logger/CMakeLists.txt +++ b/src/experiments/ezs-logger/CMakeLists.txt @@ -16,6 +16,5 @@ set(MY_CAMPAIGN_SRCS ## Build library add_library(fail-${EXPERIMENT_NAME} ${MY_CAMPAIGN_SRCS}) add_dependencies(fail-${EXPERIMENT_NAME} fail-comm) -target_link_libraries(fail-${EXPERIMENT_NAME} fail-comm) -target_link_libraries(fail-${EXPERIMENT_NAME}) +target_link_libraries(fail-${EXPERIMENT_NAME} fail-comm fail-util) diff --git a/src/experiments/fiascoFail/CMakeLists.txt b/src/experiments/fiascoFail/CMakeLists.txt new file mode 100644 index 00000000..b57c1039 --- /dev/null +++ b/src/experiments/fiascoFail/CMakeLists.txt @@ -0,0 +1,42 @@ +set(EXPERIMENT_NAME fiascoFail) +set(EXPERIMENT_TYPE FiascoFailExperiment) +configure_file(../instantiate-experiment-indirect.ah.in + ${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY +) + +## Setup desired protobuf descriptions HERE ## +set(MY_PROTOS + fiascofail.proto +) + +set(MY_CAMPAIGN_SRCS + instantiateExperiment.cc + experimentInfo.hpp + experiment.hpp + experiment.cc + campaign.hpp + campaign.cc +) + +#### PROTOBUFS #### +find_package(Protobuf REQUIRED) +include_directories(${PROTOBUF_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +find_package(MySQL REQUIRED) +include_directories(${MYSQL_INCLUDE_DIR}) + +set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/../../core/comm) +PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS}) + +## Build library +add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS}) +add_dependencies(fail-${EXPERIMENT_NAME} fail-comm) +#target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY} ${MYSQL_LIBRARIES}) +target_link_libraries(fail-${EXPERIMENT_NAME} fail) +target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY} ${MYSQL_LIBRARIES}) + +## This is the example's campaign server distributing experiment parameters +add_executable(${EXPERIMENT_NAME}-server main.cc) +target_link_libraries(${EXPERIMENT_NAME}-server fail-${EXPERIMENT_NAME} fail ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} ${MYSQL_LIBRARIES}) +install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin) diff --git a/src/experiments/fiascoFail/campaign.cc b/src/experiments/fiascoFail/campaign.cc new file mode 100644 index 00000000..418e35d3 --- /dev/null +++ b/src/experiments/fiascoFail/campaign.cc @@ -0,0 +1,9 @@ +#include "campaign.hpp" +#include "cpn/CampaignManager.hpp" + +void FiascoFailCampaign::cb_send_pilot(DatabaseCampaignMessage pilot) +{ + FiascoFailExperimentData *data = new FiascoFailExperimentData; + data->msg.mutable_fsppilot()->CopyFrom(pilot); + fail::campaignmanager.addParam(data); +} diff --git a/src/experiments/fiascoFail/campaign.hpp b/src/experiments/fiascoFail/campaign.hpp new file mode 100644 index 00000000..c0ad2be5 --- /dev/null +++ b/src/experiments/fiascoFail/campaign.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include "cpn/DatabaseCampaign.hpp" +#include "comm/ExperimentData.hpp" +#include "experimentInfo.hpp" +#include "fiascofail.pb.h" +//#include + +class FiascoFailExperimentData : public fail::ExperimentData +{ +public: + FiascofailProtoMsg msg; + FiascoFailExperimentData() : fail::ExperimentData(&msg) {} +}; + +class FiascoFailCampaign : public fail::DatabaseCampaign +{ + virtual const google::protobuf::Descriptor * cb_result_message() + { + return google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("FiascofailProtoMsg"); + } + virtual void cb_send_pilot(DatabaseCampaignMessage pilot); + + virtual int expected_number_of_results(std::string variant, std::string benchmark) + { +#if FIASCO_FAULTMODEL_BURST + return 1; +#else + return 8; +#endif + } +}; diff --git a/src/experiments/fiascoFail/experiment.cc b/src/experiments/fiascoFail/experiment.cc new file mode 100644 index 00000000..b9cac1c4 --- /dev/null +++ b/src/experiments/fiascoFail/experiment.cc @@ -0,0 +1,575 @@ +#include +#include +#include + +#include +#include + + +#include "experiment.hpp" +#include "experimentInfo.hpp" +#include "campaign.hpp" + +#include "sal/SALConfig.hpp" +#include "sal/SALInst.hpp" +#include "sal/Memory.hpp" +#include "sal/Listener.hpp" +#include +#include "util/WallclockTimer.hpp" +#include "config/FailConfig.hpp" +#include "util/CommandLine.hpp" + +using namespace std; +using namespace fail; + +#define LOCAL 0 + +void FiascoFailExperiment::parseOptions() +{ + CommandLine &cmd = CommandLine::Inst(); + cmd.addOption("", "", Arg::None, "USAGE: fail-client -Wf,[option] ... \n\n"); + CommandLine::option_handle GOLDEN = cmd.addOption("g", "golden", Arg::None, "-g,--golden \tExecute golden-run experiment?"); + CommandLine::option_handle HELP = cmd.addOption("h", "help", Arg::None, "-h,--help \tPrint usage and exit"); + CommandLine::option_handle END_ADDRESS = cmd.addOption("E", "end", Arg::Required, "-E,--end \tEnd-Address of experiment"); + CommandLine::option_handle TOTAL_TIMER = cmd.addOption("T", "time", Arg::Required, "-T,--time \tTotal timer ticks of the golden run experiment from restoring point"); + CommandLine::option_handle TOTAL_INSTR = cmd.addOption("t", "total", Arg::Required, "-t,--total \tTotal instructions of the golden run experiment from restoring point"); + CommandLine::option_handle ECC_PANIC_FUNC = cmd.addOption("p", "panic", Arg::Required, "-p--panic \tAddress of the ecc_panic function"); + CommandLine::option_handle ERROR_CORRECTED_ADDR = cmd.addOption("c", "corrected", Arg::Required, "-c--corected \tAddress of the errors_corrected variable"); + + if(!cmd.parse()) + { + cerr << "Error parsing arguments." << endl; + exit(-1); + } + + if(cmd[HELP]) + { + cmd.printUsage(); + exit(0); + } + + if(cmd[GOLDEN].count() > 0) + { + _golden_run = true; + } + else + { + _golden_run = false; + } + + // Check if end-address is given + if(cmd[END_ADDRESS].count() > 0) + { + endAddress = strtoul(cmd[END_ADDRESS].first()->arg, NULL, 16); + } + else + { + m_log << "You have to give an end address!" << endl; + exit(-1); + } + + // Check if number of golden run timer ticks is given + if(cmd[TOTAL_TIMER].count() > 0) + { + golden_run_timer_ticks = strtoull(cmd[TOTAL_TIMER].first()->arg, NULL, 10); + } + else if(!_golden_run) + { + m_log << "You hava to give the number of total timer ticks of the golden run" << endl; + exit(-1); + } + + // Check if number of total instructions is given + if(cmd[TOTAL_INSTR].count() > 0) + { + golden_run_instructions = strtoul(cmd[TOTAL_INSTR].first()->arg, NULL, 10); + } + else if(!_golden_run) + { + m_log << "You have to give the number of total instructions of the golden run" << endl; + exit(-1); + } + + // Check if ecc_panic function address is given + if(cmd[ECC_PANIC_FUNC].count() > 0) + { + ecc_panic_address = strtoul(cmd[ECC_PANIC_FUNC].first()->arg, NULL, 16); + } + else if(!_golden_run) + { + m_log << "You have to give the address of the ecc_panic function" << endl; + exit(-1); + } + + // Check if errors_corrected variable address is given + if(cmd[ERROR_CORRECTED_ADDR].count() > 0) + { + addr_errors_corrected = strtoul(cmd[ERROR_CORRECTED_ADDR].first()->arg, NULL, 16); + } + else if(!_golden_run) + { + m_log << "You have to give the address of the errors_corrected variable" << endl; + exit(-1); + } +} + +void FiascoFailExperiment::readGoldenRun(string& target) +{ + ifstream golden_run_file("golden.out"); + + if(!golden_run_file.good()) + { + m_log << "Could not open file golden.out" << endl; + simulator.terminate(); + exit(-1); + } + + target.assign((istreambuf_iterator(golden_run_file)), istreambuf_iterator()); + golden_run_file.close(); +} + +/* + * Function to record every output on the VGA-Output-Port in m_CurrentOutput + * Runs until any breakpoint different from the VGA-Port is reached + */ +BaseListener* FiascoFailExperiment::waitIOOrOther(bool clear_output) +{ + IOPortListener ev_ioport(0x3F8, true); // VGA-Output-Port: 0x3F8 + BaseListener* ev = NULL; + if(clear_output) + { + m_CurrentOutput.clear(); + } + while(true) + { + simulator.addListener(&ev_ioport); // Add VGA-Port to the current listeners... + ev = simulator.resume(); // ...and continue + if(ev == &ev_ioport) // If current breakpoint == VGA-Port... + { + m_CurrentOutput += ev_ioport.getData(); // ... add output to m_CurrentOutput + } + else // Else: Breakpoint different from VGA-Port reached, break + { + break; + } + } + return ev; // Return the current breakpoint +} + +bool FiascoFailExperiment::run() +{ + m_log << "startup" << endl; + parseOptions(); + + if(_golden_run) + { + // Do the golden-run experiment + goldenRun(); + } + else + { + // Do the actual fault injection + faultInjection(); + } + + // Experiment finished + simulator.terminate(); + return true; +} + + +bool FiascoFailExperiment::faultInjection() +{ + string golden_run; + readGoldenRun(golden_run); // Read the output string from the golden run + + BPSingleListener bp; + int experiments = 0; +#if !LOCAL + for(experiments = 0; experiments < 500 || (m_jc.getNumberOfUndoneJobs() != 0); ) + { +#endif + m_log << "asking job server for experiment parameters" << endl; + FiascoFailExperimentData param; +#if !LOCAL + if(!m_jc.getParam(param)) + { + m_log << "Dying." << endl; + simulator.terminate(1); + } +#else + // XXX debug + param.msg.mutable_fsppilot()->set_injection_instr(96); + param.msg.mutable_fsppilot()->set_injection_instr_absolute(4026670033); + param.msg.mutable_fsppilot()->set_data_address(4237508604); + param.msg.mutable_fsppilot()->set_data_width(1); + param.msg.mutable_fsppilot()->set_variant("baseline"); + param.msg.mutable_fsppilot()->set_benchmark("shared_ds"); +#endif + + if(param.msg.fsppilot().data_width() != 1) + { + m_log << "cannot deal with data_width = " << param.msg.fsppilot().data_width() << endl; + simulator.terminate(1); + } + + // Get the experiment data from the Job-Server + int id = param.getWorkloadID(); + m_variant = param.msg.fsppilot().variant(); + m_benchmark = param.msg.fsppilot().benchmark(); + unsigned instr_offset = param.msg.fsppilot().injection_instr(); // Offset to the IP where the fault injection has to be done + guest_address_t mem_addr = param.msg.fsppilot().data_address(); // Memory address wehre the fault injection has to be done + + // for each job with the SINGLEBITFLIP fault model we're actually doing *8* + // experiments (one for each bit) + for(int bit_offset = 0; bit_offset < 8; ++bit_offset) + { + ++experiments; + + WallclockTimer timer; // Timer to log the actual time of the experiment + timer.startTimer(); + + FiascofailProtoMsg_Result *result = param.msg.add_result(); // Protobuf object for the result + result->set_bit_offset(bit_offset); // Set the bit offset (1 if FAULTMODEL_BURST is active) + m_log << dec << "job " << id << " @bit: " << bit_offset << " " << m_variant << "/" << m_benchmark + << " instr-offset " << hex << instr_offset + << " mem " << hex << mem_addr << "+" << dec << bit_offset << endl; + + m_log << "restoring state" << endl; + simulator.restore("state"); // Restore the state (Entry point is the first IP of the main-function from the application) + m_log << "restore @ip " << hex << simulator.getCPU(0).getInstructionPointer() << " finished!" << endl; + + // convert to microseconds (simulator.getTimerTicksPerSecond() only + // works reliably when simulation has begun) + unsigned goldenrun_runtime = (unsigned)(golden_run_timer_ticks * 1000000.0 / simulator.getTimerTicksPerSecond()); + unsigned timeout_runtime = goldenrun_runtime + 1000000/18.2; // + 1 timer tick + + BPSingleListener func_finish(endAddress); // Add the last IP of the main-function to the listeners (end of experiment) + simulator.addListener(&func_finish); + + + simtime_t time_start = simulator.getTimerTicks(); // measure elapsed time + + if(instr_offset > 0) + { + bp.setWatchInstructionPointer(ANY_ADDR); // Create new Breakpoint... + bp.setCounter(instr_offset + 1); // ...to break when the IP for the fault injection is reached... + simulator.addListener(&bp); // ...and add it to the actual listeners + + BaseListener *go = waitIOOrOther(true); // Resume simulation and log VGA-Output + if(go == &func_finish) // If func_finish has triggerd the break, something went wong... + { + stringstream ss; + ss << "experiment reached finish() before FI"; + m_log << ss.str() << endl; + result->set_resulttype(result->UNKNOWN); + result->set_details(ss.str()); + result->set_runtime(timer); + m_jc.sendResult(param); + + continue; // ... so continue with next experiment + } + else if(go != &bp) // Else if the breakpoint for the fault injection is not reached, something went wrong... + { + stringstream ss; + ss << "experiment didn't reach bp"; + m_log << ss.str() << endl; + result->set_resulttype(result->UNKNOWN); + result->set_details(ss.str()); + result->set_latest_ip(simulator.getCPU(0).getInstructionPointer()); + result->set_runtime(timer); +#if !LOCAL + m_jc.sendResult(param); +#endif + +#if FIASCO_FAULTMODEL_BURST + bit_offset = 8; +#endif + + continue; // ... so continue with the next experiment + } + } + + // sanity check (check if actual IP equals the trced IP) + uint32_t injection_ip = simulator.getCPU(0).getInstructionPointer(); + if(param.msg.fsppilot().has_injection_instr_absolute() && + injection_ip != param.msg.fsppilot().injection_instr_absolute()) + { + stringstream ss; + ss << "SANITY CHECK FAILED: " << hex << injection_ip + << " != " << hex << param.msg.fsppilot().injection_instr_absolute(); + m_log << ss.str() << endl; + result->set_resulttype(result->UNKNOWN); + result->set_latest_ip(injection_ip); + result->set_details(ss.str()); + result->set_runtime(timer); +#if !LOCAL + m_jc.sendResult(param); +#endif + +#if FIASCO_FAULTMODEL_BURST + bit_offset = 8; +#endif + + continue; // If sanity check fails: next experiment + } + if(param.msg.fsppilot().has_injection_instr_absolute()) + { + m_log << "Absolute IP sanity check OK" << endl; + } + else + { + m_log << "Absolute IP sanity check skipped (job parameters insufficient)" << endl; + } + + + + // --- fault injection --- + MemoryManager& mm = simulator.getMemoryManager(); // Get the memory manager from Bochs + host_address_t addr = reinterpret_cast(&mm)->guestToHost(mem_addr); // check if the fault-address is mapped (guestToHost returns ADDR_INV if not) + if (addr == (host_address_t)ADDR_INV) + { + result->set_resulttype(result->UNKNOWN); + result->set_latest_ip(injection_ip); + result->set_runtime(timer); + stringstream ss; + ss << "INVALID DATA-ADDRESS " << hex << mem_addr << " @ ip " << injection_ip; + result->set_details(ss.str()); + m_jc.sendResult(param); + + continue; // Faul-address is not mapped so continue with the next experiment + } + byte_t data = mm.getByte(mem_addr); // Get tha actual value stored in the fault-addres + byte_t newdata; +#if FIASCO_FAULTMODEL_BURST + newdata = data ^ 0xff; // If Faultmode burst is active: Flip every 8 bits... + bit_offset = 8; // ...and continue with the next byte +#else + newdata = data ^ (1 << bit_offset); // Else: Flip the bit according to the actual bit-offset and continue with next bit +#endif + mm.setByte(mem_addr, newdata); // Store the new data in the actual faut-address + m_log << "fault injected @ ip " << injection_ip + << " 0x" << hex << ((int)data) << " -> 0x" << ((int)newdata) << endl; + + + + + // --- aftermath --- + // catch traps as "extraordinary" ending + TrapListener ev_trap(ANY_TRAP); + simulator.addListener(&ev_trap); + + // jump outside text segment (TODO: text segments for multiple elf-files + paging) + /* + BPRangeListener ev_below_text(ANY_ADDR, addr_text_start -1); // TODO + BPRangeListener ev_beyond_text(addr_text_end + 1, ANY_ADDR); // TODO + simulator.addListener(&ev_below_text); + simulator.addListener(&ev_beyond_text); + */ + + // timeout (e.g., stuck in a HLT instruction) + TimerListener ev_timeout(timeout_runtime); + simulator.addListener(&ev_timeout); + + // grant generous (10x) more instructions before aborting to avoid false positives + BPSingleListener ev_dyninstructions(ANY_ADDR); + // FIXME overflow possible + ev_dyninstructions.setCounter(golden_run_instructions * 10); + simulator.addListener(&ev_dyninstructions); + + // incomplete (e.g. cursors blinks so nothing happens any more or a longjump occurs) + BPSingleListener ev_blink(FIASCO_BREAK_BLINK); + simulator.addListener(&ev_blink); + BPSingleListener ev_longjmp(FIASCO_BREAK_LONGJMP); + simulator.addListener(&ev_longjmp); + + // function called by ecc apsects, when an uncorrectable error is detected + BPSingleListener func_ecc_panic(ecc_panic_address); + if(ecc_panic_address != ADDR_INV) + { + simulator.addListener(&func_ecc_panic); + } + + // wait until experiment-terminating event occurs + bool finished = false; + BaseListener *go; + while(!finished) + { + go = waitIOOrOther(false); // resume experiment until func_finish or any other BP is reached and log the output + if(go == &ev_trap) // if a trap is triggered, check which one + { + // Traps that occour in golden run are considered as deliberate + if(ev_trap.getTriggerNumber() == 14) // Page fault trap + { + finished = false; + simulator.addListener(&ev_trap); // Trap considered as deliberate so continue + } + else + { + finished = true; // Trap not considered as deliberate so break + } + } + else + { + finished = true; // Experiment reached BP so break + } + } + + // record latest IP regardless of result + // TODO: consider recording latest IP within text segment, too, which + // would make this usable for the jump-outside case + result->set_latest_ip(simulator.getCPU(0).getInstructionPointer()); + + // record error_corrected regardless of result + if (addr_errors_corrected != ADDR_INV) + { + int32_t error_corrected = mm.getByte(addr_errors_corrected); + result->set_error_corrected(error_corrected ? result->TRUE : result->FALSE); + } + else + { + // not setting this yields NULL in the DB + //result->set_error_corrected(0); + } + + result->set_sim_runtime_factor( + (simulator.getTimerTicks() - time_start) / (double) golden_run_timer_ticks); // Get the runtime factor compared to the golden run + + + // Look for result + if(go == &func_finish) // If BP == func_finished... + { + if(strcmp(m_CurrentOutput.c_str(), golden_run.c_str()) == 0) // ...and output is equal to the golden run: Result: OK + { + m_log << "experiment finished ordinarily" << endl; + result->set_resulttype(result->OK); + } + else // ...or output is different from the golden run: Result: SDC + { + m_log << "experiment finished, but output incorrect" << endl; + result->set_resulttype(result->SDC); + result->set_details(m_CurrentOutput.c_str()); + } + } + else if(go == &ev_trap) // If BP == trap: Result: Trap + { + m_log << dec << "Result TRAP #" << ev_trap.getTriggerNumber() << endl; + result->set_resulttype(result->TRAP); + + stringstream ss; + ss << ev_trap.getTriggerNumber(); + result->set_details(ss.str()); + } + else if(go == &func_ecc_panic) // If BP == ecc_panic_function: Result: Detected (but not corrected) + { + m_log << "ECC Panic: uncorrectable error" << endl; + result->set_resulttype(result->DETECTED); // DETECTED <=> ECC_PANIC <=> reboot + } + // TODO (see above) + /*else if(go == &ev_below_text || go == &ev_beyond_text) + { + m_log << "Result Trap #" << ev_trap.getTriggerNumber() << endl; + result->set_jump_outside(result->TRUE); + result->set_resulttype(result->TRAP); + + stringstream ss; + ss << ev_trap.getTriggerNumber(); + result->set_details(ss.str()); + }*/ + else if(go == &ev_timeout || go == &ev_dyninstructions || go == &ev_blink || go == &ev_longjmp) // Result: Timeout if any of these BP occur + { + m_log << "Result TIMEOUT" << endl; + result->set_resulttype(result->TIMEOUT); + if(go == &ev_dyninstructions) + { + result->set_details("i"); + } + else if(go == &ev_blink) + { + result->set_details("b"); + } + else if(go == &ev_longjmp) + { + result->set_details("l"); + } + else + { + result->set_details("t"); + } + } + else // None of the above BPs reached so obviously something went wrong + { + m_log << "Result WTF?" << endl; + result->set_resulttype(result->UNKNOWN); + + stringstream ss; + ss << "event addr: " << go << " EIP " << simulator.getCPU(0).getInstructionPointer(); + result->set_details(ss.str()); + } + result->set_runtime(timer); + } + +#if !LOCAL + m_jc.sendResult(param); // Send the result back to the job server and continue with next experiment (if there is one) + } +#endif + return true; +} + +void FiascoFailExperiment::goldenRun() +{ + std::vector m_lTraps; + + + simulator.restore("state"); // Restore state (Continues from the first IP in the main function of the Application) + + BPSingleListener l_stop_address(endAddress); // Add the last IP of the main function to the actual listeners + m_log << "Golden-Run start, Stop-Address: 0x" << hex << endAddress << endl; + + std::string golden_output; + ofstream golden_output_file("golden.out"); // Save the logged output in "golden.out" + + simulator.addListener(&l_stop_address); + + TrapListener ev_trap(ANY_TRAP); // Trap listeners, break if any trap is triggered + simulator.addListener(&ev_trap); + + bool finished = false; + m_CurrentOutput = ""; + while(!finished) // Continue and log output + { + BaseListener* ev = waitIOOrOther(false); + if(ev == &ev_trap) // if trap is triggered, log the number + { + m_lTraps.push_back(ev_trap.getTriggerNumber()); + simulator.addListener(&ev_trap); + } + else if(ev == &l_stop_address) // if stop address is reached, save the output and finish the experiment + { + golden_output.assign(m_CurrentOutput.c_str()); + golden_output_file << m_CurrentOutput.c_str(); + m_log << "Output successfully logged..." << endl; + finished = true; + } + else // something went wrong + { + m_log << "Error on logging Output, terminating..." << endl; + golden_output_file.close(); + simulator.clearListeners(); + simulator.terminate(); + exit(-1); + } + } + + m_log << "Saving..." << endl; + golden_output_file.close(); + m_log << "Done." << endl; + + stringstream ss; + ss << "triggered traps: "; + for(std::vector::iterator lIterator = m_lTraps.begin(); lIterator != m_lTraps.end(); ++lIterator) + { + ss << *lIterator << " "; + } + m_log << ss.str() << endl; +} diff --git a/src/experiments/fiascoFail/experiment.hpp b/src/experiments/fiascoFail/experiment.hpp new file mode 100644 index 00000000..888409eb --- /dev/null +++ b/src/experiments/fiascoFail/experiment.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +#include "util/Logger.hpp" +#include "efw/ExperimentFlow.hpp" +#include "efw/JobClient.hpp" +#include "sal/Listener.hpp" + +class FiascoFailExperiment : public fail::ExperimentFlow +{ +private: + fail::Logger m_log; + fail::JobClient m_jc; + std::string m_variant, m_benchmark; + void readGoldenRun(std::string &); + fail::BaseListener* waitIOOrOther(bool); + void parseOptions(); + bool faultInjection(); + + std::string m_CurrentOutput; + fail::guest_address_t endAddress; + unsigned golden_run_instructions; + unsigned long long golden_run_timer_ticks; + fail::guest_address_t ecc_panic_address; + fail::guest_address_t addr_errors_corrected; + bool _golden_run; + void goldenRun(); + +public: + FiascoFailExperiment() : m_log("FiascoFail", false){} + bool run(); +}; diff --git a/src/experiments/fiascoFail/experimentInfo.hpp b/src/experiments/fiascoFail/experimentInfo.hpp new file mode 100644 index 00000000..31030762 --- /dev/null +++ b/src/experiments/fiascoFail/experimentInfo.hpp @@ -0,0 +1,9 @@ +#ifndef __FIASCOFAIL_EXPERIMENT_INFO_HPP +#define __FIASCOFAIL_EXPERIMENT_INFO_HPP + +#define FIASCO_BREAK_BLINK 0xf004b800 +#define FIASCO_BREAK_LONGJMP 0xf004c88e + +#define FIASCO_FAULTMODEL_BURST 1 + +#endif diff --git a/src/experiments/fiascoFail/fiascofail.proto b/src/experiments/fiascoFail/fiascofail.proto new file mode 100644 index 00000000..57a91d9d --- /dev/null +++ b/src/experiments/fiascoFail/fiascofail.proto @@ -0,0 +1,51 @@ +import "DatabaseCampaignMessage.proto"; + +message FiascofailProtoMsg { + required DatabaseCampaignMessage fsppilot = 1; + + repeated group Result = 2 { + // single experiment bit offset + required uint32 bit_offset = 1 [(sql_primary_key) = true]; + + enum ResultType { + OK = 0; + SDC = 1; + DETECTED = 2; + TRAP = 3; + TIMEOUT = 4; + UNKNOWN = 5; + } + required ResultType resulttype = 2; + + // all subsequent fields are optional, resulting in NULLable DB + // columns, saving space when unused; NULL should be interpreted as 0 + // for these cases + enum MemAccessOutside { + NONE = 0; + READ = 1; + WRITE = 2; + } + optional MemAccessOutside memaccess_outside = 3; + + enum Flag { + FALSE = 0; + TRUE = 1; + } + optional Flag jump_outside = 4; + + // did ECC correct the fault? + optional Flag error_corrected = 5; + + // simulated runtime factor compared to golden run (1.000 = golden run runtime) + optional float sim_runtime_factor = 6; + + // especially interesting for TRAP/UNKNOWN: latest IP + optional uint32 latest_ip = 7; + + // optional textual description of what happened + optional string details = 8; + + // experiment runtime (FIXME: should be part of DatabaseCampaignMessage instead) + optional float runtime = 9; + } +} diff --git a/src/experiments/fiascoFail/instantiateExperiment.cc b/src/experiments/fiascoFail/instantiateExperiment.cc new file mode 100644 index 00000000..7bc7bae8 --- /dev/null +++ b/src/experiments/fiascoFail/instantiateExperiment.cc @@ -0,0 +1,7 @@ +#include "experiment.hpp" +#include "sal/SALInst.hpp" + +void instantiateFiascoFailExperiment() +{ + fail::simulator.addFlow(new FiascoFailExperiment); +} diff --git a/src/experiments/fiascoFail/main.cc b/src/experiments/fiascoFail/main.cc new file mode 100644 index 00000000..031ae3c4 --- /dev/null +++ b/src/experiments/fiascoFail/main.cc @@ -0,0 +1,25 @@ +#include +#include + +#include "cpn/CampaignManager.hpp" +#include "util/CommandLine.hpp" +#include "campaign.hpp" + +int main(int argc, char **argv) +{ + fail::CommandLine &cmd = fail::CommandLine::Inst(); + for(int i = 1; i < argc; ++i) + { + cmd.add_args(argv[i]); + } + + FiascoFailCampaign c; + if(fail::campaignmanager.runCampaign(&c)) + { + return 0; + } + else + { + return 1; + } +} diff --git a/src/experiments/generic-experiment/CMakeLists.txt b/src/experiments/generic-experiment/CMakeLists.txt new file mode 100644 index 00000000..2c537ae8 --- /dev/null +++ b/src/experiments/generic-experiment/CMakeLists.txt @@ -0,0 +1,37 @@ +set(EXPERIMENT_NAME generic-experiment) +set(EXPERIMENT_TYPE GenericExperiment) +configure_file(../instantiate-experiment.ah.in + ${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY +) + +## Setup desired protobuf descriptions HERE ## +set(MY_PROTOS + generic-experiment.proto +) + +set(MY_CAMPAIGN_SRCS + experiment.hpp + experiment.cc + campaign.hpp + campaign.cc +) + +#### PROTOBUFS #### +find_package(Protobuf REQUIRED) +include_directories(${PROTOBUF_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +find_package(MySQL REQUIRED) +include_directories(${MYSQL_INCLUDE_DIR}) + +PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS}) + +## Build library +add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS}) +add_dependencies(fail-${EXPERIMENT_NAME} fail-comm) +target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY} fail-sal) + +## This is the example's campaign server distributing experiment parameters +add_executable(${EXPERIMENT_NAME}-server main.cc) +target_link_libraries(${EXPERIMENT_NAME}-server -Wl,--start-group fail-${EXPERIMENT_NAME} fail-sal fail-util fail-cpn fail-comm ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} ${MYSQL_LIBRARIES} -Wl,--end-group) +install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin) diff --git a/src/experiments/generic-experiment/campaign.cc b/src/experiments/generic-experiment/campaign.cc new file mode 100644 index 00000000..1286e9da --- /dev/null +++ b/src/experiments/generic-experiment/campaign.cc @@ -0,0 +1,21 @@ +#include +#include + +#include "campaign.hpp" +#include "experimentInfo.hpp" +#include "cpn/CampaignManager.hpp" +#include "util/Logger.hpp" +#include "util/ProtoStream.hpp" +#include "sal/SALConfig.hpp" + +#include "experimentInfo.hpp" + +using namespace std; +using namespace fail; +using namespace google::protobuf; + +void GenericExperimentCampaign::cb_send_pilot(DatabaseCampaignMessage pilot) { + GenericExperimentData *data = new GenericExperimentData; + data->msg.mutable_fsppilot()->CopyFrom(pilot); + campaignmanager.addParam(data); +} diff --git a/src/experiments/generic-experiment/campaign.hpp b/src/experiments/generic-experiment/campaign.hpp new file mode 100644 index 00000000..8a49a8a4 --- /dev/null +++ b/src/experiments/generic-experiment/campaign.hpp @@ -0,0 +1,16 @@ +#ifndef __KESOGCCAMPAIGN_HPP__ + #define __KESOGCCAMPAIGN_HPP__ + +#include "cpn/DatabaseCampaign.hpp" +#include + +class GenericExperimentCampaign : public fail::DatabaseCampaign { + virtual const google::protobuf::Descriptor * cb_result_message() { + return google::protobuf::DescriptorPool::generated_pool() + ->FindMessageTypeByName("GenericExperimentMessage"); + } + + virtual void cb_send_pilot(DatabaseCampaignMessage pilot); +}; + +#endif // __KESOGCCAMPAIGN_HPP__ diff --git a/src/experiments/generic-experiment/config.cmake b/src/experiments/generic-experiment/config.cmake new file mode 100644 index 00000000..63d3927a --- /dev/null +++ b/src/experiments/generic-experiment/config.cmake @@ -0,0 +1,2 @@ +SET(bochs_configure_params "--enable-a20-pin;--enable-x86-64;--enable-cpu-level=6;--enable-ne2000;--enable-acpi;--enable-pci;--enable-usb;--enable-trace-cache;--enable-fast-function-calls;--enable-host-specific-asms;--enable-readline;--enable-clgd54xx;--enable-fpu;--enable-vmx=2;--enable-monitor-mwait;--enable-cdrom;--enable-sb16=linux;--enable-gdb-stub;--with-nogui" CACHE STRING "") + diff --git a/src/experiments/generic-experiment/experiment.cc b/src/experiments/generic-experiment/experiment.cc new file mode 100644 index 00000000..c11cb690 --- /dev/null +++ b/src/experiments/generic-experiment/experiment.cc @@ -0,0 +1,266 @@ +#include +#include + +// getpid +#include +#include + + +#include +#include "experiment.hpp" +#include "experimentInfo.hpp" +#include "sal/SALConfig.hpp" +#include "sal/SALInst.hpp" +#include "sal/Memory.hpp" +#include "sal/Listener.hpp" + +#include "sal/bochs/BochsListener.hpp" +#include +#include + +#include "campaign.hpp" +#include "generic-experiment.pb.h" +#include "util/CommandLine.hpp" + +using namespace std; +using namespace fail; + + +GenericExperiment::~GenericExperiment() {} + +static GenericExperimentData space_for_param; +ExperimentData* GenericExperiment::cb_allocate_experiment_data() { + return &space_for_param; +} + +/** + * Allocate a new result slot in the given experiment data + */ +google::protobuf::Message* GenericExperiment::cb_new_result(ExperimentData* data) { + GenericExperimentData *param = static_cast(data); + GenericExperimentMessage_Result *result = param->msg.add_result(); + return result; +} + + +void handleEvent(GenericExperimentMessage_Result& result, + GenericExperimentMessage_Result_ResultType restype, + unsigned int details) { + cout << "Result details: " << restype << " "<< details << endl; + result.set_resulttype(restype); + result.set_details(details); +} + +void GenericExperiment::parseSymbols(const std::string &args, std::set * into) { + std::vector elems; + std::stringstream ss(args); + std::string item; + while (std::getline(ss, item, ',')) { + const ElfSymbol * symbol = &m_elf.getSymbol(item); + if (!symbol->isValid()) { + m_log << "ELF Symbol not found: " << item << endl; + simulator.terminate(1); + } + m_log << "Adding symbol " << item << " at 0x" << hex << symbol->getAddress() << endl; + BPSingleListener *l = new BPSingleListener(symbol->getAddress()); + into->insert(l); + end_markers.insert(l); + listener_to_symbol[l] = symbol; + } +} + + + +bool GenericExperiment::cb_start_experiment() { + CommandLine &cmd = CommandLine::Inst(); + cmd.addOption("", "", Arg::None, "USAGE: fail-client -Wf,[option] -Wf,[option] ... \n\n"); + CommandLine::option_handle HELP = cmd.addOption("h", "help", Arg::None, "-h,--help \tPrint usage and exit"); + + CommandLine::option_handle STATE_DIR = cmd.addOption("", "state-dir", Arg::Required, + "--state-dir \t Path to the state directory"); + + // catch any trap + CommandLine::option_handle TRAP = cmd.addOption("", "trap", Arg::None, + "--trap \tCatch Traps"); + CommandLine::option_handle WRITE_MEM_TEXT = cmd.addOption("", "catch-write-textsegment", Arg::None, + "--catch-write-textsegment \tCatch writes to the text segment"); + + CommandLine::option_handle WRITE_MEM_OUTERSPACE + = cmd.addOption("", "catch-write-outerspace", Arg::None, + "--catch-write-outerspace \tCatch writes to the outerspace"); + + CommandLine::option_handle TIMEOUT = cmd.addOption("", "timeout", Arg::Required, + "--timeout \t Experiment Timeout in uS"); + + + std::map option_handles; + for (std::map::iterator it = end_marker_groups.begin(); + it != end_marker_groups.end(); ++it) { + CommandLine::option_handle handle = + cmd.addOption("", it->first, Arg::Required, + "--" + it->first + " \tList of symbols (comma separated)"); + option_handles[it->first] = handle; + } + + if (!cmd.parse()) { + cerr << "Error parsing arguments." << endl; + exit(-1); + } + + if (cmd[HELP]) { + cmd.printUsage(); + exit(0); + } + + address_t minimal_ip = INT_MAX; // Every address is lower + address_t maximal_ip = 0; + address_t minimal_data = 0x100000; // 1 Mbyte + address_t maximal_data = 0; + + for (ElfReader::section_iterator it = m_elf.sec_begin(); + it != m_elf.sec_end(); ++it) { + const ElfSymbol &symbol = *it; + std::string prefix(".text"); + if (symbol.getName().compare(0, prefix.size(), prefix) == 0) { + minimal_ip = std::min(minimal_ip, symbol.getStart()); + maximal_ip = std::max(maximal_ip, symbol.getEnd()); + } else { + minimal_data = std::min(minimal_data, symbol.getStart()); + maximal_data = std::max(maximal_data, symbol.getEnd()); + } + } + + if (cmd[WRITE_MEM_TEXT]) { + m_log << "Catch writes to text segment from " << hex << minimal_ip << " to " << maximal_ip << std::endl; + enabled_mem_text = true; + + l_mem_text.setWatchAddress(minimal_ip); + l_mem_text.setTriggerAccessType(MemAccessEvent::MEM_WRITE); + l_mem_text.setWatchWidth(maximal_ip - minimal_ip); + } + + if (cmd[WRITE_MEM_OUTERSPACE]) { + m_log << "Catch writes to outerspace from " << hex << " from " << maximal_data << std::endl; + enabled_mem_outerspace = true; + + l_mem_outerspace.setWatchAddress(maximal_data); + l_mem_outerspace.setTriggerAccessType(MemAccessEvent::MEM_WRITE); + l_mem_outerspace.setWatchWidth(0xfffffff0); + } + + if (cmd[TRAP]) { + m_log << "Catch all traps" << endl; + enabled_trap = true; + } + + if (cmd[STATE_DIR]) { + std::string value(cmd[STATE_DIR].first()->arg); + m_state_dir = value; + m_log << "Set state dir to " << value << endl; + } + + if (cmd[TIMEOUT]) { + std::string value(cmd[TIMEOUT].first()->arg); + std::stringstream ss(value); + ss >> m_Timeout; + if (ss.bad()) { + m_log << "Could not parse --timeout argument" << endl; + return false; // Initialization failed + } + l_timeout.setTimeout(m_Timeout); + enabled_timeout = true; + m_log << "Enabled Experiment Timeout of " << dec << m_Timeout << " microseconds" << endl; + } + + for (std::map::iterator it = option_handles.begin(); + it != option_handles.end(); ++it) { + if (cmd[option_handles[it->first]]) { + option::Option *opt = cmd[option_handles[it->first]].first(); + while (opt != 0) { + parseSymbols(std::string(opt->arg), end_marker_groups[it->first]); + opt = opt->next(); + } + } + } + + return true; // Everything OK +} + + +bool GenericExperiment::cb_before_resume() { + if (enabled_trap) + simulator.addListener(&l_trap); + + if (enabled_mem_text) + simulator.addListener(&l_mem_text); + + if (enabled_mem_outerspace) { + std::cout << "enabled mem outerspace " << endl; + simulator.addListener(&l_mem_outerspace); + } + + if (enabled_timeout) + simulator.addListener(&l_timeout); + + for (std::set::iterator it = end_markers.begin(); + it != end_markers.end(); ++it) { + simulator.addListener(*it); + } + + return true; // everything OK +} + +void GenericExperiment::cb_after_resume(fail::BaseListener *event) { + GenericExperimentMessage_Result * result = static_cast(this->get_current_result()); + + // Record the crash time + result->set_crash_time(simulator.getTimerTicks()); + + + if (event == &l_timeout) { + handleEvent(*result, result->TIMEOUT, m_Timeout); + } else if (event == &l_trap) { + handleEvent(*result, result->TRAP, l_trap.getTriggerNumber()); + } else if (event == &l_mem_text) { + handleEvent(*result, result->WRITE_TEXTSEGMENT, + l_mem_text.getTriggerAddress()); + + } else if (event == &l_mem_outerspace){ + handleEvent(*result, result->WRITE_OUTERSPACE, + l_mem_outerspace.getTriggerAddress()); + + ////////////////////////////////////////////////// + // End Marker Groups + ////////////////////////////////////////////////// + } else if (OK_marker.find(event) != OK_marker.end()) { + const ElfSymbol *symbol = listener_to_symbol[event]; + handleEvent(*result, result->OK_MARKER, symbol->getAddress()); + + } else if (FAIL_marker.find(event) != FAIL_marker.end()) { + const ElfSymbol *symbol = listener_to_symbol[event]; + handleEvent(*result, result->FAIL_MARKER, symbol->getAddress()); + + } else if (DETECTED_marker.find(event) != DETECTED_marker.end()) { + const ElfSymbol *symbol = listener_to_symbol[event]; + handleEvent(*result, result->DETECTED_MARKER, symbol->getAddress()); + + } else if (GROUP1_marker.find(event) != GROUP1_marker.end()) { + const ElfSymbol *symbol = listener_to_symbol[event]; + handleEvent(*result, result->GROUP1_MARKER, symbol->getAddress()); + + } else if (GROUP2_marker.find(event) != GROUP2_marker.end()) { + const ElfSymbol *symbol = listener_to_symbol[event]; + handleEvent(*result, result->GROUP2_MARKER, symbol->getAddress()); + + } else if (GROUP3_marker.find(event) != GROUP3_marker.end()) { + const ElfSymbol *symbol = listener_to_symbol[event]; + handleEvent(*result, result->GROUP3_MARKER, symbol->getAddress()); + + } else if (GROUP4_marker.find(event) != GROUP4_marker.end()) { + const ElfSymbol *symbol = listener_to_symbol[event]; + handleEvent(*result, result->GROUP4_MARKER, symbol->getAddress()); + + } else { + handleEvent(*result, result->UNKNOWN, 0); + } +} diff --git a/src/experiments/generic-experiment/experiment.hpp b/src/experiments/generic-experiment/experiment.hpp new file mode 100644 index 00000000..72780e7b --- /dev/null +++ b/src/experiments/generic-experiment/experiment.hpp @@ -0,0 +1,111 @@ +#ifndef __GENERIC_EXPERIMENT_EXPERIMENT_HPP__ +#define __GENERIC_EXPERIMENT_EXPERIMENT_HPP__ + +#include "sal/SALInst.hpp" +#include "efw/DatabaseExperiment.hpp" +#include "sal/Listener.hpp" +#include "efw/JobClient.hpp" +#include "util/Logger.hpp" +#include "util/ElfReader.hpp" +#include +#include +#include +#include + + +class GenericExperiment : public fail::DatabaseExperiment { + fail::ElfReader m_elf; + + std::string m_state_dir; + + bool enabled_mem_text; + fail::MemAccessListener l_mem_text; + + bool enabled_mem_outerspace; + fail::MemAccessListener l_mem_outerspace; + + bool enabled_trap; + fail::TrapListener l_trap; + + bool enabled_timeout; + unsigned m_Timeout; + fail::TimerListener l_timeout; + + std::map listener_to_symbol; + + typedef std::set ListenerSet; + + ListenerSet end_markers; + ListenerSet OK_marker; + ListenerSet FAIL_marker; + ListenerSet DETECTED_marker; + ListenerSet GROUP1_marker; + ListenerSet GROUP2_marker; + ListenerSet GROUP3_marker; + ListenerSet GROUP4_marker; + + std::map end_marker_groups; + + void parseSymbols(const std::string &args, std::set *into); + +public: + GenericExperiment() : DatabaseExperiment("GenericExperiment"), + m_state_dir("state"), + l_trap(fail::ANY_TRAP), l_timeout(0) { + enabled_mem_text = false; + enabled_mem_outerspace = false; + enabled_trap = false; + enabled_timeout = false; + + end_marker_groups["ok-marker"] = &OK_marker; + end_marker_groups["fail-marker"] = &FAIL_marker; + end_marker_groups["detected-marker"] = &FAIL_marker; + end_marker_groups["group1-marker"] = &GROUP1_marker; + end_marker_groups["group2-marker"] = &GROUP2_marker; + end_marker_groups["group3-marker"] = &GROUP3_marker; + end_marker_groups["group4-marker"] = &GROUP4_marker; + } + virtual ~GenericExperiment(); + + /** + * Get path to the state directory + */ + virtual std::string cb_state_directory() { return m_state_dir; } + + /** + * Allocate enough space to hold the incoming ExperimentData message. + */ + virtual fail::ExperimentData* cb_allocate_experiment_data(); + + /** + * Allocate a new result slot in the given experiment data + */ + virtual google::protobuf::Message* cb_new_result(fail::ExperimentData* data); + + /** + * Callback that is called, before the actual experiment + * starts. Simulation is terminated on false. + * @param The current result message + * @return \c true on success, \c false otherwise + */ + virtual bool cb_start_experiment(); + + /** + * Callback that is called before the resuming till crash has + * started. This is called after the fault was injected. Here the + * end listeners should be installed. Returns true on + * success. Otherwise the experiment is canceled. + + * @return \c true on success, \c false otherwise + */ + virtual bool cb_before_resume(); + + /** + * Callback that is called after the resume-till-crash phase with + * the last triggered listener. This callback should collect all + * data and fill up the result message. + */ + virtual void cb_after_resume(fail::BaseListener *event); +}; + +#endif // __GENERIC_EXPERIMENT_EXPERIMENT_HPP__ diff --git a/src/experiments/generic-experiment/experimentInfo.hpp b/src/experiments/generic-experiment/experimentInfo.hpp new file mode 100644 index 00000000..c371b250 --- /dev/null +++ b/src/experiments/generic-experiment/experimentInfo.hpp @@ -0,0 +1,15 @@ +#ifndef __EXPERIMENT_INFO_HPP__ +#define __EXPERIMENT_INFO_HPP__ + +#include "comm/ExperimentData.hpp" +#include "generic-experiment.pb.h" + +class GenericExperimentData : public fail::ExperimentData { +public: + GenericExperimentMessage msg; + GenericExperimentData() : fail::ExperimentData(&msg) {} +}; + + + +#endif // __EXPERIMENT_INFO_HPP__ diff --git a/src/experiments/generic-experiment/generic-experiment.proto b/src/experiments/generic-experiment/generic-experiment.proto new file mode 100644 index 00000000..09b25fc6 --- /dev/null +++ b/src/experiments/generic-experiment/generic-experiment.proto @@ -0,0 +1,36 @@ +import "DatabaseCampaignMessage.proto"; + +message GenericExperimentMessage { + required DatabaseCampaignMessage fsppilot = 1; + + repeated group Result = 2 { + // This submessage is required by the database experiment and + // is filled with standard experiment result values + required DatabaseExperimentMessage base_result = 1; + + // make these optional to reduce overhead for server->client communication + enum ResultType { + OK_MARKER = 1; + FAIL_MARKER = 2; + DETECTED_MARKER = 3; + + GROUP1_MARKER = 4; + GROUP2_MARKER = 5; + GROUP3_MARKER = 6; + GROUP4_MARKER = 7; + + TIMEOUT = 8; + TRAP = 9; + WRITE_TEXTSEGMENT = 10; + WRITE_OUTERSPACE = 11; + + UNKNOWN = 100; + } + // result type, see above + required ResultType resulttype = 4; + + required uint64 crash_time = 5; + + optional uint64 details = 7; + } +} diff --git a/src/experiments/generic-experiment/main.cc b/src/experiments/generic-experiment/main.cc new file mode 100644 index 00000000..73501382 --- /dev/null +++ b/src/experiments/generic-experiment/main.cc @@ -0,0 +1,20 @@ +#include +#include + +#include "cpn/CampaignManager.hpp" +#include "util/CommandLine.hpp" +#include "campaign.hpp" + +int main(int argc, char **argv) +{ + fail::CommandLine &cmd = fail::CommandLine::Inst(); + for (int i = 1; i < argc; ++i) + cmd.add_args(argv[i]); + + GenericExperimentCampaign c; + if (fail::campaignmanager.runCampaign(&c)) { + return 0; + } else { + return 1; + } +} diff --git a/src/experiments/generic-tracing/config.cmake b/src/experiments/generic-tracing/config.cmake new file mode 100644 index 00000000..a3c46366 --- /dev/null +++ b/src/experiments/generic-tracing/config.cmake @@ -0,0 +1,10 @@ +SET(PLUGINS_ACTIVATED "tracing" CACHE STRING "") + +SET(bochs_configure_params "--enable-a20-pin;--enable-x86-64;--enable-cpu-level=6;--enable-ne2000;--enable-acpi;--enable-pci;--enable-usb;--enable-trace-cache;--enable-fast-function-calls;--enable-host-specific-asms;--enable-readline;--enable-clgd54xx;--enable-fpu;--enable-vmx=2;--enable-monitor-mwait;--enable-cdrom;--enable-sb16=linux;--enable-gdb-stub;--with-nogui" CACHE STRING "") + +# Build the import and prune trace tools always +SET(BUILD_IMPORT_TRACE ON CACHE BOOL "" FORCE) +SET(BUILD_PRUNE_TRACE ON CACHE BOOL "" FORCE) +SET(BUILD_CONVERT_TRACE ON CACHE BOOL "" FORCE) +SET(BUILD_DUMP_TRACE ON CACHE BOOL "" FORCE) +SET(BUILD_LLVM_DISASSEMBLER ON CACHE BOOL "" FORCE) diff --git a/src/experiments/regression-test/CMakeLists.txt b/src/experiments/regression-test/CMakeLists.txt index 23586b5f..4c80e13f 100644 --- a/src/experiments/regression-test/CMakeLists.txt +++ b/src/experiments/regression-test/CMakeLists.txt @@ -15,3 +15,6 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) ## build library add_library(fail-${EXPERIMENT_NAME} ${MY_EXPERIMENT_SRCS}) +add_dependencies(fail-${EXPERIMENT_NAME} fail-comm) +target_link_libraries(fail-${EXPERIMENT_NAME} fail-tracing fail-serialoutput fail-comm fail-util) +target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY}) diff --git a/src/experiments/weather-monitor/CMakeLists.txt b/src/experiments/weather-monitor/CMakeLists.txt index ab1e77b0..1ef3c24b 100644 --- a/src/experiments/weather-monitor/CMakeLists.txt +++ b/src/experiments/weather-monitor/CMakeLists.txt @@ -27,8 +27,8 @@ PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS}) ## Build library add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS}) -add_dependencies(fail-${EXPERIMENT_NAME} fail-comm) -target_link_libraries(fail-${EXPERIMENT_NAME} fail-tracing fail-comm) +add_dependencies(fail-${EXPERIMENT_NAME} fail-comm fail-util fail-sal fail-tracing) +target_link_libraries(fail-${EXPERIMENT_NAME} fail-comm fail-util fail-sal fail-tracing) target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY}) ## This is the example's campaign server distributing experiment parameters diff --git a/src/experiments/weather-monitor/config.cmake b/src/experiments/weather-monitor/config.cmake new file mode 100644 index 00000000..e7e04ff9 --- /dev/null +++ b/src/experiments/weather-monitor/config.cmake @@ -0,0 +1,4 @@ +## Configuration +SET(PLUGINS_ACTIVATED "tracing" CACHE STRING "") + +SET(bochs_configure_params "--enable-a20-pin;--enable-x86-64;--enable-cpu-level=6;--enable-ne2000;--enable-acpi;--enable-pci;--enable-usb;--enable-trace-cache;--enable-fast-function-calls;--enable-host-specific-asms;--enable-disasm;--enable-readline;--enable-clgd54xx;--enable-fpu;--enable-vmx=2;--enable-monitor-mwait;--enable-cdrom;--enable-sb16=linux;--enable-gdb-stub;--with-nogui" CACHE STRING "") diff --git a/src/experiments/weather-monitor/experiment.cc b/src/experiments/weather-monitor/experiment.cc index b3195ea5..4f12c2c5 100644 --- a/src/experiments/weather-monitor/experiment.cc +++ b/src/experiments/weather-monitor/experiment.cc @@ -5,6 +5,9 @@ #include #include "util/Logger.hpp" +#include "util/ElfReader.hpp" +#include "util/CommandLine.hpp" +#include "util/gzstream/gzstream.h" #include "experiment.hpp" #include "experimentInfo.hpp" @@ -25,6 +28,8 @@ using namespace std; using namespace fail; +const std::string WeatherMonitorExperiment::dir_images(DIR_IMAGES); +const std::string WeatherMonitorExperiment::dir_prerequisites(DIR_PREREQUISITES); // Check if configuration dependencies are satisfied: #if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) || \ @@ -32,61 +37,183 @@ using namespace fail; #error This experiment needs: breakpoints, traps, save, and restore. Enable these in the configuration. #endif -bool WeatherMonitorExperiment::run() +bool WeatherMonitorExperiment::readElfSymbols( + guest_address_t& entry, + guest_address_t& text_start, + guest_address_t& text_end, + guest_address_t& data_start, + guest_address_t& data_end, + guest_address_t& wait_begin, + guest_address_t& wait_end, + guest_address_t& vptr_panic) { - char const *statename = "bochs.state" WEATHER_SUFFIX; - Logger log("Weathermonitor", false); - BPSingleListener bp; + ElfReader elfreader(filename_elf(m_variant, m_benchmark).c_str()); - log << "startup" << endl; + entry = elfreader.getSymbol("main").getAddress(); + text_start = elfreader.getSymbol("___TEXT_START__").getAddress(); + text_end = elfreader.getSymbol("___TEXT_END__").getAddress(); + data_start = elfreader.getSymbol("___DATA_START__").getAddress(); + data_end = elfreader.getSymbol("___BSS_END__").getAddress(); + wait_begin = elfreader.getSymbol("wait_begin").getAddress(); + wait_end = elfreader.getSymbol("wait_end").getAddress(); -/* - * this does not work as the guestsys doesn't output anything - * albeit that, it's no longer needed in this experiment - */ - -#if 0 - // STEP 0: record memory map with vptr addresses - ofstream mmap; - mmap.open ("memory.map"); - GuestListener g; - while (true) { - simulator.addListenerAndResume(&g); - mmap << g.getData() << flush; + // vptr_panic only exists in guarded version + vptr_panic = elfreader.getSymbol("vptr_panic").getAddress(); + // use a dummy address, in case the symbol cannot be found + if (vptr_panic == ADDR_INV) { + vptr_panic = 99999999; } - mmap.close(); -#endif -#if 1 + if (entry == ADDR_INV || text_start == ADDR_INV || text_end == ADDR_INV || + data_start == ADDR_INV || data_end == ADDR_INV || + wait_begin == ADDR_INV || wait_end == ADDR_INV) { + return false; + } + + return true; +} + +std::string WeatherMonitorExperiment::filename_elf(const std::string& variant, const std::string& benchmark) +{ + if (variant.size() && benchmark.size()) { + return dir_images + "/" + variant + ".elf"; + } + return "weather.elf"; +} + +std::string WeatherMonitorExperiment::filename_state(const std::string& variant, const std::string& benchmark) +{ + if (variant.size() && benchmark.size()) { + return dir_prerequisites + "/" + variant + ".state"; + } + return "state.weather"; +} + +std::string WeatherMonitorExperiment::filename_trace(const std::string& variant, const std::string& benchmark) +{ + if (variant.size() && benchmark.size()) { + return dir_prerequisites + "/" + variant + ".trace"; + } + return "trace.weather"; +} + +std::string WeatherMonitorExperiment::filename_traceinfo(const std::string& variant, const std::string& benchmark) +{ + if (variant.size() && benchmark.size()) { + return dir_prerequisites + "/" + variant + ".info"; + } + return "weather.info"; +} + +bool WeatherMonitorExperiment::writeTraceInfo(unsigned numinstr_tracing, unsigned numinstr_after) +{ + ofstream ti(filename_traceinfo(m_variant, m_benchmark).c_str(), ios::out); + if (!ti.is_open()) { + cout << "failed to open " << filename_traceinfo(m_variant, m_benchmark) << endl; + return false; + } + ti << numinstr_tracing << endl << numinstr_after << endl; + ti.flush(); + ti.close(); + return true; +} + +bool WeatherMonitorExperiment::readTraceInfo(unsigned& numinstr_tracing, unsigned& numinstr_after) +{ + ifstream file(filename_traceinfo(m_variant, m_benchmark).c_str()); + if (!file.is_open()) { + cout << "failed to open " << filename_traceinfo(m_variant, m_benchmark) << endl; + return false; + } + + string buf; + unsigned count = 0; + + while (getline(file, buf)) { + stringstream ss(buf, ios::in); + switch (count) { + case 0: + ss >> numinstr_tracing; + break; + case 1: + ss >> numinstr_after; + break; + } + count++; + } + file.close(); + assert(count == 2); + return (count == 2); +} + + +void WeatherMonitorExperiment::parseOptions() +{ + CommandLine &cmd = CommandLine::Inst(); + cmd.addOption("", "", Arg::None, "USAGE: fail-client -Wf,[option] -Wf,[option] ... "); + CommandLine::option_handle HELP = + cmd.addOption("h", "help", Arg::None, "-h,--help \tPrint usage and exit"); + CommandLine::option_handle VARIANT = + cmd.addOption("", "variant", Arg::Required, "--variant v \texperiment variant"); + CommandLine::option_handle BENCHMARK = + cmd.addOption("", "benchmark", Arg::Required, "--benchmark b \tbenchmark"); + + if (!cmd.parse()) { + cerr << "Error parsing arguments." << endl; + simulator.terminate(1); + } else if (cmd[HELP]) { + cmd.printUsage(); + simulator.terminate(0); + } + + if (cmd[VARIANT].count() > 0 && cmd[BENCHMARK].count() > 0) { + m_variant = std::string(cmd[VARIANT].first()->arg); + m_benchmark = std::string(cmd[BENCHMARK].first()->arg); + } else { + cerr << "Please supply parameters for --variant and --benchmark." << endl; + simulator.terminate(1); + } +} + +bool WeatherMonitorExperiment::establishState(guest_address_t& entry) +{ // STEP 1: run until interesting function starts, and save state - bp.setWatchInstructionPointer(WEATHER_FUNC_MAIN); + bp.setWatchInstructionPointer(entry); simulator.addListenerAndResume(&bp); - log << "test function entry reached, saving state" << endl; - log << "EIP = " << hex << bp.getTriggerInstructionPointer() << endl; - simulator.save(statename); - assert(bp.getTriggerInstructionPointer() == WEATHER_FUNC_MAIN); - assert(simulator.getCPU(0).getInstructionPointer() == WEATHER_FUNC_MAIN); + LOG << "test function entry reached, saving state" << endl; + LOG << "EIP = " << hex << bp.getTriggerInstructionPointer() << endl; + simulator.save(filename_state(m_variant, m_benchmark).c_str()); + assert(bp.getTriggerInstructionPointer() == entry); + assert(simulator.getCPU(0).getInstructionPointer() == entry); + return true; +} + +bool WeatherMonitorExperiment::performTrace( + guest_address_t& entry, + guest_address_t& data_start, + guest_address_t& data_end, + guest_address_t& wait_end) +{ // STEP 2: record trace for fault-space pruning - log << "restoring state" << endl; - simulator.restore(statename); - log << "EIP = " << hex << simulator.getCPU(0).getInstructionPointer() << endl; - assert(simulator.getCPU(0).getInstructionPointer() == WEATHER_FUNC_MAIN); + LOG << "STEP 2 restoring state" << endl; + simulator.restore(filename_state(m_variant, m_benchmark).c_str()); + LOG << "EIP = " << hex << simulator.getCPU(0).getInstructionPointer() << endl; + assert(simulator.getCPU(0).getInstructionPointer() == entry); - log << "enabling tracing" << endl; + LOG << "enabling tracing" << endl; TracingPlugin tp; // TODO: record max(ESP) // restrict memory access logging to injection target MemoryMap mm; - mm.add(WEATHER_DATA_START, WEATHER_DATA_END - WEATHER_DATA_START); + mm.add(data_start, data_end - data_start); tp.restrictMemoryAddresses(&mm); //tp.setLogIPOnly(true); // record trace - char const *tracefile = "trace.tc" WEATHER_SUFFIX; - ofstream of(tracefile); + ogzstream of(filename_trace(m_variant, m_benchmark).c_str()); tp.setTraceFile(&of); // this must be done *after* configuring the plugin: @@ -95,7 +222,7 @@ bool WeatherMonitorExperiment::run() #if 1 // trace WEATHER_NUMITER_TRACING measurement loop iterations // -> calibration - bp.setWatchInstructionPointer(WEATHER_FUNC_WAIT_END); + bp.setWatchInstructionPointer(wait_end); bp.setCounter(WEATHER_NUMITER_TRACING); #else // FIXME this doesn't work properly: trace is one instruction too short as @@ -111,54 +238,61 @@ bool WeatherMonitorExperiment::run() // count instructions // FIXME add SAL functionality for this? - int instr_counter = 0; + unsigned numinstr_tracing = 0; while (simulator.resume() == &ev_count) { - ++instr_counter; + ++numinstr_tracing; simulator.addListener(&ev_count); } - log << dec << "tracing finished after " << instr_counter + LOG << dec << "tracing finished after " << numinstr_tracing << " instructions, seeing wait_end " << WEATHER_NUMITER_TRACING << " times" << endl; simulator.removeFlow(&tp); // serialize trace to file if (of.fail()) { - log << "failed to write " << tracefile << endl; + LOG << "failed to write " << filename_trace(m_variant, m_benchmark) << endl; simulator.clearListeners(this); // cleanup return false; } of.close(); - log << "trace written to " << tracefile << endl; + LOG << "trace written to " << filename_trace(m_variant, m_benchmark) << endl; // wait another WEATHER_NUMITER_AFTER measurement loop iterations - bp.setWatchInstructionPointer(WEATHER_FUNC_WAIT_END); + bp.setWatchInstructionPointer(wait_end); bp.setCounter(WEATHER_NUMITER_AFTER); simulator.addListener(&bp); // count instructions // FIXME add SAL functionality for this? - instr_counter = 0; + unsigned numinstr_after = 0; while (simulator.resume() == &ev_count) { - ++instr_counter; + ++numinstr_after; simulator.addListener(&ev_count); } - log << dec << "experiment finished after " << instr_counter + LOG << dec << "experiment finished after " << numinstr_after << " instructions, seeing wait_end " << WEATHER_NUMITER_AFTER << " times" << endl; -#elif 0 - // STEP 3: The actual experiment. + if (!writeTraceInfo(numinstr_tracing, numinstr_after)) { + LOG << "failed to write " << filename_traceinfo(m_variant, m_benchmark) << endl; + return false; + } + return true; +} + +bool WeatherMonitorExperiment::faultInjection() +{ #if !LOCAL for (int i = 0; i < 50 || (m_jc.getNumberOfUndoneJobs() != 0) ; ++i) { // only do 50 sequential experiments, to prevent swapping // 50 exp ~ 0.5GB RAM usage per instance (linearly increasing) #endif // get an experiment parameter set - log << "asking job server for experiment parameters" << endl; + LOG << "asking job server for experiment parameters" << endl; WeatherMonitorExperimentData param; #if !LOCAL if (!m_jc.getParam(param)) { - log << "Dying." << endl; + LOG << "Dying." << endl; // communicate that we were told to die simulator.terminate(1); } @@ -168,9 +302,29 @@ bool WeatherMonitorExperiment::run() param.msg.fsppilot().set_data_address(0x00103bdc); #endif - int id = param.getWorkloadID(); + m_variant = param.msg.fsppilot().variant(); + m_benchmark = param.msg.fsppilot().benchmark(); unsigned injection_instr = param.msg.fsppilot().injection_instr(); + + /* get symbols from ELF */ + LOG << "retrieving ELF addresses..." << endl; + guest_address_t entry, text_start, text_end, data_start, data_end, wait_begin, wait_end, vptr_panic; + if (!readElfSymbols(entry, text_start, text_end, data_start, data_end, wait_begin, wait_end, vptr_panic)) { + LOG << "failed, essential symbols are missing!" << endl; + simulator.terminate(1); + } else { + LOG << "successfully retrieved ELF's addresses." << endl; + } + + /* get NUMINSTR_TRACING and NUMINSTR_AFTER */ + unsigned numinstr_tracing, numinstr_after; + if (!readTraceInfo(numinstr_tracing, numinstr_after)) { + LOG << "failed to read trace info from " << filename_traceinfo(m_variant, m_benchmark) << endl; + simulator.terminate(1); + return false; + } + address_t data_address = param.msg.fsppilot().data_address(); //old data. now it resides in the DatabaseCampaignMessage @@ -180,11 +334,11 @@ bool WeatherMonitorExperiment::run() // 8 results in one job WeathermonitorProtoMsg_Result *result = param.msg.add_result(); result->set_bitoffset(bit_offset); - log << dec << "job " << id << " instr " << injection_instr + LOG << dec << "job " << id << " instr " << injection_instr << " mem " << data_address << "+" << bit_offset << endl; - log << "restoring state" << endl; - simulator.restore(statename); + LOG << "restoring state" << endl; + simulator.restore(filename_state(m_variant, m_benchmark).c_str()); // XXX debug /* @@ -197,13 +351,13 @@ bool WeatherMonitorExperiment::run() // this marks THE END BPSingleListener ev_end(ANY_ADDR); - ev_end.setCounter(WEATHER_NUMINSTR_TRACING + WEATHER_NUMINSTR_AFTER); + ev_end.setCounter(numinstr_tracing + numinstr_after); simulator.addListener(&ev_end); // count loop iterations by counting wait_begin() calls // FIXME would be nice to have a callback API for this as this needs to // be done "in parallel" - BPSingleListener ev_wait_begin(WEATHER_FUNC_WAIT_BEGIN); + BPSingleListener ev_wait_begin(wait_begin); simulator.addListener(&ev_wait_begin); int count_loop_iter_before = 0; @@ -229,7 +383,7 @@ bool WeatherMonitorExperiment::run() // note at what IP we did it uint32_t injection_ip = simulator.getCPU(0).getInstructionPointer(); result->set_iter_before_fi(count_loop_iter_before); - log << "fault injected @ ip " << injection_ip + LOG << "fault injected @ ip " << injection_ip << " 0x" << hex << ((int)data) << " -> 0x" << ((int)newdata) << endl; // sanity check if (param.msg.fsppilot().has_injection_instr_absolute() && @@ -237,7 +391,7 @@ bool WeatherMonitorExperiment::run() stringstream ss; ss << "SANITY CHECK FAILED: " << injection_ip << " != " << param.msg.fsppilot().injection_instr_absolute(); - log << ss.str() << endl; + LOG << ss.str() << endl; result->set_resulttype(result->UNKNOWN); result->set_latest_ip(injection_ip); result->set_details(ss.str()); @@ -264,12 +418,12 @@ bool WeatherMonitorExperiment::run() TrapListener ev_trap(ANY_TRAP); simulator.addListener(&ev_trap); // jump outside text segment - BPRangeListener ev_below_text(ANY_ADDR, WEATHER_TEXT_START - 1); - BPRangeListener ev_beyond_text(WEATHER_TEXT_END + 1, ANY_ADDR); + BPRangeListener ev_below_text(ANY_ADDR, text_start - 1); + BPRangeListener ev_beyond_text(text_end + 1, ANY_ADDR); simulator.addListener(&ev_below_text); simulator.addListener(&ev_beyond_text); // error detected - BPSingleListener ev_detected(WEATHER_FUNC_VPTR_PANIC); + BPSingleListener ev_detected(vptr_panic); simulator.addListener(&ev_detected); // timeout (e.g., stuck in a HLT instruction) // 10000us = 500000 instructions @@ -278,7 +432,7 @@ bool WeatherMonitorExperiment::run() #if LOCAL && 0 // XXX debug - log << "enabling tracing" << endl; + LOG << "enabling tracing" << endl; TracingPlugin tp; tp.setLogIPOnly(true); tp.setOstream(&cout); @@ -300,28 +454,28 @@ bool WeatherMonitorExperiment::run() result->set_latest_ip(simulator.getCPU(0).getInstructionPointer()); if (ev == &ev_end) { - log << "Result FINISHED (" << dec + LOG << "Result FINISHED (" << dec << count_loop_iter_before << "+" << count_loop_iter_after << ")" << endl; result->set_resulttype(result->FINISHED); } else if (ev == &ev_timeout) { - log << "Result TIMEOUT (" << dec + LOG << "Result TIMEOUT (" << dec << count_loop_iter_before << "+" << count_loop_iter_after << ")" << endl; result->set_resulttype(result->TIMEOUT); } else if (ev == &ev_below_text || ev == &ev_beyond_text) { - log << "Result OUTSIDE" << endl; + LOG << "Result OUTSIDE" << endl; result->set_resulttype(result->OUTSIDE); } else if (ev == &ev_trap) { - log << dec << "Result TRAP #" << ev_trap.getTriggerNumber() << endl; + LOG << dec << "Result TRAP #" << ev_trap.getTriggerNumber() << endl; result->set_resulttype(result->TRAP); stringstream ss; ss << ev_trap.getTriggerNumber(); result->set_details(ss.str()); } else if (ev == &ev_detected) { - log << dec << "Result DETECTED" << endl; + LOG << dec << "Result DETECTED" << endl; result->set_resulttype(result->DETECTED); } else { - log << "Result WTF?" << endl; + LOG << "Result WTF?" << endl; result->set_resulttype(result->UNKNOWN); stringstream ss; @@ -331,7 +485,7 @@ bool WeatherMonitorExperiment::run() } // sanity check: do we have exactly 8 results? if (param.msg.result_size() != 8) { - log << "WTF? param.msg.result_size() != 8" << endl; + LOG << "WTF? param.msg.result_size() != 8" << endl; } else { #if !LOCAL m_jc.sendResult(param); @@ -342,7 +496,44 @@ bool WeatherMonitorExperiment::run() } #endif + return true; +} + +bool WeatherMonitorExperiment::run() +{ + LOG << "startup" << endl; +#if PREREQUISITES + parseOptions(); + + /* get symbols from ELF */ + LOG << "retrieving ELF addresses..." << endl; + guest_address_t entry, text_start, text_end, data_start, data_end, wait_begin, wait_end, vptr_panic; + if (!readElfSymbols(entry, text_start, text_end, data_start, data_end, wait_begin, wait_end, vptr_panic)) { + LOG << "failed, essential symbols are missing!" << endl; + simulator.terminate(1); + } else { + LOG << "successfully retrieved ELF's addresses." << endl; + } + + //STEP 1 + if (establishState(entry)) { + LOG << "STEP 1 (establish state) finished." << endl; + } else { + LOG << "STEP 1 (establish state) failed!" << endl; + } + + //STEP 2 + if (performTrace(entry, data_start, data_end, wait_end)) { + LOG << "STEP 2 (perform trace) finished." << endl; + } else { + LOG << "STEP 2 (perform trace) failed!" << endl; + } + +#else // !PREREQUISITES i.e. STEP 3 "the actual experiment" + faultInjection(); + #endif + // Explicitly terminate, or the simulator will continue to run. simulator.terminate(); } diff --git a/src/experiments/weather-monitor/experiment.hpp b/src/experiments/weather-monitor/experiment.hpp index 98036982..92c7b698 100644 --- a/src/experiments/weather-monitor/experiment.hpp +++ b/src/experiments/weather-monitor/experiment.hpp @@ -4,10 +4,39 @@ #include "efw/ExperimentFlow.hpp" #include "efw/JobClient.hpp" +#include "util/Logger.hpp" +#include "util/ElfReader.hpp" + +#include "sal/Listener.hpp" +#include "sal/SALConfig.hpp" + class WeatherMonitorExperiment : public fail::ExperimentFlow { fail::JobClient m_jc; + std::string m_variant, m_benchmark; + static const std::string dir_images; + static const std::string dir_prerequisites; + fail::Logger LOG; + fail::BPSingleListener bp; + + std::string filename_elf(const std::string& variant, const std::string& benchmark); + std::string filename_state(const std::string& variant, const std::string& benchmark); + std::string filename_trace(const std::string& variant, const std::string& benchmark); + std::string filename_traceinfo(const std::string& variant, const std::string& benchmark); + bool writeTraceInfo(unsigned numinstr_tracing, unsigned numinstr_after); + bool readTraceInfo(unsigned& numinstr_tracing, unsigned& numinstr_after); + bool readElfSymbols(fail::guest_address_t& entry, fail::guest_address_t& text_start, + fail::guest_address_t& text_end, fail::guest_address_t& data_start, + fail::guest_address_t& data_end, fail::guest_address_t& wait_begin, + fail::guest_address_t& wait_end, fail::guest_address_t& vptr_panic); + bool establishState(fail::guest_address_t& entry); + bool performTrace(fail::guest_address_t& entry, fail::guest_address_t& data_start, + fail::guest_address_t& data_end, fail::guest_address_t& wait_end); + bool faultInjection(); + public: + WeatherMonitorExperiment() : LOG("Weathermonitor", false) {} bool run(); + void parseOptions(void); }; #endif // __WEATHERMONITOR_EXPERIMENT_HPP__ diff --git a/src/experiments/weather-monitor/experimentInfo.hpp b/src/experiments/weather-monitor/experimentInfo.hpp index 3faa0142..e867d6e6 100644 --- a/src/experiments/weather-monitor/experimentInfo.hpp +++ b/src/experiments/weather-monitor/experimentInfo.hpp @@ -1,127 +1,9 @@ -#ifndef __WEATHERMONITOR_EXPERIMENT_INFO_HPP__ -#define __WEATHERMONITOR_EXPERIMENT_INFO_HPP__ +#pragma once -// autogenerated, don't edit! +#define DIR_IMAGES "oostubs" +#define DIR_PREREQUISITES "prerequisites" +#define PREREQUISITES 0 //1 == STEP1/2 -// 0 = vanilla, 1 = guarded, 2 = plausibility -#define WEATHERMONITOR_VARIANT 0 +#define WEATHER_NUMITER_TRACING 4 //same for all variants +#define WEATHER_NUMITER_AFTER 2 //same for all variants -#if WEATHERMONITOR_VARIANT == 0 // without vptr guards - -// suffix for simulator state, trace file -#define WEATHER_SUFFIX ".vanilla" -// main() address: -// nm -C vanilla.elf|fgrep main -#define WEATHER_FUNC_MAIN 0x00100d70 -// wait_begin address -#define WEATHER_FUNC_WAIT_BEGIN 0x00100d68 -// wait_end address -#define WEATHER_FUNC_WAIT_END 0x00100d6c -// vptr_panic address (only exists in guarded variant) -#define WEATHER_FUNC_VPTR_PANIC 0x99999999 -// number of main loop iterations to trace -// (determines trace length and therefore fault-space width) -#define WEATHER_NUMITER_TRACING 4 -// number of instructions needed for these iterations in golden run (taken from -// experiment step #2) -#define WEATHER_NUMINSTR_TRACING 20599 -// number of additional loop iterations for FI experiments (to see whether -// everything continues working fine) -#define WEATHER_NUMITER_AFTER 2 -// number of instructions needed for these iterations in golden run (taken from -// experiment step #2) -#define WEATHER_NUMINSTR_AFTER 10272 -// data/BSS begin: -// nm -C vanilla.elf|fgrep ___DATA_START__ -#define WEATHER_DATA_START 0x00101558 -// data/BSS end: -// nm -C vanilla.elf|fgrep ___BSS_END__ -#define WEATHER_DATA_END 0x00102e48 -// text begin: -// nm -C vanilla.elf|fgrep ___TEXT_START__ -#define WEATHER_TEXT_START 0x00100000 -// text end: -// nm -C vanilla.elf|fgrep ___TEXT_END__ -#define WEATHER_TEXT_END 0x0010139f - -#elif WEATHERMONITOR_VARIANT == 1 // with guards - -// suffix for simulator state, trace file -#define WEATHER_SUFFIX ".guarded" -// main() address: -// nm -C guarded.elf|fgrep main -#define WEATHER_FUNC_MAIN 0x00100dac -// wait_begin address -#define WEATHER_FUNC_WAIT_BEGIN 0x00100da4 -// wait_end address -#define WEATHER_FUNC_WAIT_END 0x00100da8 -// vptr_panic address (only exists in guarded variant) -#define WEATHER_FUNC_VPTR_PANIC 0x0010104c -// number of main loop iterations to trace -// (determines trace length and therefore fault-space width) -#define WEATHER_NUMITER_TRACING 4 -// number of instructions needed for these iterations in golden run (taken from -// experiment step #2) -#define WEATHER_NUMINSTR_TRACING 20599 -// number of additional loop iterations for FI experiments (to see whether -// everything continues working fine) -#define WEATHER_NUMITER_AFTER 2 -// number of instructions needed for these iterations in golden run (taken from -// experiment step #2) -#define WEATHER_NUMINSTR_AFTER 10272 -// data/BSS begin: -// nm -C guarded.elf|fgrep ___DATA_START__ -#define WEATHER_DATA_START 0x00101878 -// data/BSS end: -// nm -C guarded.elf|fgrep ___BSS_END__ -#define WEATHER_DATA_END 0x00103198 -// text begin: -// nm -C guarded.elf|fgrep ___TEXT_START__ -#define WEATHER_TEXT_START 0x00100000 -// text end: -// nm -C guarded.elf|fgrep ___TEXT_END__ -#define WEATHER_TEXT_END 0x001016af - -#elif WEATHERMONITOR_VARIANT == 2 // with guards + plausibility check - -// suffix for simulator state, trace file -#define WEATHER_SUFFIX ".plausibility" -// main() address: -// nm -C plausibility.elf|fgrep main -#define WEATHER_FUNC_MAIN 0x00100dbc -// wait_begin address -#define WEATHER_FUNC_WAIT_BEGIN 0x00100db4 -// wait_end address -#define WEATHER_FUNC_WAIT_END 0x00100db8 -// vptr_panic address (only exists in guarded variant) -#define WEATHER_FUNC_VPTR_PANIC 0x001010f0 -// number of main loop iterations to trace -// (determines trace length and therefore fault-space width) -#define WEATHER_NUMITER_TRACING 4 -// number of instructions needed for these iterations in golden run (taken from -// experiment step #2) -#define WEATHER_NUMINSTR_TRACING 20599 -// number of additional loop iterations for FI experiments (to see whether -// everything continues working fine) -#define WEATHER_NUMITER_AFTER 2 -// number of instructions needed for these iterations in golden run (taken from -// experiment step #2) -#define WEATHER_NUMINSTR_AFTER 10272 -// data/BSS begin: -// nm -C plausibility.elf|fgrep ___DATA_START__ -#define WEATHER_DATA_START 0x00101998 -// data/BSS end: -// nm -C plausibility.elf|fgrep ___BSS_END__ -#define WEATHER_DATA_END 0x001032b8 -// text begin: -// nm -C plausibility.elf|fgrep ___TEXT_START__ -#define WEATHER_TEXT_START 0x00100000 -// text end: -// nm -C plausibility.elf|fgrep ___TEXT_END__ -#define WEATHER_TEXT_END 0x001017cb - -#else -#error Unknown WEATHERMONITOR_VARIANT -#endif - -#endif diff --git a/src/experiments/weather-monitor/experimentInfo.hpp.sh b/src/experiments/weather-monitor/experimentInfo.hpp.sh deleted file mode 100755 index 25d79af4..00000000 --- a/src/experiments/weather-monitor/experimentInfo.hpp.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/bash -set -e -TARGET=experimentInfo.hpp - -[ ! -e "$1" -o ! -e "$2" -o ! -e "$3" ] && echo "usage: $0 vanilla.elf guarded.elf plausibility.elf" && exit 1 - -function addrof() { nm -C $1 | (fgrep "$2" || echo 99999999) | awk '{print $1}'; } - -cat >$TARGET <>$TARGET -cat >>$TARGET <>$TARGET -cat >>$TARGET <>$TARGET -cat >>$TARGET < +#include "sal/bochs/BochsCPU.hpp" +#include "sal/SALConfig.hpp" + + +using namespace std; +using namespace fail; + +bool Checkpoint::run() +{ + assert(!m_checking && "FATAL: Checkpoint plugin must not be added to simulation in checking mode"); + + // log information + m_log << "Checkpoint Logger started." << std::endl; + m_log << "Triggering on: " << m_symbol << std::endl; + m_log << "Writing output to: " << m_file << std::endl; + + /* + std::vector::const_iterator it = m_check_ranges.begin(); + for( ; it != m_check_ranges.end(); ++it) { + m_log << "Checksumming: " << + << ((it->first.second) ? "*" : "") + << "0x" << std::hex << it->first.first + << " - " << + << (it->second.second) ? "*" : "" + << "0x" << std::hex << it->second.first + << std::endl; + } + */ + + if (!m_ostream.is_open()) { + m_log << "No output file." << std::endl; + return false; + } + + // listen for memory writes and save checkpoints + MemWriteListener ev_mem(m_symbol.getAddress()); + while (true) { + simulator.addListenerAndResume(&ev_mem); + + save_checkpoint(ev_mem.getTriggerInstructionPointer()); + } + + return true; +} + +address_t Checkpoint::resolve_address(const indirectable_address_t &addr) { + if(addr.second) { + const address_t paddr = addr.first; + address_t value = 0; + + MemoryManager& mm = simulator.getMemoryManager(); + + if(mm.isMapped(paddr) && mm.isMapped(paddr+1) && mm.isMapped(paddr+2) && mm.isMapped(paddr+3)) { + simulator.getMemoryManager().getBytes(paddr, 4, &value); + } + + // HACK/WORKAROUND for dOSEK, which uses bit 31 for parity! + // This fixes checkpoint ranges for dOSEK, but breaks other systems *if* + // addresses with bit 31 set are used as the limit for checkpoint regions + return value & ~(1<<31); + } else { + return addr.first; + } +} + +void Checkpoint::checksum(uint8_t (&Message_Digest)[20]) +{ + SHA1Context sha; + int err; + + // prepare SHA1 hash + err = SHA1Reset(&sha); + assert(err == 0); + + MemoryManager& mm = simulator.getMemoryManager(); + + // disable paging on x86 + #ifdef BUILD_X86 + const Register *reg_cr0 = simulator.getCPU(0).getRegister(RID_CR0); + uint32_t cr0 = simulator.getCPU(0).getRegisterContent(reg_cr0); + simulator.getCPU(0).setRegisterContent(reg_cr0, cr0 & ~(1<<31)); + #endif + + // iterate memory regions + std::vector::const_iterator it = m_check_ranges.begin(); + for( ; it != m_check_ranges.end(); ++it) { + fail::address_t start = resolve_address(it->first); + fail::address_t end = resolve_address(it->second); + + if((start == 0) || (end == 0)) { + m_log << std::hex << "invalid checksum range pointer" << std::endl; + continue; + } + + //m_log << std::hex << "checksumming 0x" << start << " - 0x" << end << std::endl; + + for(fail::address_t addr = start; addr < end; addr++) { + if(mm.isMapped(addr)) { + // read byte + uint8_t data = mm.getByte(addr); + // add to hash + err = SHA1Input(&sha, &data, 1); + } else { + err = SHA1Input(&sha, (uint8_t*) &addr, 4); + } + + assert(err == 0); + } + } + + // restore paging on x86 + #ifdef BUILD_X86 + simulator.getCPU(0).setRegisterContent(reg_cr0, cr0); + #endif + + // complete hash + err = SHA1Result(&sha, Message_Digest); + assert(err == 0); +} + +void Checkpoint::checkpoint(const fail::ElfSymbol symbol, + uint32_t &value, + fail::simtime_t &simtime, + std::string &digest_str) +{ + // increment checkpoint count + m_count++; + + // timestamp + simtime = simulator.getTimerTicks(); + + // written value + address_t addr = symbol.getAddress(); + MemoryManager& mm = simulator.getMemoryManager(); + if(mm.isMapped(addr) && mm.isMapped(addr+1) && mm.isMapped(addr+2) && mm.isMapped(addr+3)) { + mm.getBytes(symbol.getAddress(), symbol.getSize(), &value); + } else { + value = 0xDEADBEEF; // TODO: invalid value? + } + + // checksum + uint8_t digest[20]; + checksum(digest); + + // checksum to string + std::stringstream s; + s.fill('0'); + for ( size_t i = 0 ; i < 20 ; ++i ) + s << std::setw(2) << std::hex <<(unsigned short)digest[i]; + digest_str = s.str(); +} + +void Checkpoint::save_checkpoint(fail::address_t ip) +{ + uint32_t value; + fail::simtime_t simtime; + std::string digest; + + // get checkpoint info + checkpoint(m_symbol, value, simtime, digest); + + // log checkpoint + m_log << std::dec << "Checkpoint " << m_count << " @ " << simtime << std::endl; + + // write checkpoint + if (m_ostream.is_open()) { + m_ostream << std::hex << ip << "\t" << std::dec << simtime << "\t" << value << "\t" << digest << std::endl; + } else { + m_log << "Output error" << std::endl; + } +} + +Checkpoint::check_result Checkpoint::check(const fail::ElfSymbol symbol, fail::address_t ip) +{ + uint32_t value; + fail::simtime_t simtime; + std::string digest; + + address_t golden_ip; + uint32_t golden_timestamp; + uint32_t golden_value; + char golden_digest_hex[41]; + + assert(m_checking && "FATAL: Checkpoint plugin cannot check in tracing mode"); + + // get checkpoint info + checkpoint(symbol, value, simtime, digest); + + // check with log + if (!m_istream.is_open()) { + m_log << "Input file not open!" << std::endl; + return INVALID; + } + if (m_istream.eof()) { + m_log << "Checkpoint after last golden checkpoint!" << std::endl; + return INVALID; + } + + // read golden values + m_istream >> std::hex >> golden_ip; + m_istream >> std::dec >> golden_timestamp; + m_istream >> std::dec >> golden_value; + m_istream.width(41); + m_istream >> golden_digest_hex; + std::string golden_digest = golden_digest_hex; + + + //bool same_timestamp = simtime == golden_timestamp); + bool same_ip = ip == golden_ip; + bool same_value = value == golden_value; + bool same_digest = digest == golden_digest; + + if (!same_ip || !same_value || !same_digest) { + // log + m_log << "GOLDEN:" << std::hex << golden_ip << "\t" << std::dec << golden_timestamp << "\t" << golden_value << "\t" << golden_digest << std::endl; + m_log << "TEST: " << std::hex << ip << "\t" << std::dec << simtime << "\t" << value << "\t" << digest << std::endl; + } + + + if(!same_value) return DIFFERENT_VALUE; + if(!same_ip) return DIFFERENT_IP; + if(!same_digest) return DIFFERENT_DIGEST; + + return IDENTICAL; +} diff --git a/src/plugins/checkpoint/Checkpoint.hpp b/src/plugins/checkpoint/Checkpoint.hpp new file mode 100644 index 00000000..7cd2aa79 --- /dev/null +++ b/src/plugins/checkpoint/Checkpoint.hpp @@ -0,0 +1,117 @@ +#ifndef __Checkpoint_HPP__ +#define __Checkpoint_HPP__ + +#include +#include +#include +#include +#include "efw/ExperimentFlow.hpp" +#include "config/FailConfig.hpp" +#include "util/Logger.hpp" +#include +#include "util/ElfReader.hpp" + +/** + * @class Checkpoint + * @brief Listens to a memory location and outputs instruction pointer, written value, + * timestamp and SHA1 hash of memory regions to file on each write access from SUT + */ +class Checkpoint : public fail::ExperimentFlow +{ +public: + typedef std::pair indirectable_address_t; //!< fixed address or pointer to address + typedef std::pair address_range; //!< contiguous memory region + typedef std::vector range_vector; //!< vector of memory regions + + enum check_result { + IDENTICAL, + DIFFERENT_IP, + DIFFERENT_VALUE, + DIFFERENT_DIGEST, + INVALID + }; + +private: + const fail::ElfSymbol m_symbol; //!< target memory symbol triggering checkpoints + const range_vector m_check_ranges; //!< address ranges to checksum + const bool m_checking; //!< checking mode (when false: tracing mode) + std::string m_file; //!< the input/output filename + fail::Logger m_log; //!< debug output + std::ofstream m_ostream; //!< outputfile stream + std::ifstream m_istream; //!< inputfile stream + unsigned m_count; + +public: + /** + * Construct Checkpoint Logger in tracing (output) mode. + * + * @param symbol The global memory address the plugin listens to + * @param check_ranges Address ranges which are included in the saved checksum + * @param outputfile The path to the file to write the checkpoints + */ + Checkpoint(const fail::ElfSymbol & symbol, + const std::vector check_ranges, + const std::string& outputfile) : + m_symbol(symbol), m_check_ranges(check_ranges), m_checking(false), + m_file(outputfile) , m_log("CPLogger", false), m_count(0) + { + m_ostream.open(m_file.c_str() ); + if (!m_ostream.is_open()) { + m_log << "Could not open " << m_file.c_str() << " for writing." << std::endl; + } + } + + /** + * Construct Checkpoint Logger in checking (input) mode. + * + * @param symbol The global memory address the plugin listens to + * @param check_ranges Address ranges which are compared to the saved checksum + * @param inputfile The path to the file to read in checkpoints + */ + Checkpoint(const std::vector check_ranges, + const std::string& inputfile) : + m_check_ranges(check_ranges), m_checking(true), m_file(inputfile), + m_log("CPLogger", false), m_count(0) + { + m_istream.open(m_file.c_str() ); + if (!m_istream.is_open()) { + m_log << "Could not open " << m_file.c_str() << " for reading." << std::endl; + } + } + + //! How many checkpoints have been triggered so far + unsigned getCount() const { + return m_count; + } + + //! Start plugin control flow for tracing mode. Do not call in checking mode! + bool run(); + + /** + * Perform a check against saved checkpoints. Call this method in experiment when + * a MemWriteBreakpoint on symbol triggers. + * + * @param symbol (memory) symbol which triggered checkpoint + * @param ip instruction pointer which triggered checkpoint + * @return check result + */ + check_result check(const fail::ElfSymbol symbol, fail::address_t ip); + +private: + //! calulate checksum over memory regions + void checksum(uint8_t (&Message_Digest)[20]); + + //! extract checkpoint information from simulation + void checkpoint(const fail::ElfSymbol symbol, + uint32_t &value, + fail::simtime_t &simtime, + std::string &digest_str); + + //! save checkpoint to file + void save_checkpoint(fail::address_t ip); + + //! get value of indirectable_address_t + fail::address_t resolve_address(const indirectable_address_t &addr); +}; + +#endif // __Checkpoint_HPP__ diff --git a/src/plugins/checkpoint/sha1.c b/src/plugins/checkpoint/sha1.c new file mode 100644 index 00000000..9df1a20c --- /dev/null +++ b/src/plugins/checkpoint/sha1.c @@ -0,0 +1,392 @@ +/* + * sha1.c + * + * Copyright (C) The Internet Society (2001). All Rights Reserved. + * This file is taken from RFC3174. + * + * Description: + * This file implements the Secure Hashing Algorithm 1 as + * defined in FIPS PUB 180-1 published April 17, 1995. + * + * The SHA-1, produces a 160-bit message digest for a given + * data stream. It should take about 2**n steps to find a + * message with the same digest as a given message and + * 2**(n/2) to find any two messages with the same digest, + * when n is the digest size in bits. Therefore, this + * algorithm can serve as a means of providing a + * "fingerprint" for a message. + * + * Portability Issues: + * SHA-1 is defined in terms of 32-bit "words". This code + * uses (included via "sha1.h" to define 32 and 8 + * bit unsigned integer types. If your C compiler does not + * support 32 bit unsigned integers, this code is not + * appropriate. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. Although SHA-1 allows a message digest to be generated + * for messages of any number of bits less than 2^64, this + * implementation only works with messages with a length that is + * a multiple of the size of an 8-bit character. + * + */ + +#include "sha1.h" + +/* + * Define the SHA1 circular left shift macro + */ +#define SHA1CircularShift(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) + +/* Local Function Prototyptes */ +void SHA1PadMessage(SHA1Context *); +void SHA1ProcessMessageBlock(SHA1Context *); + +/* + * SHA1Reset + * + * Description: + * This function will initialize the SHA1Context in preparation + * for computing a new SHA1 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Reset(SHA1Context *context) +{ + if (!context) + { + return shaNull; + } + + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Intermediate_Hash[0] = 0x67452301; + context->Intermediate_Hash[1] = 0xEFCDAB89; + context->Intermediate_Hash[2] = 0x98BADCFE; + context->Intermediate_Hash[3] = 0x10325476; + context->Intermediate_Hash[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = 0; + + return shaSuccess; +} + +/* + * SHA1Result + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 19th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Result( SHA1Context *context, + uint8_t Message_Digest[SHA1HashSize]) +{ + int i; + + if (!context || !Message_Digest) + { + return shaNull; + } + + if (context->Corrupted) + { + return context->Corrupted; + } + + if (!context->Computed) + { + SHA1PadMessage(context); + for(i=0; i<64; ++i) + { + /* message may be sensitive, clear it out */ + context->Message_Block[i] = 0; + } + context->Length_Low = 0; /* and clear length */ + context->Length_High = 0; + context->Computed = 1; + + } + + for(i = 0; i < SHA1HashSize; ++i) + { + Message_Digest[i] = context->Intermediate_Hash[i>>2] + >> 8 * ( 3 - ( i & 0x03 ) ); + } + + return shaSuccess; +} + +/* + * SHA1Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int SHA1Input( SHA1Context *context, + const uint8_t *message_array, + unsigned length) +{ + if (!length) + { + return shaSuccess; + } + + if (!context || !message_array) + { + return shaNull; + } + + if (context->Computed) + { + context->Corrupted = shaStateError; + + return shaStateError; + } + + if (context->Corrupted) + { + return context->Corrupted; + } + while(length-- && !context->Corrupted) + { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + context->Length_Low += 8; + if (context->Length_Low == 0) + { + context->Length_High++; + if (context->Length_High == 0) + { + /* Message is too long */ + context->Corrupted = 1; + } + } + + if (context->Message_Block_Index == 64) + { + SHA1ProcessMessageBlock(context); + } + + message_array++; + } + + return shaSuccess; +} + +/* + * SHA1ProcessMessageBlock + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the publication. + * + * + */ +void SHA1ProcessMessageBlock(SHA1Context *context) +{ + const uint32_t K[] = { /* Constants defined in SHA-1 */ + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ + uint32_t W[80]; /* Word sequence */ + uint32_t A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for(t = 0; t < 16; t++) + { + W[t] = context->Message_Block[t * 4] << 24; + W[t] |= context->Message_Block[t * 4 + 1] << 16; + W[t] |= context->Message_Block[t * 4 + 2] << 8; + W[t] |= context->Message_Block[t * 4 + 3]; + } + + for(t = 16; t < 80; t++) + { + W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + + for(t = 0; t < 20; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + + B = A; + A = temp; + } + + for(t = 20; t < 40; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 40; t < 60; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 60; t < 80; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + + context->Message_Block_Index = 0; +} + +/* + * SHA1PadMessage + * + + * Description: + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call the ProcessMessageBlock function + * provided appropriately. When it returns, it can be assumed that + * the message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * ProcessMessageBlock: [in] + * The appropriate SHA*ProcessMessageBlock function + * Returns: + * Nothing. + * + */ + +void SHA1PadMessage(SHA1Context *context) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index > 55) + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 64) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + + SHA1ProcessMessageBlock(context); + + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + else + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 56) + { + + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = context->Length_High >> 24; + context->Message_Block[57] = context->Length_High >> 16; + context->Message_Block[58] = context->Length_High >> 8; + context->Message_Block[59] = context->Length_High; + context->Message_Block[60] = context->Length_Low >> 24; + context->Message_Block[61] = context->Length_Low >> 16; + context->Message_Block[62] = context->Length_Low >> 8; + context->Message_Block[63] = context->Length_Low; + + SHA1ProcessMessageBlock(context); +} diff --git a/src/plugins/checkpoint/sha1.h b/src/plugins/checkpoint/sha1.h new file mode 100644 index 00000000..9569ae3d --- /dev/null +++ b/src/plugins/checkpoint/sha1.h @@ -0,0 +1,72 @@ +/* + * sha1.h + * + * Description: + * This is the header file for code which implements the Secure + * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published + * April 17, 1995. + * + * Many of the variable names in this code, especially the + * single character names, were used because those were the names + * used in the publication. + * + * Please read the file sha1.c for more information. + * + */ + +#ifndef _SHA1_H_ +#define _SHA1_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef _SHA_enum_ +#define _SHA_enum_ +enum +{ + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError /* called Input after Result */ +}; +#endif +#define SHA1HashSize 20 + +/* + * This structure will hold context information for the SHA-1 + * hashing operation + */ +typedef struct SHA1Context +{ + uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ + + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + + /* Index into message block array */ + int_least16_t Message_Block_Index; + uint8_t Message_Block[64]; /* 512-bit message blocks */ + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the message digest corrupted? */ +} SHA1Context; + +/* + * Function Prototypes + */ + +int SHA1Reset( SHA1Context *); +int SHA1Input( SHA1Context *, + const uint8_t *, + unsigned int); +int SHA1Result( SHA1Context *, + uint8_t Message_Digest[SHA1HashSize]); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/plugins/serialoutput/SerialOutputLogger.cc b/src/plugins/serialoutput/SerialOutputLogger.cc index 8f5a2f54..0d79517c 100644 --- a/src/plugins/serialoutput/SerialOutputLogger.cc +++ b/src/plugins/serialoutput/SerialOutputLogger.cc @@ -10,7 +10,7 @@ bool SerialOutputLogger::run() while (true) { simulator.addListener(&ev_ioport); simulator.resume(); - if (m_output.size() < m_limit) { + if (m_limit == 0 || m_output.size() < m_limit) { m_output += ev_ioport.getData(); } } diff --git a/tools/analysis/VisualFAIL/CONFIGURATION.php.dist b/tools/analysis/VisualFAIL/CONFIGURATION.php.dist new file mode 100644 index 00000000..6215963e --- /dev/null +++ b/tools/analysis/VisualFAIL/CONFIGURATION.php.dist @@ -0,0 +1,10 @@ + diff --git a/tools/analysis/VisualFAIL/README.md b/tools/analysis/VisualFAIL/README.md new file mode 100644 index 00000000..1a5ee4d1 --- /dev/null +++ b/tools/analysis/VisualFAIL/README.md @@ -0,0 +1,64 @@ +VisualFail* +=========== + +Guest-system setup +------------------ +For analysis with VisualFail*, the guest-system ELF binary must be compiled with +debugging information (gcc/g++/clang/clang++ compiler flag "-g"). Note that +debugging information quality/accuracy usually decreases with higher +optimization levels. + +Database preparation +-------------------- +1. import-trace -t yourtrace.tc -i MemoryImporter +2. import-trace -t yourtrace.tc -i FullTraceImporter +3. import-trace -t yourtrace.tc -i ElfImporter -e yourbinary.elf --objdump $(which objdump) --sources + +Step 1 is the prerequisite to run the fault-injection campaign (you may use +other importers as well, e.g., the RegisterImporter). Steps 2 and 3 are +required for VisualFail* to work. + +Setup +----- +Copy CONFIGURATION.php.dist to CONFIGURATION.php, edit it, and add your MySQL +database credentials and the result-table name (usually starting with +"result...", "echo SHOW TABLES | mysql yourdatabase" on the command line should +give you the correct table name). + +(In a later version of VisualFail*, we will probably add automatic loading of +~/.my.cnf if available.) + +Running and using VisualFail* +----------------------------- +./StartVF.sh requires PHP 5.4.0 or newer and uses its simple built-in web +server. You can connect to it by using http://localhost:1234 in a web browser +on the same machine. (If you need to connect from another machine, manually run +"php -S 0.0.0.0:1234 -t .") + +Alternatively, VisualFail* can be set up using a "real" web server with a recent +PHP version (5.x should suffice). + +Once the web server runs, you can use VisualFail*: + +- Pick a coloring (currently, only "Right margin" really makes sense), a + benchmark and a variant from the drop-down menus. Click "Analyze". Wait. + +- Enable the experiment result types you want to highlight by clicking them in + the top row. + +- Scroll down the left column with the disassembled machine code. Instructions + that activated faults in the FI experiments, and led to one of the enabled + result types, are highlighted with red color. The stronger the coloring, the + more experiments led to one of these failure modes. (Actually, not the raw + number of actual experiments is used, but is weighted with the size of the + corresponding def/use equivalence class.) + +- Click one of the highlighted instructions to display a popup with the actual + result numbers, and the distribution among the different failure modes. + +- Pick a source-code file from the right-hand side pulldown to look into the + instructions generated from that file. The right column now contains the + source code from that file, interspersed with the disassembled machine code + generated from it. These disassembled machine-code lines are, just like in + the disassembly column, clickable to display details. (The source-code lines + are currently not clickable, although the mouse cursor indicates otherwise.) diff --git a/tools/analysis/VisualFAIL/StartVF.sh b/tools/analysis/VisualFAIL/StartVF.sh new file mode 100755 index 00000000..674f1d14 --- /dev/null +++ b/tools/analysis/VisualFAIL/StartVF.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# +# Starts VisualFAIL over php on Port 1234 +# + +php -S localhost:1234 -t . diff --git a/tools/analysis/VisualFAIL/core.php b/tools/analysis/VisualFAIL/core.php new file mode 100644 index 00000000..b5abd96b --- /dev/null +++ b/tools/analysis/VisualFAIL/core.php @@ -0,0 +1,507 @@ +'); + return; + } + + $abfrage = "SELECT 1 FROM fulltrace;"; + + $ergebnis = mysql_query($abfrage); + + if (!$ergebnis) { + echo json_encode('Tabelle fulltrace nicht gefunden
'); + return; + } + + $abfrage = "SELECT 1 FROM dbg_filename;"; + + $ergebnis = mysql_query($abfrage); + + if (!$ergebnis) { + echo json_encode('Tabelle dbg_filename nicht gefunden
'); + return; + } + + $abfrage = "SELECT 1 FROM dbg_mapping;"; + + $ergebnis = mysql_query($abfrage); + + if (!$ergebnis) { + echo json_encode('Tabelle dbg_mapping nicht gefunden
'); + return; + } + +/* + $abfrage = "SELECT 1 FROM dbg_methods;"; + + $ergebnis = mysql_query($abfrage); + + if (!$ergebnis) { + echo json_encode('Tabelle dbg_methods nicht gefunden
'); + return; + } +*/ + + $abfrage = "SELECT 1 FROM dbg_source;"; + + $ergebnis = mysql_query($abfrage); + + if (!$ergebnis) { + echo json_encode('Tabelle dbg_source nicht gefunden
'); + return; + } + +/* + $abfrage = "SELECT 1 FROM dbg_stacktrace;"; + + $ergebnis = mysql_query($abfrage); + + if (!$ergebnis) { + echo json_encode('Tabelle dbg_stacktrace nicht gefunden
'); + return; + } + + $abfrage = "SELECT 1 FROM dbg_variables;"; + + $ergebnis = mysql_query($abfrage); + + if (!$ergebnis) { + echo json_encode('Tabelle dbg_variables nicht gefunden
'); + return; + } +*/ +} + +function getBinarys() +{ + $binarys = array(); + + $abfrage = "SELECT benchmark FROM variant;"; + + $ergebnis = mysql_query($abfrage); + + while ($row = mysql_fetch_object($ergebnis)) { + array_push($binarys, $row->benchmark); + } + + $result = array_unique($binarys); + + echo json_encode($result); +} + +function getVariants() +{ + $variants = array(); + + $abfrage = "SELECT id, variant FROM variant WHERE benchmark = '" . $_GET['datei'] ."';"; + + $ergebnis = mysql_query($abfrage); + + while ($row = mysql_fetch_object($ergebnis)) { + $variants[$row->id] = $row->variant; + } + + echo json_encode($variants); +} + +function remove_common_prefix($files) +{ + if (count($files) == 0) { + return array(); + } + + // start with arbitrary file + $commonprefix = dirname(current($files)); + + foreach ($files AS $id => $file) { + for ($i = 0; $i < strlen($commonprefix); ++$i) { + if ($i >= strlen($file) || $file[$i] != $commonprefix[$i]) { + $commonprefix = substr($commonprefix, 0, $i); + break; + } + } + if (strlen($commonprefix) == 0) { + break; + } + } + + $out = array(); + foreach ($files AS $id => $file) { + $out[$id] = substr($file, strlen($commonprefix)); + } + + return $out; +} + +function getSourceFiles() +{ + $sourceFiles = array(); + + $abfrage = "SELECT file_id, path FROM dbg_filename WHERE variant_id = '" . $_GET['variant_id']. "';"; + + $ergebnis = mysql_query($abfrage); + + while ($row = mysql_fetch_object($ergebnis)) { + $sourceFiles[$row->file_id] = $row->path; + } + + $sourceFiles = remove_common_prefix($sourceFiles); + + echo json_encode($sourceFiles); +} + +function asmCode() +{ + $content = ""; + + $abfrage = "SELECT instr_address, disassemble FROM objdump WHERE variant_id = '" . $_GET['variant_id'] ."' ORDER BY instr_address;"; + + $ergebnis = mysql_query($abfrage); + + $content = $content; + while ($row = mysql_fetch_object($ergebnis)) { + $content .= dechex($row->instr_address) . '
'; + } + echo json_encode($content); +} + +function collapse_repeated($html, $disasm, $force_finish) +{ + static $last_disasm = ''; + static $collect = array(); + $limit_before = $limit_after = 3; + + $out = ''; + if ($force_finish || $last_disasm != $disasm) { + if (count($collect) > $limit_before + $limit_after + 1) { + for ($i = 0; $i < $limit_before; ++$i) { + $out .= $collect[$i]; + } + $out .= '-- omitted ' . (count($collect) - $limit_before - $limit_after) . " repetitions of '$last_disasm'
"; + for ($i = count($collect) - $limit_after; $i < count($collect); ++$i) { + $out .= $collect[$i]; + } + } else { + $out = implode('', $collect); + } + $last_disasm = $disasm; + $collect = array(); + } + + if ($force_finish) { + $out .= $html; + } else { + $collect[] = $html; + } + + return $out; +} + +function getAsmCode() +{ + $content = ""; + $resulttypes = array(); + + $asmAbfrage = "SELECT instr_address, disassemble FROM objdump WHERE variant_id = '" . $_GET['variant_id'] ."' ORDER BY instr_address;"; + + $asmcode = mysql_query($asmAbfrage); + + getResulttypes($resulttypes); + + $fehlerdaten = resultsDB($_GET['variant_id'], $_GET['version'], $resulttypes); + //$fehlerdaten = askDBFehler($_GET['variant_id'], $resulttypes, $_GET['version']); + + //print_r($fehlerdaten); + // FIXME id not unique + $content = '
instr_address,$fehlerdaten['Daten'])) { + $line = 'instr_address) . ' ' . htmlspecialchars($row->disassemble) . '
'; + $content .= collapse_repeated($line, 'dontcare', true); + } else { + $line = dechex($row->instr_address) . ' ' . htmlspecialchars($row->disassemble) . '
'; + $content .= collapse_repeated($line, htmlspecialchars($row->disassemble), false); + } + } + $content .= collapse_repeated('', '', true); + $content .= '
'; + + echo json_encode($content); +} + +function getHighlevelCode() +{ + $content = ""; + $resulttypes = array(); + + getResulttypes($resulttypes); + + $kleinsteAdresseAbfrage = "SELECT MIN(instr_address) AS instr_address FROM objdump WHERE variant_id = " . $_GET['variant_id']; + $kleinsteAdresseErgebnis = mysql_query($kleinsteAdresseAbfrage) or trigger_error($kleinsteAdresseAbfrage, E_USER_NOTICE); + $kleinsteAdresse = mysql_fetch_object($kleinsteAdresseErgebnis); + + $highlevelCodeAbfrage = "SELECT linenumber, line FROM dbg_source WHERE variant_id = '" . $_GET['variant_id']. "' AND file_id = '" . $_GET['file_id']. "' ORDER BY linenumber;"; + $mappingAbfrage = "SELECT linenumber, instr_absolute, line_range_size FROM dbg_mapping WHERE variant_id = '" . $_GET['variant_id']. "' AND file_id = '" . $_GET['file_id'] . "' AND instr_absolute >= '" . $kleinsteAdresse->instr_address . "' ORDER BY instr_absolute;"; + + $highlevelCode = mysql_query($highlevelCodeAbfrage); + $mappingInfo = mysql_query($mappingAbfrage); + + $fehlerdaten = resultsDB($_GET['variant_id'], $_GET['version'], $resulttypes); + + // retrieve mapping of linenumber -> array of [start-address;end-address) ranges + $mappingRanges = array(); + while (($row = mysql_fetch_object($mappingInfo))) { + if (!isset($mappingRanges[$row->linenumber])) { + $mappingRanges[$row->linenumber] = array(); + } + $mappingRanges[$row->linenumber][] = + array(intval($row->instr_absolute), + $row->instr_absolute + $row->line_range_size); + } + + $mapping = array(); + // "maxFehler" should be "sumFehler" or alike + $maxFehlerMapping = array(); + + foreach ($mappingRanges as $lineNumber => $value) { + $maxFehler = array(); + foreach ($resulttypes as $val) { + $maxFehler[$val] = 0; + } + foreach ($value as $index => $ranges) { + // was ">" instead of ">=" before + $InstrMappingAbfrage = "SELECT instr_address, disassemble FROM objdump WHERE variant_id = '" . $_GET['variant_id']. "' AND instr_address >= '" . $ranges[0] . "' AND instr_address < '" . $ranges[1] . "' ORDER BY instr_address;"; + $mappingErgebnis = mysql_query($InstrMappingAbfrage); + while ($row = mysql_fetch_object($mappingErgebnis)) { + if (array_key_exists($row->instr_address,$fehlerdaten['Daten'])) { + $newline = 'instr_address][$value]; + } + + $newline .= ' style="cursor: pointer;">' . dechex($row->instr_address) . ' ' . htmlspecialchars($row->disassemble) . '
'; + $newline = collapse_repeated($newline, 'dontcare', true); + } else { + $newline = dechex($row->instr_address) . ' ' . htmlspecialchars($row->disassemble) . '
'; + $newline = collapse_repeated($newline, htmlspecialchars($row->disassemble), false); + } + $mapping[$lineNumber] [] = $newline; + } + $mapping[$lineNumber] [] = collapse_repeated('', '', true); + } + foreach ($resulttypes as $value) { + $maxFehlerMapping[$lineNumber][$value] = $maxFehler[$value]; + } + } + + while ($row = mysql_fetch_object($highlevelCode)) { + // FIXME id unique? + $content .= '' . $row->linenumber . ' : ' . $row->line . '
'; + if (array_key_exists($row->linenumber, $mapping)) { + $content .= '
'; + foreach ($mapping[$row->linenumber] as $index => $span) { + $content .= $span; + } + $content .= '
resulttype; + array_push($resulttypes, $row->resulttype); + } +} + +function getResulttypesOUT() +{ + $resulttypes = array(); + + $abfrage = "SELECT resulttype FROM " . $GLOBALS['result_table'] . " GROUP BY resulttype;"; + + $ergebnis = mysql_query($abfrage); + + while ($row = mysql_fetch_object($ergebnis)) { + //echo $row->resulttype; + array_push($resulttypes, $row->resulttype); + } + + echo json_encode($resulttypes); +} + +function askDBFehler($variant_id, $resulttypes, $version) +{ + if ($version == 'onlyRightEdge') { + // we don't need fulltrace here at all + $abfrage = "SELECT t.instr2 AS instr, t.instr2_absolute AS instr_absolute"; + foreach ( $resulttypes as $value) { + $abfrage .= ", SUM(IF(r.resulttype = '" . $value . "', 1, 0)*(t.time2-t.time1+1)) AS " . $value; + } + $abfrage .= " FROM trace t + JOIN fsppilot p + ON t.variant_id = p.variant_id + AND t.data_address = p.data_address + AND p.instr2 = t.instr2 + JOIN " . $GLOBALS['result_table'] . " r + ON p.id = r.pilot_id + WHERE t.variant_id = $variant_id + AND t.accesstype = 'R' + GROUP BY t.instr2_absolute;"; + } else if ($version == 'latestip') { + $abfrage = "SELECT r.latest_ip "; + foreach ( $resulttypes as $value) { + $abfrage .= ", SUM(IF(r.resulttype = '" . $value . "', 1, 0)*(t.time2-t.time1+1)) AS " . $value; + } + $abfrage .= " FROM trace t + JOIN fsppilot p + ON t.variant_id = p.variant_id + AND t.data_address = p.data_address + AND p.instr2 = t.instr2 + JOIN " . $GLOBALS['result_table'] . " r + ON p.id = r.pilot_id + WHERE t.variant_id = '" . $variant_id . "' AND t.accesstype = 'R' + GROUP BY r.latest_ip;"; + } else { + $abfrage = "SELECT ft.instr, ft.instr_absolute "; + foreach ( $resulttypes as $value) { + $abfrage .= ", SUM(IF(r.resulttype = '" . $value . "', 1, 0)*(t.time2-t.time1+1)) AS " . $value; + } + $abfrage .= " FROM fulltrace ft + LEFT JOIN trace t + ON ft.variant_id = '" . $variant_id . "' + AND t.variant_id = '" . $variant_id . "' + AND ft.instr BETWEEN t.instr1 AND t.instr2 + AND t.accesstype = 'R' + JOIN fsppilot p + ON t.variant_id = '" . $variant_id . "' + AND p.variant_id = '" . $variant_id . "' + AND t.data_address = p.data_address + AND p.instr2 = t.instr2 + JOIN " . $GLOBALS['result_table'] . " r + ON p.id = r.pilot_id + GROUP BY ft.instr_absolute;"; + } + + //echo $abfrage; + + $ergebnis = mysql_query($abfrage); + + return $ergebnis; +} + +function resultsDB($variant_id, $version, $resulttypes) +{ + getResulttypes($resulttypes); + + //print_r($resulttypes); + + $ergebnis = askDBFehler($variant_id, $resulttypes, $version); + + //print_r($ergebnis); + + $results = array(); + + // We find the fields number + $numfields=mysql_num_fields($ergebnis); + + for ($i=0; $i < $numfields; $i++) { + $fieldname[$i]=mysql_field_name($ergebnis, $i); + } + + for ($i=2; $i < $numfields; $i++) { + $results["max"][$fieldname[$i]] = 0; + } + + $maxFehler = 0; + while ($row = mysql_fetch_object($ergebnis)) { + if ($version != 'latestip') { + if ($row->instr_absolute != NULL) { + $results["Daten"][$row->instr_absolute] = array(); + for ($i = 2; $i < $numfields ; $i++) { + $results["Daten"][$row->instr_absolute][$fieldname[$i]] = $row->$fieldname[$i]; + + if ($row->$fieldname[$i] > $results["max"][$fieldname[$i]]) { + $results["max"][$fieldname[$i]] = $row->$fieldname[$i]; + } + } + } + } else { + if ($row->latest_ip != NULL) { + $results["Daten"][$row->latest_ip] = array(); + for ($i = 0 ; $i < $numfields ; $i++) { + $results["Daten"][$row->latest_ip][$fieldname[$i]] = $row->$fieldname[$i]; + + if ($row->$fieldname[$i] > $results["max"][$fieldname[$i]]) { + $results["max"][$fieldname[$i]] = $row->$fieldname[$i]; + } + } + } + } + } + + return $results; +} + +?> diff --git a/tools/analysis/VisualFAIL/css/bootstrap-theme.css b/tools/analysis/VisualFAIL/css/bootstrap-theme.css new file mode 100644 index 00000000..df2d3d96 --- /dev/null +++ b/tools/analysis/VisualFAIL/css/bootstrap-theme.css @@ -0,0 +1,397 @@ +/*! + * Bootstrap v3.0.3 (http://getbootstrap.com) + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + */ + +.btn-default, +.btn-primary, +.btn-success, +.btn-info, +.btn-warning, +.btn-danger { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 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, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 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, #ffffff 0%, #e0e0e0 100%); + background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%); + background-repeat: repeat-x; + border-color: #dbdbdb; + border-color: #ccc; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.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-primary { + background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%); + background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%); + background-repeat: repeat-x; + border-color: #2b669a; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.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-success { + background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); + background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); + background-repeat: repeat-x; + border-color: #3e8f3e; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.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-warning { + background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); + background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); + background-repeat: repeat-x; + border-color: #e38d13; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.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-danger { + background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); + background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); + background-repeat: repeat-x; + border-color: #b92c28; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.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-info { + background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); + background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); + background-repeat: repeat-x; + border-color: #28a4c9; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.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; +} + +.thumbnail, +.img-thumbnail { + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 2px rgba(0, 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: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); +} + +.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: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); +} + +.navbar-default { + background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%); + background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%); + background-repeat: repeat-x; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); +} + +.navbar-default .navbar-nav > .active > a { + background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); + background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0); + -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); +} + +.navbar-brand, +.navbar-nav > li > a { + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); +} + +.navbar-inverse { + background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%); + background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.navbar-inverse .navbar-nav > .active > a { + background-image: -webkit-linear-gradient(top, #222222 0%, #282828 100%); + background-image: linear-gradient(to bottom, #222222 0%, #282828 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0); + -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); + box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); +} + +.navbar-inverse .navbar-brand, +.navbar-inverse .navbar-nav > li > a { + text-shadow: 0 -1px 0 rgba(0, 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, 0.2); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.alert-success { + background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); + background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); + background-repeat: repeat-x; + border-color: #b2dba1; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); +} + +.alert-info { + background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); + background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); + background-repeat: repeat-x; + border-color: #9acfea; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); +} + +.alert-warning { + background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); + background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); + background-repeat: repeat-x; + border-color: #f5e79e; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); +} + +.alert-danger { + background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); + background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); + background-repeat: repeat-x; + border-color: #dca7a7; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); +} + +.progress { + background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); + background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); +} + +.progress-bar { + background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%); + background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); +} + +.progress-bar-success { + background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); + background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); +} + +.progress-bar-info { + background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); + background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); +} + +.progress-bar-warning { + background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); + background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); +} + +.progress-bar-danger { + background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); + background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); +} + +.list-group { + border-radius: 4px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 2px rgba(0, 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: linear-gradient(to bottom, #428bca 0%, #3278b3 100%); + background-repeat: repeat-x; + border-color: #3278b3; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0); +} + +.panel { + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.panel-default > .panel-heading { + background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); + background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); +} + +.panel-primary > .panel-heading { + background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); + background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); +} + +.panel-success > .panel-heading { + background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); + background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); +} + +.panel-info > .panel-heading { + background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); + background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); +} + +.panel-warning > .panel-heading { + background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); + background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); +} + +.panel-danger > .panel-heading { + background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); + background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); +} + +.well { + background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); + background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); + background-repeat: repeat-x; + border-color: #dcdcdc; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); + -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); +} \ No newline at end of file diff --git a/tools/analysis/VisualFAIL/css/bootstrap-theme.min.css b/tools/analysis/VisualFAIL/css/bootstrap-theme.min.css new file mode 100644 index 00000000..c7b6d39b --- /dev/null +++ b/tools/analysis/VisualFAIL/css/bootstrap-theme.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.0.3 (http://getbootstrap.com) + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + */ + +.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,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,0.125);box-shadow:inset 0 3px 5px rgba(0,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:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.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-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);background-repeat:repeat-x;border-color:#2b669a;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff2d6ca2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.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-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);background-repeat:repeat-x;border-color:#3e8f3e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff419641',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.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-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);background-repeat:repeat-x;border-color:#e38d13;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffeb9316',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.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-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);background-repeat:repeat-x;border-color:#b92c28;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc12e2a',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.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-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);background-repeat:repeat-x;border-color:#28a4c9;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2aabd2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.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}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,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:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.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:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff8f8f8',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff3f3f3',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.075);box-shadow:inset 0 3px 9px rgba(0,0,0,0.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,0.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff282828',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.25);box-shadow:inset 0 3px 9px rgba(0,0,0,0.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,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,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;border-color:#b2dba1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffc8e5bc',GradientType=0)}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;border-color:#9acfea;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffb9def0',GradientType=0)}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;border-color:#f5e79e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fff8efc0',GradientType=0)}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;border-color:#dca7a7;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffe7c3c3',GradientType=0)}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff5f5f5',GradientType=0)}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3071a9',GradientType=0)}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff449d44',GradientType=0)}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff31b0d5',GradientType=0)}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffec971f',GradientType=0)}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc9302c',GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,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:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;border-color:#3278b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3278b3',GradientType=0)}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffd0e9c6',GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffc4e3f3',GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fffaf2cc',GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffebcccc',GradientType=0)}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;border-color:#dcdcdc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1)} \ No newline at end of file diff --git a/tools/analysis/VisualFAIL/css/bootstrap.css b/tools/analysis/VisualFAIL/css/bootstrap.css new file mode 100644 index 00000000..377dff30 --- /dev/null +++ b/tools/analysis/VisualFAIL/css/bootstrap.css @@ -0,0 +1,7118 @@ +/*! + * Bootstrap v3.0.3 (http://getbootstrap.com) + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + */ + +/*! normalize.css v2.1.3 | MIT License | git.io/normalize */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +nav, +section, +summary { + display: block; +} + +audio, +canvas, +video { + display: inline-block; +} + +audio:not([controls]) { + display: none; + height: 0; +} + +[hidden], +template { + display: none; +} + +html { + font-family: sans-serif; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +body { + margin: 0; +} + +a { + background: transparent; +} + +a:focus { + outline: thin dotted; +} + +a:active, +a:hover { + outline: 0; +} + +h1 { + margin: 0.67em 0; + font-size: 2em; +} + +abbr[title] { + border-bottom: 1px dotted; +} + +b, +strong { + font-weight: bold; +} + +dfn { + font-style: italic; +} + +hr { + height: 0; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +mark { + color: #000; + background: #ff0; +} + +code, +kbd, +pre, +samp { + font-family: monospace, serif; + font-size: 1em; +} + +pre { + white-space: pre-wrap; +} + +q { + quotes: "\201C" "\201D" "\2018" "\2019"; +} + +small { + font-size: 80%; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + border: 0; +} + +svg:not(:root) { + overflow: hidden; +} + +figure { + margin: 0; +} + +fieldset { + padding: 0.35em 0.625em 0.75em; + margin: 0 2px; + border: 1px solid #c0c0c0; +} + +legend { + padding: 0; + border: 0; +} + +button, +input, +select, +textarea { + margin: 0; + font-family: inherit; + font-size: 100%; +} + +button, +input { + line-height: normal; +} + +button, +select { + text-transform: none; +} + +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +button[disabled], +html input[disabled] { + cursor: default; +} + +input[type="checkbox"], +input[type="radio"] { + padding: 0; + box-sizing: border-box; +} + +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; +} + +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +@media print { + * { + color: #000 !important; + text-shadow: none !important; + background: transparent !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; + } + @page { + margin: 2cm .5cm; + } + 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; + } +} + +*, +*:before, +*:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +html { + font-size: 62.5%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 1.428571429; + color: #333333; + background-color: #ffffff; +} + +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; +} + +img { + vertical-align: middle; +} + +.img-responsive { + display: block; + height: auto; + max-width: 100%; +} + +.img-rounded { + border-radius: 6px; +} + +.img-thumbnail { + display: inline-block; + height: auto; + max-width: 100%; + padding: 4px; + line-height: 1.428571429; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} + +.img-circle { + border-radius: 50%; +} + +hr { + margin-top: 20px; + margin-bottom: 20px; + border: 0; + border-top: 1px solid #eeeeee; +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} + +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + 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: normal; + line-height: 1; + color: #999999; +} + +h1, +h2, +h3 { + margin-top: 20px; + margin-bottom: 10px; +} + +h1 small, +h2 small, +h3 small, +h1 .small, +h2 .small, +h3 .small { + font-size: 65%; +} + +h4, +h5, +h6 { + margin-top: 10px; + margin-bottom: 10px; +} + +h4 small, +h5 small, +h6 small, +h4 .small, +h5 .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: 200; + line-height: 1.4; +} + +@media (min-width: 768px) { + .lead { + font-size: 21px; + } +} + +small, +.small { + font-size: 85%; +} + +cite { + font-style: normal; +} + +.text-muted { + color: #999999; +} + +.text-primary { + color: #428bca; +} + +.text-primary:hover { + color: #3071a9; +} + +.text-warning { + color: #8a6d3b; +} + +.text-warning:hover { + color: #66512c; +} + +.text-danger { + color: #a94442; +} + +.text-danger:hover { + color: #843534; +} + +.text-success { + color: #3c763d; +} + +.text-success:hover { + color: #2b542c; +} + +.text-info { + color: #31708f; +} + +.text-info:hover { + color: #245269; +} + +.text-left { + text-align: left; +} + +.text-right { + text-align: right; +} + +.text-center { + text-align: center; +} + +.page-header { + padding-bottom: 9px; + margin: 40px 0 20px; + border-bottom: 1px solid #eeeeee; +} + +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; + list-style: none; +} + +.list-inline > li { + display: inline-block; + padding-right: 5px; + padding-left: 5px; +} + +.list-inline > li:first-child { + padding-left: 0; +} + +dl { + margin-top: 0; + margin-bottom: 20px; +} + +dt, +dd { + line-height: 1.428571429; +} + +dt { + font-weight: bold; +} + +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; + } + .dl-horizontal dd:before, + .dl-horizontal dd:after { + display: table; + content: " "; + } + .dl-horizontal dd:after { + clear: both; + } + .dl-horizontal dd:before, + .dl-horizontal dd:after { + display: table; + content: " "; + } + .dl-horizontal dd:after { + clear: both; + } +} + +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999999; +} + +.initialism { + font-size: 90%; + text-transform: uppercase; +} + +blockquote { + padding: 10px 20px; + margin: 0 0 20px; + border-left: 5px solid #eeeeee; +} + +blockquote p { + font-size: 17.5px; + font-weight: 300; + line-height: 1.25; +} + +blockquote p:last-child { + margin-bottom: 0; +} + +blockquote small, +blockquote .small { + display: block; + line-height: 1.428571429; + color: #999999; +} + +blockquote small:before, +blockquote .small:before { + content: '\2014 \00A0'; +} + +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} + +blockquote.pull-right p, +blockquote.pull-right small, +blockquote.pull-right .small { + text-align: right; +} + +blockquote.pull-right small:before, +blockquote.pull-right .small:before { + content: ''; +} + +blockquote.pull-right 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.428571429; +} + +code, +kbd, +pre, +samp { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; +} + +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + white-space: nowrap; + background-color: #f9f2f4; + border-radius: 4px; +} + +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 1.428571429; + color: #333333; + word-break: break-all; + word-wrap: break-word; + background-color: #f5f5f5; + border: 1px solid #cccccc; + 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; +} + +.container:before, +.container:after { + display: table; + content: " "; +} + +.container:after { + clear: both; +} + +.container:before, +.container:after { + display: table; + content: " "; +} + +.container:after { + clear: both; +} + +@media (min-width: 768px) { + .container { + width: 750px; + } +} + +@media (min-width: 992px) { + .container { + width: 970px; + } +} + +@media (min-width: 1200px) { + .container { + width: 1170px; + } +} + +.row { + margin-right: -15px; + margin-left: -15px; +} + +.row:before, +.row:after { + display: table; + content: " "; +} + +.row:after { + clear: both; +} + +.row:before, +.row:after { + display: table; + content: " "; +} + +.row:after { + clear: both; +} + +.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.66666666666666%; +} + +.col-xs-10 { + width: 83.33333333333334%; +} + +.col-xs-9 { + width: 75%; +} + +.col-xs-8 { + width: 66.66666666666666%; +} + +.col-xs-7 { + width: 58.333333333333336%; +} + +.col-xs-6 { + width: 50%; +} + +.col-xs-5 { + width: 41.66666666666667%; +} + +.col-xs-4 { + width: 33.33333333333333%; +} + +.col-xs-3 { + width: 25%; +} + +.col-xs-2 { + width: 16.666666666666664%; +} + +.col-xs-1 { + width: 8.333333333333332%; +} + +.col-xs-pull-12 { + right: 100%; +} + +.col-xs-pull-11 { + right: 91.66666666666666%; +} + +.col-xs-pull-10 { + right: 83.33333333333334%; +} + +.col-xs-pull-9 { + right: 75%; +} + +.col-xs-pull-8 { + right: 66.66666666666666%; +} + +.col-xs-pull-7 { + right: 58.333333333333336%; +} + +.col-xs-pull-6 { + right: 50%; +} + +.col-xs-pull-5 { + right: 41.66666666666667%; +} + +.col-xs-pull-4 { + right: 33.33333333333333%; +} + +.col-xs-pull-3 { + right: 25%; +} + +.col-xs-pull-2 { + right: 16.666666666666664%; +} + +.col-xs-pull-1 { + right: 8.333333333333332%; +} + +.col-xs-pull-0 { + right: 0; +} + +.col-xs-push-12 { + left: 100%; +} + +.col-xs-push-11 { + left: 91.66666666666666%; +} + +.col-xs-push-10 { + left: 83.33333333333334%; +} + +.col-xs-push-9 { + left: 75%; +} + +.col-xs-push-8 { + left: 66.66666666666666%; +} + +.col-xs-push-7 { + left: 58.333333333333336%; +} + +.col-xs-push-6 { + left: 50%; +} + +.col-xs-push-5 { + left: 41.66666666666667%; +} + +.col-xs-push-4 { + left: 33.33333333333333%; +} + +.col-xs-push-3 { + left: 25%; +} + +.col-xs-push-2 { + left: 16.666666666666664%; +} + +.col-xs-push-1 { + left: 8.333333333333332%; +} + +.col-xs-push-0 { + left: 0; +} + +.col-xs-offset-12 { + margin-left: 100%; +} + +.col-xs-offset-11 { + margin-left: 91.66666666666666%; +} + +.col-xs-offset-10 { + margin-left: 83.33333333333334%; +} + +.col-xs-offset-9 { + margin-left: 75%; +} + +.col-xs-offset-8 { + margin-left: 66.66666666666666%; +} + +.col-xs-offset-7 { + margin-left: 58.333333333333336%; +} + +.col-xs-offset-6 { + margin-left: 50%; +} + +.col-xs-offset-5 { + margin-left: 41.66666666666667%; +} + +.col-xs-offset-4 { + margin-left: 33.33333333333333%; +} + +.col-xs-offset-3 { + margin-left: 25%; +} + +.col-xs-offset-2 { + margin-left: 16.666666666666664%; +} + +.col-xs-offset-1 { + margin-left: 8.333333333333332%; +} + +.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.66666666666666%; + } + .col-sm-10 { + width: 83.33333333333334%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-8 { + width: 66.66666666666666%; + } + .col-sm-7 { + width: 58.333333333333336%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-5 { + width: 41.66666666666667%; + } + .col-sm-4 { + width: 33.33333333333333%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-2 { + width: 16.666666666666664%; + } + .col-sm-1 { + width: 8.333333333333332%; + } + .col-sm-pull-12 { + right: 100%; + } + .col-sm-pull-11 { + right: 91.66666666666666%; + } + .col-sm-pull-10 { + right: 83.33333333333334%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-8 { + right: 66.66666666666666%; + } + .col-sm-pull-7 { + right: 58.333333333333336%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-5 { + right: 41.66666666666667%; + } + .col-sm-pull-4 { + right: 33.33333333333333%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-2 { + right: 16.666666666666664%; + } + .col-sm-pull-1 { + right: 8.333333333333332%; + } + .col-sm-pull-0 { + right: 0; + } + .col-sm-push-12 { + left: 100%; + } + .col-sm-push-11 { + left: 91.66666666666666%; + } + .col-sm-push-10 { + left: 83.33333333333334%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-8 { + left: 66.66666666666666%; + } + .col-sm-push-7 { + left: 58.333333333333336%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-5 { + left: 41.66666666666667%; + } + .col-sm-push-4 { + left: 33.33333333333333%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-2 { + left: 16.666666666666664%; + } + .col-sm-push-1 { + left: 8.333333333333332%; + } + .col-sm-push-0 { + left: 0; + } + .col-sm-offset-12 { + margin-left: 100%; + } + .col-sm-offset-11 { + margin-left: 91.66666666666666%; + } + .col-sm-offset-10 { + margin-left: 83.33333333333334%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-8 { + margin-left: 66.66666666666666%; + } + .col-sm-offset-7 { + margin-left: 58.333333333333336%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-5 { + margin-left: 41.66666666666667%; + } + .col-sm-offset-4 { + margin-left: 33.33333333333333%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-2 { + margin-left: 16.666666666666664%; + } + .col-sm-offset-1 { + margin-left: 8.333333333333332%; + } + .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.66666666666666%; + } + .col-md-10 { + width: 83.33333333333334%; + } + .col-md-9 { + width: 75%; + } + .col-md-8 { + width: 66.66666666666666%; + } + .col-md-7 { + width: 58.333333333333336%; + } + .col-md-6 { + width: 50%; + } + .col-md-5 { + width: 41.66666666666667%; + } + .col-md-4 { + width: 33.33333333333333%; + } + .col-md-3 { + width: 25%; + } + .col-md-2 { + width: 16.666666666666664%; + } + .col-md-1 { + width: 8.333333333333332%; + } + .col-md-pull-12 { + right: 100%; + } + .col-md-pull-11 { + right: 91.66666666666666%; + } + .col-md-pull-10 { + right: 83.33333333333334%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-8 { + right: 66.66666666666666%; + } + .col-md-pull-7 { + right: 58.333333333333336%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-5 { + right: 41.66666666666667%; + } + .col-md-pull-4 { + right: 33.33333333333333%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-2 { + right: 16.666666666666664%; + } + .col-md-pull-1 { + right: 8.333333333333332%; + } + .col-md-pull-0 { + right: 0; + } + .col-md-push-12 { + left: 100%; + } + .col-md-push-11 { + left: 91.66666666666666%; + } + .col-md-push-10 { + left: 83.33333333333334%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-8 { + left: 66.66666666666666%; + } + .col-md-push-7 { + left: 58.333333333333336%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-5 { + left: 41.66666666666667%; + } + .col-md-push-4 { + left: 33.33333333333333%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-2 { + left: 16.666666666666664%; + } + .col-md-push-1 { + left: 8.333333333333332%; + } + .col-md-push-0 { + left: 0; + } + .col-md-offset-12 { + margin-left: 100%; + } + .col-md-offset-11 { + margin-left: 91.66666666666666%; + } + .col-md-offset-10 { + margin-left: 83.33333333333334%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-8 { + margin-left: 66.66666666666666%; + } + .col-md-offset-7 { + margin-left: 58.333333333333336%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-5 { + margin-left: 41.66666666666667%; + } + .col-md-offset-4 { + margin-left: 33.33333333333333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-2 { + margin-left: 16.666666666666664%; + } + .col-md-offset-1 { + margin-left: 8.333333333333332%; + } + .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.66666666666666%; + } + .col-lg-10 { + width: 83.33333333333334%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-8 { + width: 66.66666666666666%; + } + .col-lg-7 { + width: 58.333333333333336%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-5 { + width: 41.66666666666667%; + } + .col-lg-4 { + width: 33.33333333333333%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-2 { + width: 16.666666666666664%; + } + .col-lg-1 { + width: 8.333333333333332%; + } + .col-lg-pull-12 { + right: 100%; + } + .col-lg-pull-11 { + right: 91.66666666666666%; + } + .col-lg-pull-10 { + right: 83.33333333333334%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-8 { + right: 66.66666666666666%; + } + .col-lg-pull-7 { + right: 58.333333333333336%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-5 { + right: 41.66666666666667%; + } + .col-lg-pull-4 { + right: 33.33333333333333%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-2 { + right: 16.666666666666664%; + } + .col-lg-pull-1 { + right: 8.333333333333332%; + } + .col-lg-pull-0 { + right: 0; + } + .col-lg-push-12 { + left: 100%; + } + .col-lg-push-11 { + left: 91.66666666666666%; + } + .col-lg-push-10 { + left: 83.33333333333334%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-8 { + left: 66.66666666666666%; + } + .col-lg-push-7 { + left: 58.333333333333336%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-5 { + left: 41.66666666666667%; + } + .col-lg-push-4 { + left: 33.33333333333333%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-2 { + left: 16.666666666666664%; + } + .col-lg-push-1 { + left: 8.333333333333332%; + } + .col-lg-push-0 { + left: 0; + } + .col-lg-offset-12 { + margin-left: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66666666666666%; + } + .col-lg-offset-10 { + margin-left: 83.33333333333334%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66666666666666%; + } + .col-lg-offset-7 { + margin-left: 58.333333333333336%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66666666666667%; + } + .col-lg-offset-4 { + margin-left: 33.33333333333333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-2 { + margin-left: 16.666666666666664%; + } + .col-lg-offset-1 { + margin-left: 8.333333333333332%; + } + .col-lg-offset-0 { + margin-left: 0; + } +} + +table { + max-width: 100%; + background-color: transparent; +} + +th { + text-align: left; +} + +.table { + 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.428571429; + vertical-align: top; + border-top: 1px solid #dddddd; +} + +.table > thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #dddddd; +} + +.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 #dddddd; +} + +.table .table { + background-color: #ffffff; +} + +.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 #dddddd; +} + +.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 #dddddd; +} + +.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-"] { + display: table-cell; + float: none; +} + +.table > thead > tr > .active, +.table > tbody > tr > .active, +.table > tfoot > tr > .active, +.table > thead > .active > td, +.table > tbody > .active > td, +.table > tfoot > .active > td, +.table > thead > .active > th, +.table > tbody > .active > th, +.table > tfoot > .active > th { + background-color: #f5f5f5; +} + +.table-hover > tbody > tr > .active:hover, +.table-hover > tbody > .active:hover > td, +.table-hover > tbody > .active:hover > th { + background-color: #e8e8e8; +} + +.table > thead > tr > .success, +.table > tbody > tr > .success, +.table > tfoot > tr > .success, +.table > thead > .success > td, +.table > tbody > .success > td, +.table > tfoot > .success > td, +.table > thead > .success > th, +.table > tbody > .success > th, +.table > tfoot > .success > th { + background-color: #dff0d8; +} + +.table-hover > tbody > tr > .success:hover, +.table-hover > tbody > .success:hover > td, +.table-hover > tbody > .success:hover > th { + background-color: #d0e9c6; +} + +.table > thead > tr > .danger, +.table > tbody > tr > .danger, +.table > tfoot > tr > .danger, +.table > thead > .danger > td, +.table > tbody > .danger > td, +.table > tfoot > .danger > td, +.table > thead > .danger > th, +.table > tbody > .danger > th, +.table > tfoot > .danger > th { + background-color: #f2dede; +} + +.table-hover > tbody > tr > .danger:hover, +.table-hover > tbody > .danger:hover > td, +.table-hover > tbody > .danger:hover > th { + background-color: #ebcccc; +} + +.table > thead > tr > .warning, +.table > tbody > tr > .warning, +.table > tfoot > tr > .warning, +.table > thead > .warning > td, +.table > tbody > .warning > td, +.table > tfoot > .warning > td, +.table > thead > .warning > th, +.table > tbody > .warning > th, +.table > tfoot > .warning > th { + background-color: #fcf8e3; +} + +.table-hover > tbody > tr > .warning:hover, +.table-hover > tbody > .warning:hover > td, +.table-hover > tbody > .warning:hover > th { + background-color: #faf2cc; +} + +@media (max-width: 767px) { + .table-responsive { + width: 100%; + margin-bottom: 15px; + overflow-x: scroll; + overflow-y: hidden; + border: 1px solid #dddddd; + -ms-overflow-style: -ms-autohiding-scrollbar; + -webkit-overflow-scrolling: touch; + } + .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 { + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: inherit; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} + +label { + display: inline-block; + margin-bottom: 5px; + font-weight: bold; +} + +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; + /* IE8-9 */ + + line-height: normal; +} + +input[type="file"] { + display: block; +} + +select[multiple], +select[size] { + height: auto; +} + +select optgroup { + font-family: inherit; + font-size: inherit; + font-style: inherit; +} + +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; +} + +input[type="number"]::-webkit-outer-spin-button, +input[type="number"]::-webkit-inner-spin-button { + height: auto; +} + +output { + display: block; + padding-top: 7px; + font-size: 14px; + line-height: 1.428571429; + color: #555555; + vertical-align: middle; +} + +.form-control { + display: block; + width: 100%; + height: 34px; + padding: 6px 12px; + font-size: 14px; + line-height: 1.428571429; + color: #555555; + vertical-align: middle; + background-color: #ffffff; + background-image: none; + border: 1px solid #cccccc; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; + transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; +} + +.form-control:focus { + border-color: #66afe9; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); +} + +.form-control:-moz-placeholder { + color: #999999; +} + +.form-control::-moz-placeholder { + color: #999999; + opacity: 1; +} + +.form-control:-ms-input-placeholder { + color: #999999; +} + +.form-control::-webkit-input-placeholder { + color: #999999; +} + +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + cursor: not-allowed; + background-color: #eeeeee; +} + +textarea.form-control { + height: auto; +} + +.form-group { + margin-bottom: 15px; +} + +.radio, +.checkbox { + display: block; + min-height: 20px; + padding-left: 20px; + margin-top: 10px; + margin-bottom: 10px; + vertical-align: middle; +} + +.radio label, +.checkbox label { + display: inline; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; +} + +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + float: left; + 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: normal; + 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], +.radio[disabled], +.radio-inline[disabled], +.checkbox[disabled], +.checkbox-inline[disabled], +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"], +fieldset[disabled] .radio, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} + +.input-sm { + 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 { + height: auto; +} + +.input-lg { + 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 { + height: auto; +} + +.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, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.has-warning .form-control:focus { + border-color: #66512c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; +} + +.has-warning .input-group-addon { + color: #8a6d3b; + background-color: #fcf8e3; + border-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, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.has-error .form-control:focus { + border-color: #843534; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; +} + +.has-error .input-group-addon { + color: #a94442; + background-color: #f2dede; + border-color: #a94442; +} + +.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, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.has-success .form-control:focus { + border-color: #2b542c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; +} + +.has-success .input-group-addon { + color: #3c763d; + background-color: #dff0d8; + border-color: #3c763d; +} + +.form-control-static { + margin-bottom: 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; + } + .form-inline select.form-control { + width: auto; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + padding-left: 0; + margin-top: 0; + margin-bottom: 0; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + float: none; + margin-left: 0; + } +} + +.form-horizontal .control-label, +.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; +} + +.form-horizontal .form-group:before, +.form-horizontal .form-group:after { + display: table; + content: " "; +} + +.form-horizontal .form-group:after { + clear: both; +} + +.form-horizontal .form-group:before, +.form-horizontal .form-group:after { + display: table; + content: " "; +} + +.form-horizontal .form-group:after { + clear: both; +} + +.form-horizontal .form-control-static { + padding-top: 7px; +} + +@media (min-width: 768px) { + .form-horizontal .control-label { + text-align: right; + } +} + +.btn { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-size: 14px; + font-weight: normal; + line-height: 1.428571429; + text-align: center; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} + +.btn:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.btn:hover, +.btn:focus { + color: #333333; + text-decoration: none; +} + +.btn:active, +.btn.active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} + +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + pointer-events: none; + cursor: not-allowed; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; +} + +.btn-default { + color: #333333; + background-color: #ffffff; + border-color: #cccccc; +} + +.btn-default:hover, +.btn-default:focus, +.btn-default:active, +.btn-default.active, +.open .dropdown-toggle.btn-default { + color: #333333; + background-color: #ebebeb; + 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: #ffffff; + border-color: #cccccc; +} + +.btn-default .badge { + color: #ffffff; + background-color: #fff; +} + +.btn-primary { + color: #ffffff; + background-color: #428bca; + border-color: #357ebd; +} + +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + color: #ffffff; + background-color: #3276b1; + 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-warning { + color: #ffffff; + background-color: #f0ad4e; + border-color: #eea236; +} + +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.open .dropdown-toggle.btn-warning { + color: #ffffff; + background-color: #ed9c28; + 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: #ffffff; + background-color: #d9534f; + border-color: #d43f3a; +} + +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.open .dropdown-toggle.btn-danger { + color: #ffffff; + background-color: #d2322d; + 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-success { + color: #ffffff; + background-color: #5cb85c; + border-color: #4cae4c; +} + +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.open .dropdown-toggle.btn-success { + color: #ffffff; + background-color: #47a447; + 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: #ffffff; + background-color: #5bc0de; + border-color: #46b8da; +} + +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.open .dropdown-toggle.btn-info { + color: #ffffff; + background-color: #39b3d7; + 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-link { + font-weight: normal; + 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: #999999; + text-decoration: none; +} + +.btn-lg { + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} + +.btn-sm { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} + +.btn-xs { + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} + +.btn-block { + display: block; + width: 100%; + padding-right: 0; + padding-left: 0; +} + +.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 0.15s linear; + transition: opacity 0.15s linear; +} + +.fade.in { + opacity: 1; +} + +.collapse { + display: none; +} + +.collapse.in { + display: block; +} + +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +@font-face { + font-family: 'Glyphicons Halflings'; + src: url('../fonts/glyphicons-halflings-regular.eot'); + src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg'); +} + +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + -webkit-font-smoothing: antialiased; + font-style: normal; + font-weight: normal; + line-height: 1; + -moz-osx-font-smoothing: grayscale; +} + +.glyphicon:empty { + width: 1em; +} + +.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"; +} + +.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; + list-style: none; + background-color: #ffffff; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 4px; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + background-clip: padding-box; +} + +.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: normal; + line-height: 1.428571429; + color: #333333; + 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: #ffffff; + text-decoration: none; + background-color: #428bca; + outline: 0; +} + +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #999999; +} + +.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-header { + display: block; + padding: 3px 20px; + font-size: 12px; + line-height: 1.428571429; + color: #999999; +} + +.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 { + border-top: 0; + border-bottom: 4px solid; + content: ""; +} + +.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; + } +} + +.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: none; +} + +.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:before, +.btn-toolbar:after { + display: table; + content: " "; +} + +.btn-toolbar:after { + clear: both; +} + +.btn-toolbar:before, +.btn-toolbar:after { + display: table; + content: " "; +} + +.btn-toolbar:after { + clear: both; +} + +.btn-toolbar .btn-group { + float: left; +} + +.btn-toolbar > .btn + .btn, +.btn-toolbar > .btn-group + .btn, +.btn-toolbar > .btn + .btn-group, +.btn-toolbar > .btn-group + .btn-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-bottom-left-radius: 0; + border-top-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-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + +.btn-group-xs > .btn { + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} + +.btn-group-sm > .btn { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} + +.btn-group-lg > .btn { + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} + +.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, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 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:before, +.btn-group-vertical > .btn-group:after { + display: table; + content: " "; +} + +.btn-group-vertical > .btn-group:after { + clear: both; +} + +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after { + display: table; + content: " "; +} + +.btn-group-vertical > .btn-group:after { + clear: both; +} + +.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-right-radius: 0; + border-bottom-left-radius: 4px; + border-top-left-radius: 0; +} + +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} + +.btn-group-vertical > .btn-group:first-child > .btn:last-child, +.btn-group-vertical > .btn-group:first-child > .dropdown-toggle { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.btn-group-vertical > .btn-group:last-child > .btn:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} + +.btn-group-justified { + display: table; + width: 100%; + border-collapse: separate; + table-layout: fixed; +} + +.btn-group-justified > .btn, +.btn-group-justified > .btn-group { + display: table-cell; + float: none; + width: 1%; +} + +.btn-group-justified > .btn-group .btn { + width: 100%; +} + +[data-toggle="buttons"] > .btn > input[type="radio"], +[data-toggle="buttons"] > .btn > input[type="checkbox"] { + display: none; +} + +.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 { + 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 { + 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 { + 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: normal; + line-height: 1; + color: #555555; + text-align: center; + background-color: #eeeeee; + border: 1px solid #cccccc; + 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 > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) { + 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 > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.input-group-addon:last-child { + border-left: 0; +} + +.input-group-btn { + position: relative; + white-space: nowrap; +} + +.input-group-btn:first-child > .btn { + margin-right: -1px; +} + +.input-group-btn:last-child > .btn { + margin-left: -1px; +} + +.input-group-btn > .btn { + position: relative; +} + +.input-group-btn > .btn + .btn { + margin-left: -4px; +} + +.input-group-btn > .btn:hover, +.input-group-btn > .btn:active { + z-index: 2; +} + +.nav { + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.nav:before, +.nav:after { + display: table; + content: " "; +} + +.nav:after { + clear: both; +} + +.nav:before, +.nav:after { + display: table; + content: " "; +} + +.nav:after { + clear: both; +} + +.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: #eeeeee; +} + +.nav > li.disabled > a { + color: #999999; +} + +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #999999; + text-decoration: none; + cursor: not-allowed; + background-color: transparent; +} + +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #eeeeee; + 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 #dddddd; +} + +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} + +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.428571429; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} + +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} + +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #555555; + cursor: default; + background-color: #ffffff; + border: 1px solid #dddddd; + 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 #dddddd; +} + +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #dddddd; + 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: #ffffff; + } +} + +.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: #ffffff; + 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 #dddddd; +} + +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #dddddd; + 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: #ffffff; + } +} + +.tab-content > .tab-pane { + display: none; +} + +.tab-content > .active { + display: block; +} + +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-right-radius: 0; + border-top-left-radius: 0; +} + +.navbar { + position: relative; + min-height: 50px; + margin-bottom: 20px; + border: 1px solid transparent; +} + +.navbar:before, +.navbar:after { + display: table; + content: " "; +} + +.navbar:after { + clear: both; +} + +.navbar:before, +.navbar:after { + display: table; + content: " "; +} + +.navbar:after { + clear: both; +} + +@media (min-width: 768px) { + .navbar { + border-radius: 4px; + } +} + +.navbar-header:before, +.navbar-header:after { + display: table; + content: " "; +} + +.navbar-header:after { + clear: both; +} + +.navbar-header:before, +.navbar-header:after { + display: table; + content: " "; +} + +.navbar-header:after { + clear: both; +} + +@media (min-width: 768px) { + .navbar-header { + float: left; + } +} + +.navbar-collapse { + max-height: 340px; + padding-right: 15px; + padding-left: 15px; + overflow-x: visible; + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); + -webkit-overflow-scrolling: touch; +} + +.navbar-collapse:before, +.navbar-collapse:after { + display: table; + content: " "; +} + +.navbar-collapse:after { + clear: both; +} + +.navbar-collapse:before, +.navbar-collapse:after { + display: table; + content: " "; +} + +.navbar-collapse:after { + clear: both; +} + +.navbar-collapse.in { + overflow-y: auto; +} + +@media (min-width: 768px) { + .navbar-collapse { + width: auto; + border-top: 0; + 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; + } +} + +.container > .navbar-header, +.container > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} + +@media (min-width: 768px) { + .container > .navbar-header, + .container > .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; +} + +@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; + 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 { + 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 .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; + 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, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.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; + } + .navbar-form select.form-control { + width: auto; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + padding-left: 0; + margin-top: 0; + margin-bottom: 0; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + float: none; + margin-left: 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-right-radius: 0; + border-top-left-radius: 0; +} + +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.navbar-nav.pull-right > li > .dropdown-menu, +.navbar-nav > li > .dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.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: #777777; +} + +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #5e5e5e; + background-color: transparent; +} + +.navbar-default .navbar-text { + color: #777777; +} + +.navbar-default .navbar-nav > li > a { + color: #777777; +} + +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #333333; + background-color: transparent; +} + +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #555555; + background-color: #e7e7e7; +} + +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #cccccc; + background-color: transparent; +} + +.navbar-default .navbar-toggle { + border-color: #dddddd; +} + +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #dddddd; +} + +.navbar-default .navbar-toggle .icon-bar { + background-color: #cccccc; +} + +.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: #555555; + background-color: #e7e7e7; +} + +@media (max-width: 767px) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #777777; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #333333; + 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: #555555; + 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: #cccccc; + background-color: transparent; + } +} + +.navbar-default .navbar-link { + color: #777777; +} + +.navbar-default .navbar-link:hover { + color: #333333; +} + +.navbar-inverse { + background-color: #222222; + border-color: #080808; +} + +.navbar-inverse .navbar-brand { + color: #999999; +} + +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #ffffff; + background-color: transparent; +} + +.navbar-inverse .navbar-text { + color: #999999; +} + +.navbar-inverse .navbar-nav > li > a { + color: #999999; +} + +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #ffffff; + background-color: transparent; +} + +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #ffffff; + background-color: #080808; +} + +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #444444; + background-color: transparent; +} + +.navbar-inverse .navbar-toggle { + border-color: #333333; +} + +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #333333; +} + +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #ffffff; +} + +.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: #ffffff; + 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: #999999; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #ffffff; + 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: #ffffff; + 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: #444444; + background-color: transparent; + } +} + +.navbar-inverse .navbar-link { + color: #999999; +} + +.navbar-inverse .navbar-link:hover { + color: #ffffff; +} + +.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: #cccccc; + content: "/\00a0"; +} + +.breadcrumb > .active { + color: #999999; +} + +.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.428571429; + text-decoration: none; + background-color: #ffffff; + border: 1px solid #dddddd; +} + +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-bottom-left-radius: 4px; + border-top-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 { + background-color: #eeeeee; +} + +.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: #ffffff; + 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: #999999; + cursor: not-allowed; + background-color: #ffffff; + border-color: #dddddd; +} + +.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-bottom-left-radius: 6px; + border-top-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-bottom-left-radius: 3px; + border-top-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:before, +.pager:after { + display: table; + content: " "; +} + +.pager:after { + clear: both; +} + +.pager:before, +.pager:after { + display: table; + content: " "; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 15px; +} + +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} + +.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: #999999; + cursor: not-allowed; + background-color: #ffffff; +} + +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #ffffff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; +} + +.label[href]:hover, +.label[href]:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +.label:empty { + display: none; +} + +.btn .label { + position: relative; + top: -1px; +} + +.label-default { + background-color: #999999; +} + +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #808080; +} + +.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: bold; + line-height: 1; + color: #ffffff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + background-color: #999999; + border-radius: 10px; +} + +.badge:empty { + display: none; +} + +.btn .badge { + position: relative; + top: -1px; +} + +a.badge:hover, +a.badge:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +a.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: #428bca; + background-color: #ffffff; +} + +.nav-pills > li > a > .badge { + margin-left: 3px; +} + +.jumbotron { + padding: 30px; + margin-bottom: 30px; + font-size: 21px; + font-weight: 200; + line-height: 2.1428571435; + color: inherit; + background-color: #eeeeee; +} + +.jumbotron h1, +.jumbotron .h1 { + line-height: 1; + color: inherit; +} + +.jumbotron p { + line-height: 1.4; +} + +.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.428571429; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} + +.thumbnail > img, +.thumbnail a > img { + display: block; + height: auto; + max-width: 100%; + margin-right: auto; + margin-left: auto; +} + +a.thumbnail:hover, +a.thumbnail:focus, +a.thumbnail.active { + border-color: #428bca; +} + +.thumbnail .caption { + padding: 9px; + color: #333333; +} + +.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: bold; +} + +.alert > p, +.alert > ul { + margin-bottom: 0; +} + +.alert > p + p { + margin-top: 5px; +} + +.alert-dismissable { + padding-right: 35px; +} + +.alert-dismissable .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; + } +} + +@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, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.progress-bar { + float: left; + width: 0; + height: 100%; + font-size: 12px; + line-height: 20px; + color: #ffffff; + text-align: center; + background-color: #428bca; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +.progress-striped .progress-bar { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 40px 40px; +} + +.progress.active .progress-bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + +.progress-bar-success { + background-color: #5cb85c; +} + +.progress-striped .progress-bar-success { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.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, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.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, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.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, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.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: #ffffff; + border: 1px solid #dddddd; +} + +.list-group-item:first-child { + border-top-right-radius: 4px; + border-top-left-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: #555555; +} + +a.list-group-item .list-group-item-heading { + color: #333333; +} + +a.list-group-item:hover, +a.list-group-item:focus { + text-decoration: none; + background-color: #f5f5f5; +} + +a.list-group-item.active, +a.list-group-item.active:hover, +a.list-group-item.active:focus { + z-index: 2; + color: #ffffff; + background-color: #428bca; + border-color: #428bca; +} + +a.list-group-item.active .list-group-item-heading, +a.list-group-item.active:hover .list-group-item-heading, +a.list-group-item.active:focus .list-group-item-heading { + color: inherit; +} + +a.list-group-item.active .list-group-item-text, +a.list-group-item.active:hover .list-group-item-text, +a.list-group-item.active:focus .list-group-item-text { + color: #e1edf7; +} + +.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: #ffffff; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.panel-body { + padding: 15px; +} + +.panel-body:before, +.panel-body:after { + display: table; + content: " "; +} + +.panel-body:after { + clear: both; +} + +.panel-body:before, +.panel-body:after { + display: table; + content: " "; +} + +.panel-body:after { + clear: both; +} + +.panel > .list-group { + margin-bottom: 0; +} + +.panel > .list-group .list-group-item { + border-width: 1px 0; +} + +.panel > .list-group .list-group-item:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} + +.panel > .list-group .list-group-item:last-child { + border-bottom: 0; +} + +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} + +.panel > .table, +.panel > .table-responsive > .table { + margin-bottom: 0; +} + +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive { + border-top: 1px solid #dddddd; +} + +.panel > .table > tbody:first-child th, +.panel > .table > tbody: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:last-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:last-child > th, +.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, +.panel > .table-bordered > thead > tr:last-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:last-child > td, +.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 { + border-bottom: 0; +} + +.panel > .table-responsive { + margin-bottom: 0; + border: 0; +} + +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-right-radius: 3px; + border-top-left-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 #dddddd; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} + +.panel-group .panel { + margin-bottom: 0; + overflow: hidden; + 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 #dddddd; +} + +.panel-group .panel-footer { + border-top: 0; +} + +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #dddddd; +} + +.panel-default { + border-color: #dddddd; +} + +.panel-default > .panel-heading { + color: #333333; + background-color: #f5f5f5; + border-color: #dddddd; +} + +.panel-default > .panel-heading + .panel-collapse .panel-body { + border-top-color: #dddddd; +} + +.panel-default > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #dddddd; +} + +.panel-primary { + border-color: #428bca; +} + +.panel-primary > .panel-heading { + color: #ffffff; + background-color: #428bca; + border-color: #428bca; +} + +.panel-primary > .panel-heading + .panel-collapse .panel-body { + border-top-color: #428bca; +} + +.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-footer + .panel-collapse .panel-body { + border-bottom-color: #d6e9c6; +} + +.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-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-footer + .panel-collapse .panel-body { + border-bottom-color: #ebccd1; +} + +.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-footer + .panel-collapse .panel-body { + border-bottom-color: #bce8f1; +} + +.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, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 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: bold; + line-height: 1; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +.close:hover, +.close:focus { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.5; + filter: alpha(opacity=50); +} + +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} + +.modal-open { + overflow: hidden; +} + +.modal { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + display: none; + overflow: auto; + overflow-y: scroll; +} + +.modal.fade .modal-dialog { + -webkit-transform: translate(0, -25%); + -ms-transform: translate(0, -25%); + transform: translate(0, -25%); + -webkit-transition: -webkit-transform 0.3s ease-out; + -moz-transition: -moz-transform 0.3s ease-out; + -o-transition: -o-transform 0.3s ease-out; + transition: transform 0.3s ease-out; +} + +.modal.in .modal-dialog { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); +} + +.modal-dialog { + position: relative; + z-index: 1050; + width: auto; + margin: 10px; +} + +.modal-content { + position: relative; + background-color: #ffffff; + border: 1px solid #999999; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 6px; + outline: none; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + background-clip: padding-box; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1030; + background-color: #000000; +} + +.modal-backdrop.fade { + opacity: 0; + filter: alpha(opacity=0); +} + +.modal-backdrop.in { + opacity: 0.5; + filter: alpha(opacity=50); +} + +.modal-header { + min-height: 16.428571429px; + padding: 15px; + border-bottom: 1px solid #e5e5e5; +} + +.modal-header .close { + margin-top: -2px; +} + +.modal-title { + margin: 0; + line-height: 1.428571429; +} + +.modal-body { + position: relative; + padding: 20px; +} + +.modal-footer { + padding: 19px 20px 20px; + margin-top: 15px; + text-align: right; + border-top: 1px solid #e5e5e5; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + content: " "; +} + +.modal-footer:after { + clear: both; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + content: " "; +} + +.modal-footer:after { + clear: both; +} + +.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; +} + +@media screen and (min-width: 768px) { + .modal-dialog { + width: 600px; + margin: 30px auto; + } + .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + } +} + +.tooltip { + position: absolute; + z-index: 1030; + display: block; + font-size: 12px; + line-height: 1.4; + opacity: 0; + filter: alpha(opacity=0); + visibility: visible; +} + +.tooltip.in { + opacity: 0.9; + filter: alpha(opacity=90); +} + +.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: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + 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-top-color: #000000; + border-width: 5px 5px 0; +} + +.tooltip.top-left .tooltip-arrow { + bottom: 0; + left: 5px; + border-top-color: #000000; + border-width: 5px 5px 0; +} + +.tooltip.top-right .tooltip-arrow { + right: 5px; + bottom: 0; + border-top-color: #000000; + border-width: 5px 5px 0; +} + +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-right-color: #000000; + border-width: 5px 5px 5px 0; +} + +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-left-color: #000000; + border-width: 5px 0 5px 5px; +} + +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} + +.tooltip.bottom-left .tooltip-arrow { + top: 0; + left: 5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} + +.tooltip.bottom-right .tooltip-arrow { + top: 0; + right: 5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; + white-space: normal; + background-color: #ffffff; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + background-clip: padding-box; +} + +.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: normal; + 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 { + border-width: 10px; + content: ""; +} + +.popover.top .arrow { + bottom: -11px; + left: 50%; + margin-left: -11px; + border-top-color: #999999; + border-top-color: rgba(0, 0, 0, 0.25); + border-bottom-width: 0; +} + +.popover.top .arrow:after { + bottom: 1px; + margin-left: -10px; + border-top-color: #ffffff; + border-bottom-width: 0; + content: " "; +} + +.popover.right .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-right-color: #999999; + border-right-color: rgba(0, 0, 0, 0.25); + border-left-width: 0; +} + +.popover.right .arrow:after { + bottom: -10px; + left: 1px; + border-right-color: #ffffff; + border-left-width: 0; + content: " "; +} + +.popover.bottom .arrow { + top: -11px; + left: 50%; + margin-left: -11px; + border-bottom-color: #999999; + border-bottom-color: rgba(0, 0, 0, 0.25); + border-top-width: 0; +} + +.popover.bottom .arrow:after { + top: 1px; + margin-left: -10px; + border-bottom-color: #ffffff; + border-top-width: 0; + content: " "; +} + +.popover.left .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-left-color: #999999; + border-left-color: rgba(0, 0, 0, 0.25); + border-right-width: 0; +} + +.popover.left .arrow:after { + right: 1px; + bottom: -10px; + border-left-color: #ffffff; + border-right-width: 0; + content: " "; +} + +.carousel { + position: relative; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel-inner > .item { + position: relative; + display: none; + -webkit-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} + +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + height: auto; + max-width: 100%; + 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: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); + opacity: 0.5; + filter: alpha(opacity=50); +} + +.carousel-control.left { + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.5) 0), color-stop(rgba(0, 0, 0, 0.0001) 100%)); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0, rgba(0, 0, 0, 0.0001) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); +} + +.carousel-control.right { + right: 0; + left: auto; + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.0001) 0), color-stop(rgba(0, 0, 0, 0.5) 100%)); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0, rgba(0, 0, 0, 0.5) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); +} + +.carousel-control:hover, +.carousel-control:focus { + color: #ffffff; + text-decoration: none; + outline: none; + opacity: 0.9; + filter: alpha(opacity=90); +} + +.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%; +} + +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-right { + right: 50%; +} + +.carousel-control .icon-prev, +.carousel-control .icon-next { + width: 20px; + height: 20px; + margin-top: -10px; + margin-left: -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 #ffffff; + border-radius: 10px; +} + +.carousel-indicators .active { + width: 12px; + height: 12px; + margin: 0; + background-color: #ffffff; +} + +.carousel-caption { + position: absolute; + right: 15%; + bottom: 20px; + left: 15%; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); +} + +.carousel-caption .btn { + text-shadow: none; +} + +@media screen and (min-width: 768px) { + .carousel-control .glyphicons-chevron-left, + .carousel-control .glyphicons-chevron-right, + .carousel-control .icon-prev, + .carousel-control .icon-next { + width: 30px; + height: 30px; + margin-top: -15px; + margin-left: -15px; + font-size: 30px; + } + .carousel-caption { + right: 20%; + left: 20%; + padding-bottom: 30px; + } + .carousel-indicators { + bottom: 20px; + } +} + +.clearfix:before, +.clearfix:after { + display: table; + content: " "; +} + +.clearfix: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; +} + +@-ms-viewport { + width: device-width; +} + +.visible-xs, +tr.visible-xs, +th.visible-xs, +td.visible-xs { + 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 (min-width: 768px) and (max-width: 991px) { + .visible-xs.visible-sm { + display: block !important; + } + table.visible-xs.visible-sm { + display: table; + } + tr.visible-xs.visible-sm { + display: table-row !important; + } + th.visible-xs.visible-sm, + td.visible-xs.visible-sm { + display: table-cell !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .visible-xs.visible-md { + display: block !important; + } + table.visible-xs.visible-md { + display: table; + } + tr.visible-xs.visible-md { + display: table-row !important; + } + th.visible-xs.visible-md, + td.visible-xs.visible-md { + display: table-cell !important; + } +} + +@media (min-width: 1200px) { + .visible-xs.visible-lg { + display: block !important; + } + table.visible-xs.visible-lg { + display: table; + } + tr.visible-xs.visible-lg { + display: table-row !important; + } + th.visible-xs.visible-lg, + td.visible-xs.visible-lg { + display: table-cell !important; + } +} + +.visible-sm, +tr.visible-sm, +th.visible-sm, +td.visible-sm { + display: none !important; +} + +@media (max-width: 767px) { + .visible-sm.visible-xs { + display: block !important; + } + table.visible-sm.visible-xs { + display: table; + } + tr.visible-sm.visible-xs { + display: table-row !important; + } + th.visible-sm.visible-xs, + td.visible-sm.visible-xs { + display: table-cell !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: 992px) and (max-width: 1199px) { + .visible-sm.visible-md { + display: block !important; + } + table.visible-sm.visible-md { + display: table; + } + tr.visible-sm.visible-md { + display: table-row !important; + } + th.visible-sm.visible-md, + td.visible-sm.visible-md { + display: table-cell !important; + } +} + +@media (min-width: 1200px) { + .visible-sm.visible-lg { + display: block !important; + } + table.visible-sm.visible-lg { + display: table; + } + tr.visible-sm.visible-lg { + display: table-row !important; + } + th.visible-sm.visible-lg, + td.visible-sm.visible-lg { + display: table-cell !important; + } +} + +.visible-md, +tr.visible-md, +th.visible-md, +td.visible-md { + display: none !important; +} + +@media (max-width: 767px) { + .visible-md.visible-xs { + display: block !important; + } + table.visible-md.visible-xs { + display: table; + } + tr.visible-md.visible-xs { + display: table-row !important; + } + th.visible-md.visible-xs, + td.visible-md.visible-xs { + display: table-cell !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .visible-md.visible-sm { + display: block !important; + } + table.visible-md.visible-sm { + display: table; + } + tr.visible-md.visible-sm { + display: table-row !important; + } + th.visible-md.visible-sm, + td.visible-md.visible-sm { + display: table-cell !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: 1200px) { + .visible-md.visible-lg { + display: block !important; + } + table.visible-md.visible-lg { + display: table; + } + tr.visible-md.visible-lg { + display: table-row !important; + } + th.visible-md.visible-lg, + td.visible-md.visible-lg { + display: table-cell !important; + } +} + +.visible-lg, +tr.visible-lg, +th.visible-lg, +td.visible-lg { + display: none !important; +} + +@media (max-width: 767px) { + .visible-lg.visible-xs { + display: block !important; + } + table.visible-lg.visible-xs { + display: table; + } + tr.visible-lg.visible-xs { + display: table-row !important; + } + th.visible-lg.visible-xs, + td.visible-lg.visible-xs { + display: table-cell !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .visible-lg.visible-sm { + display: block !important; + } + table.visible-lg.visible-sm { + display: table; + } + tr.visible-lg.visible-sm { + display: table-row !important; + } + th.visible-lg.visible-sm, + td.visible-lg.visible-sm { + display: table-cell !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .visible-lg.visible-md { + display: block !important; + } + table.visible-lg.visible-md { + display: table; + } + tr.visible-lg.visible-md { + display: table-row !important; + } + th.visible-lg.visible-md, + td.visible-lg.visible-md { + display: table-cell !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; + } +} + +.hidden-xs { + display: block !important; +} + +table.hidden-xs { + display: table; +} + +tr.hidden-xs { + display: table-row !important; +} + +th.hidden-xs, +td.hidden-xs { + display: table-cell !important; +} + +@media (max-width: 767px) { + .hidden-xs, + tr.hidden-xs, + th.hidden-xs, + td.hidden-xs { + display: none !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .hidden-xs.hidden-sm, + tr.hidden-xs.hidden-sm, + th.hidden-xs.hidden-sm, + td.hidden-xs.hidden-sm { + display: none !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-xs.hidden-md, + tr.hidden-xs.hidden-md, + th.hidden-xs.hidden-md, + td.hidden-xs.hidden-md { + display: none !important; + } +} + +@media (min-width: 1200px) { + .hidden-xs.hidden-lg, + tr.hidden-xs.hidden-lg, + th.hidden-xs.hidden-lg, + td.hidden-xs.hidden-lg { + display: none !important; + } +} + +.hidden-sm { + display: block !important; +} + +table.hidden-sm { + display: table; +} + +tr.hidden-sm { + display: table-row !important; +} + +th.hidden-sm, +td.hidden-sm { + display: table-cell !important; +} + +@media (max-width: 767px) { + .hidden-sm.hidden-xs, + tr.hidden-sm.hidden-xs, + th.hidden-sm.hidden-xs, + td.hidden-sm.hidden-xs { + display: none !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .hidden-sm, + tr.hidden-sm, + th.hidden-sm, + td.hidden-sm { + display: none !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-sm.hidden-md, + tr.hidden-sm.hidden-md, + th.hidden-sm.hidden-md, + td.hidden-sm.hidden-md { + display: none !important; + } +} + +@media (min-width: 1200px) { + .hidden-sm.hidden-lg, + tr.hidden-sm.hidden-lg, + th.hidden-sm.hidden-lg, + td.hidden-sm.hidden-lg { + display: none !important; + } +} + +.hidden-md { + display: block !important; +} + +table.hidden-md { + display: table; +} + +tr.hidden-md { + display: table-row !important; +} + +th.hidden-md, +td.hidden-md { + display: table-cell !important; +} + +@media (max-width: 767px) { + .hidden-md.hidden-xs, + tr.hidden-md.hidden-xs, + th.hidden-md.hidden-xs, + td.hidden-md.hidden-xs { + display: none !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .hidden-md.hidden-sm, + tr.hidden-md.hidden-sm, + th.hidden-md.hidden-sm, + td.hidden-md.hidden-sm { + display: none !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-md, + tr.hidden-md, + th.hidden-md, + td.hidden-md { + display: none !important; + } +} + +@media (min-width: 1200px) { + .hidden-md.hidden-lg, + tr.hidden-md.hidden-lg, + th.hidden-md.hidden-lg, + td.hidden-md.hidden-lg { + display: none !important; + } +} + +.hidden-lg { + display: block !important; +} + +table.hidden-lg { + display: table; +} + +tr.hidden-lg { + display: table-row !important; +} + +th.hidden-lg, +td.hidden-lg { + display: table-cell !important; +} + +@media (max-width: 767px) { + .hidden-lg.hidden-xs, + tr.hidden-lg.hidden-xs, + th.hidden-lg.hidden-xs, + td.hidden-lg.hidden-xs { + display: none !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .hidden-lg.hidden-sm, + tr.hidden-lg.hidden-sm, + th.hidden-lg.hidden-sm, + td.hidden-lg.hidden-sm { + display: none !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-lg.hidden-md, + tr.hidden-lg.hidden-md, + th.hidden-lg.hidden-md, + td.hidden-lg.hidden-md { + display: none !important; + } +} + +@media (min-width: 1200px) { + .hidden-lg, + tr.hidden-lg, + th.hidden-lg, + td.hidden-lg { + display: none !important; + } +} + +.visible-print, +tr.visible-print, +th.visible-print, +td.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; + } + .hidden-print, + tr.hidden-print, + th.hidden-print, + td.hidden-print { + display: none !important; + } +} \ No newline at end of file diff --git a/tools/analysis/VisualFAIL/css/bootstrap.min.css b/tools/analysis/VisualFAIL/css/bootstrap.min.css new file mode 100644 index 00000000..c547283b --- /dev/null +++ b/tools/analysis/VisualFAIL/css/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.0.3 (http://getbootstrap.com) + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + */ + +/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}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}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!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}@page{margin:2cm .5cm}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}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;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}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-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}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;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:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small{font-size:65%}h4,h5,h6{margin-top:10px;margin-bottom:10px}h4 small,h5 small,h6 small,h4 .small,h5 .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:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-primary:hover{color:#3071a9}.text-warning{color:#8a6d3b}.text-warning:hover{color:#66512c}.text-danger{color:#a94442}.text-danger:hover{color:#843534}.text-success{color:#3c763d}.text-success:hover{color:#2b542c}.text-info{color:#31708f}.text-info:hover{color:#245269}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.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;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}.list-inline>li:first-child{padding-left:0}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}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}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small,blockquote .small{display:block;line-height:1.428571429;color:#999}blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small,blockquote.pull-right .small{text-align:right}blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}blockquote.pull-right 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.428571429}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;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}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}@media(min-width:768px){.container{width:750px}}@media(min-width:992px){.container{width:970px}}@media(min-width:1200px){.container{width:1170px}}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.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.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.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.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.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.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.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.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{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.428571429;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-"]{display:table-cell;float:none}.table>thead>tr>.active,.table>tbody>tr>.active,.table>tfoot>tr>.active,.table>thead>.active>td,.table>tbody>.active>td,.table>tfoot>.active>td,.table>thead>.active>th,.table>tbody>.active>th,.table>tfoot>.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>.active:hover,.table-hover>tbody>.active:hover>td,.table-hover>tbody>.active:hover>th{background-color:#e8e8e8}.table>thead>tr>.success,.table>tbody>tr>.success,.table>tfoot>tr>.success,.table>thead>.success>td,.table>tbody>.success>td,.table>tfoot>.success>td,.table>thead>.success>th,.table>tbody>.success>th,.table>tfoot>.success>th{background-color:#dff0d8}.table-hover>tbody>tr>.success:hover,.table-hover>tbody>.success:hover>td,.table-hover>tbody>.success:hover>th{background-color:#d0e9c6}.table>thead>tr>.danger,.table>tbody>tr>.danger,.table>tfoot>tr>.danger,.table>thead>.danger>td,.table>tbody>.danger>td,.table>tfoot>.danger>td,.table>thead>.danger>th,.table>tbody>.danger>th,.table>tfoot>.danger>th{background-color:#f2dede}.table-hover>tbody>tr>.danger:hover,.table-hover>tbody>.danger:hover>td,.table-hover>tbody>.danger:hover>th{background-color:#ebcccc}.table>thead>tr>.warning,.table>tbody>tr>.warning,.table>tfoot>tr>.warning,.table>thead>.warning>td,.table>tbody>.warning>td,.table>tfoot>.warning>td,.table>thead>.warning>th,.table>tbody>.warning>th,.table>tfoot>.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>.warning:hover,.table-hover>tbody>.warning:hover>td,.table-hover>tbody>.warning:hover>th{background-color:#faf2cc}@media(max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.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{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;margin-bottom:5px;font-weight:bold}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}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}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}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-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,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;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:normal;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],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{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{height:auto}.input-lg{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{height:auto}.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,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-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,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.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,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.form-control-static{margin-bottom: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}.form-inline select.form-control{width:auto}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.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}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-control-static{padding-top:7px}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn: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,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.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:#ebebeb;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:#fff}.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:#3276b1;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-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:#ed9c28;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:#d2322d;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-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:#47a447;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:#39b3d7;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-link{font-weight:normal;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:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.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;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1;-moz-osx-font-smoothing:grayscale}.glyphicon:empty{width:1em}.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"}.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;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.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:normal;line-height:1.428571429;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:#999}.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-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.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{border-top:0;border-bottom:4px solid;content:""}.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}}.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:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-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-bottom-left-radius:0;border-top-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-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.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,0.125);box-shadow:inset 0 3px 5px rgba(0,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:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.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-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.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{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{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{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:normal;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>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){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>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn:first-child>.btn{margin-right:-1px}.input-group-btn:last-child>.btn{margin-left:-1px}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.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:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;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.428571429;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-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;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}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.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}@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;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{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 .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;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,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.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}.navbar-form select.form-control{width:auto}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left: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-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.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:#ccc}.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-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.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:#999}.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:#999}.navbar-inverse .navbar-link:hover{color:#fff}.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:#999}.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.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-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{background-color:#eee}.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:#999;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-bottom-left-radius:6px;border-top-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-bottom-left-radius:3px;border-top-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:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.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:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.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:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}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;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.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.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{display:block;height:auto;max-width:100%;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:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .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}}@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,0.1);box-shadow:inset 0 1px 2px rgba(0,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,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.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,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.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,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.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,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.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-right-radius:4px;border-top-left-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{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.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,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child th,.panel>.table>tbody: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:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.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,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.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{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-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-group .panel{margin-bottom:0;overflow:hidden;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-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-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-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.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-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-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.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-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.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,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,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:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;z-index:1050;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.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}@media screen and (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.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-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.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:normal;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{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.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;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;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,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;outline:0;opacity:.9;filter:alpha(opacity=90)}.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%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-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,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix: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}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{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(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}table.visible-xs.visible-sm{display:table}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}table.visible-xs.visible-md{display:table}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}table.visible-xs.visible-lg{display:table}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}table.visible-sm.visible-xs{display:table}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!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:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}table.visible-sm.visible-md{display:table}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}table.visible-sm.visible-lg{display:table}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}table.visible-md.visible-xs{display:table}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}table.visible-md.visible-sm{display:table}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!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:1200px){.visible-md.visible-lg{display:block!important}table.visible-md.visible-lg{display:table}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}table.visible-lg.visible-xs{display:table}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}table.visible-lg.visible-sm{display:table}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}table.visible-lg.visible-md{display:table}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!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}}.hidden-xs{display:block!important}table.hidden-xs{display:table}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,tr.hidden-xs.hidden-md,th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}table.hidden-sm{display:table}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,tr.hidden-sm.hidden-md,th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}table.hidden-md{display:table}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs,tr.hidden-md.hidden-xs,th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,tr.hidden-md.hidden-sm,th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg,tr.hidden-md.hidden-lg,th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}table.hidden-lg{display:table}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs,tr.hidden-lg.hidden-xs,th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm,tr.hidden-lg.hidden-sm,th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md,tr.hidden-lg.hidden-md,th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.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}.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}} \ No newline at end of file diff --git a/tools/analysis/VisualFAIL/css/myStyle.css b/tools/analysis/VisualFAIL/css/myStyle.css new file mode 100644 index 00000000..b99a9041 --- /dev/null +++ b/tools/analysis/VisualFAIL/css/myStyle.css @@ -0,0 +1,23 @@ +body { + min-height: 2000px; + padding-top: 70px; +} + +/* Custom container */ +.container-full { + margin: 0 auto; + padding: 0 15px; + width: 100%; +} + +.logo { + padding: 0 0 0 30px; +} + +.sourcecode { + font-weight: bold; +} + +#analyse { + margin: 20px 0 0 0; +} diff --git a/tools/analysis/VisualFAIL/favicon.ico b/tools/analysis/VisualFAIL/favicon.ico new file mode 100644 index 00000000..0affa09b Binary files /dev/null and b/tools/analysis/VisualFAIL/favicon.ico differ diff --git a/tools/analysis/VisualFAIL/fonts/glyphicons-halflings-regular.eot b/tools/analysis/VisualFAIL/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 00000000..423bd5d3 Binary files /dev/null and b/tools/analysis/VisualFAIL/fonts/glyphicons-halflings-regular.eot differ diff --git a/tools/analysis/VisualFAIL/fonts/glyphicons-halflings-regular.svg b/tools/analysis/VisualFAIL/fonts/glyphicons-halflings-regular.svg new file mode 100644 index 00000000..44694887 --- /dev/null +++ b/tools/analysis/VisualFAIL/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/analysis/VisualFAIL/fonts/glyphicons-halflings-regular.ttf b/tools/analysis/VisualFAIL/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 00000000..a498ef4e Binary files /dev/null and b/tools/analysis/VisualFAIL/fonts/glyphicons-halflings-regular.ttf differ diff --git a/tools/analysis/VisualFAIL/fonts/glyphicons-halflings-regular.woff b/tools/analysis/VisualFAIL/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 00000000..d83c539b Binary files /dev/null and b/tools/analysis/VisualFAIL/fonts/glyphicons-halflings-regular.woff differ diff --git a/tools/analysis/VisualFAIL/images/ajax-loader.gif b/tools/analysis/VisualFAIL/images/ajax-loader.gif new file mode 100644 index 00000000..cc70a7a8 Binary files /dev/null and b/tools/analysis/VisualFAIL/images/ajax-loader.gif differ diff --git a/tools/analysis/VisualFAIL/images/hintergrund.png b/tools/analysis/VisualFAIL/images/hintergrund.png new file mode 100644 index 00000000..dd51417b Binary files /dev/null and b/tools/analysis/VisualFAIL/images/hintergrund.png differ diff --git a/tools/analysis/VisualFAIL/images/logos/danceoslogo.jpg b/tools/analysis/VisualFAIL/images/logos/danceoslogo.jpg new file mode 100644 index 00000000..054eb5e2 Binary files /dev/null and b/tools/analysis/VisualFAIL/images/logos/danceoslogo.jpg differ diff --git a/tools/analysis/VisualFAIL/images/logos/visualfaillogo.png b/tools/analysis/VisualFAIL/images/logos/visualfaillogo.png new file mode 100644 index 00000000..9675fed8 Binary files /dev/null and b/tools/analysis/VisualFAIL/images/logos/visualfaillogo.png differ diff --git a/tools/analysis/VisualFAIL/images/logos/visualfaillogo_klein.png b/tools/analysis/VisualFAIL/images/logos/visualfaillogo_klein.png new file mode 100644 index 00000000..df8dbed1 Binary files /dev/null and b/tools/analysis/VisualFAIL/images/logos/visualfaillogo_klein.png differ diff --git a/tools/analysis/VisualFAIL/index.php b/tools/analysis/VisualFAIL/index.php new file mode 100644 index 00000000..9d51675b --- /dev/null +++ b/tools/analysis/VisualFAIL/index.php @@ -0,0 +1,131 @@ + + + + + + + + + + + Visual FAIL* + + + + + + + + + + + + + + + + + +
+ + +
+
+ +
+
Coloring
+
+ +
+
+ +
+
Benchmark
+
+ +
+
+ +
+
Variant
+
+ +
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+						
+
+						
+
+
+
+
+ + + + + + + + diff --git a/tools/analysis/VisualFAIL/js/bootstrap.js b/tools/analysis/VisualFAIL/js/bootstrap.js new file mode 100644 index 00000000..850e6e53 --- /dev/null +++ b/tools/analysis/VisualFAIL/js/bootstrap.js @@ -0,0 +1,2006 @@ +/*! + * Bootstrap v3.0.3 (http://getbootstrap.com) + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + */ + +if (typeof jQuery === "undefined") { throw new Error("Bootstrap requires jQuery") } + +/* ======================================================================== + * Bootstrap: transition.js v3.0.3 + * http://getbootstrap.com/javascript/#transitions + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ + + function transitionEnd() { + var el = document.createElement('bootstrap') + + var transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd otransitionend' + , 'transition' : 'transitionend' + } + + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } + } + } + + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function (duration) { + var called = false, $el = this + $(this).one($.support.transition.end, function () { called = true }) + var callback = function () { if (!called) $($el).trigger($.support.transition.end) } + setTimeout(callback, duration) + return this + } + + $(function () { + $.support.transition = transitionEnd() + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: alert.js v3.0.3 + * http://getbootstrap.com/javascript/#alerts + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // ALERT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.hasClass('alert') ? $this : $this.parent() + } + + $parent.trigger(e = $.Event('close.bs.alert')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent.trigger('closed.bs.alert').remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent + .one($.support.transition.end, removeElement) + .emulateTransitionEnd(150) : + removeElement() + } + + + // ALERT PLUGIN DEFINITION + // ======================= + + var old = $.fn.alert + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.alert') + + if (!data) $this.data('bs.alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + // ALERT NO CONFLICT + // ================= + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + // ALERT DATA-API + // ============== + + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: button.js v3.0.3 + * http://getbootstrap.com/javascript/#buttons + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + } + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (!data.resetText) $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d); + }, 0) + } + + Button.prototype.toggle = function () { + var $parent = this.$element.closest('[data-toggle="buttons"]') + var changed = true + + if ($parent.length) { + var $input = this.$element.find('input') + if ($input.prop('type') === 'radio') { + // see if clicking on current one + if ($input.prop('checked') && this.$element.hasClass('active')) + changed = false + else + $parent.find('.active').removeClass('active') + } + if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') + } + + if (changed) this.$element.toggleClass('active') + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + var old = $.fn.button + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + e.preventDefault() + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: carousel.js v3.0.3 + * http://getbootstrap.com/javascript/#carousel + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = + this.sliding = + this.interval = + this.$active = + this.$items = null + + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.DEFAULTS = { + interval: 5000 + , pause: 'hover' + , wrap: true + } + + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) + + this.interval && clearInterval(this.interval) + + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + + return this + } + + Carousel.prototype.getActiveIndex = function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + + return this.$items.index(this.$active) + } + + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getActiveIndex() + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) + if (activeIndex == pos) return this.pause().cycle() + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + Carousel.prototype.pause = function (e) { + e || (this.paused = true) + + if (this.$element.find('.next, .prev').length && $.support.transition.end) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + + this.interval = clearInterval(this.interval) + + return this + } + + Carousel.prototype.next = function () { + if (this.sliding) return + return this.slide('next') + } + + Carousel.prototype.prev = function () { + if (this.sliding) return + return this.slide('prev') + } + + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || $active[type]() + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var fallback = type == 'next' ? 'first' : 'last' + var that = this + + if (!$next.length) { + if (!this.options.wrap) return + $next = this.$element.find('.item')[fallback]() + } + + this.sliding = true + + isCycling && this.pause() + + var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) + + if ($next.hasClass('active')) return + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid.bs.carousel', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0) + }) + .emulateTransitionEnd(600) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid.bs.carousel') + } + + isCycling && this.cycle() + + return this + } + + + // CAROUSEL PLUGIN DEFINITION + // ========================== + + var old = $.fn.carousel + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide + + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + $.fn.carousel.Constructor = Carousel + + + // CAROUSEL NO CONFLICT + // ==================== + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + + // CAROUSEL DATA-API + // ================= + + $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) options.interval = false + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('bs.carousel').to(slideIndex) + } + + e.preventDefault() + }) + + $(window).on('load', function () { + $('[data-ride="carousel"]').each(function () { + var $carousel = $(this) + $carousel.carousel($carousel.data()) + }) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: collapse.js v3.0.3 + * http://getbootstrap.com/javascript/#collapse + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.transitioning = null + + if (this.options.parent) this.$parent = $(this.options.parent) + if (this.options.toggle) this.toggle() + } + + Collapse.DEFAULTS = { + toggle: true + } + + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) return + + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var actives = this.$parent && this.$parent.find('> .panel > .in') + + if (actives && actives.length) { + var hasData = actives.data('bs.collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('bs.collapse', null) + } + + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + .addClass('collapsing') + [dimension](0) + + this.transitioning = 1 + + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('in') + [dimension]('auto') + this.transitioning = 0 + this.$element.trigger('shown.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + var scrollSize = $.camelCase(['scroll', dimension].join('-')) + + this.$element + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + [dimension](this.$element[0][scrollSize]) + } + + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) return + + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var dimension = this.dimension() + + this.$element + [dimension](this.$element[dimension]()) + [0].offsetHeight + + this.$element + .addClass('collapsing') + .removeClass('collapse') + .removeClass('in') + + this.transitioning = 1 + + var complete = function () { + this.transitioning = 0 + this.$element + .trigger('hidden.bs.collapse') + .removeClass('collapsing') + .addClass('collapse') + } + + if (!$.support.transition) return complete.call(this) + + this.$element + [dimension](0) + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + } + + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + + // COLLAPSE PLUGIN DEFINITION + // ========================== + + var old = $.fn.collapse + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.Constructor = Collapse + + + // COLLAPSE NO CONFLICT + // ==================== + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + // COLLAPSE DATA-API + // ================= + + $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + var target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + var $target = $(target) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $this.data() + var parent = $this.attr('data-parent') + var $parent = parent && $(parent) + + if (!data || !data.transitioning) { + if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') + $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + } + + $target.collapse(option) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: dropdown.js v3.0.3 + * http://getbootstrap.com/javascript/#dropdowns + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // DROPDOWN CLASS DEFINITION + // ========================= + + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle=dropdown]' + var Dropdown = function (element) { + $(element).on('click.bs.dropdown', this.toggle) + } + + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we use a backdrop because click events don't delegate + $('