diff --git a/scripts/install b/scripts/install index 9bae0b2..4caba1e 100644 --- a/scripts/install +++ b/scripts/install @@ -56,6 +56,8 @@ if [ ! -d $final_path ]; then sudo mkdir -p $final_path fi +wget https://github.com/asciimoo/searx/archive/v0.10.0.tar.gz +tar xvf v0.10.0.tar.gz && cp -rf searx-0.10.0/* ../sources sudo cp -r ../sources/* $final_path sudo virtualenv --system-site-packages $final_path sudo bash -c "source $final_path/bin/activate && pip install -r $final_path/requirements-ynh.txt" diff --git a/scripts/upgrade b/scripts/upgrade index 57a481c..9ae81ca 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -37,7 +37,9 @@ then fi final_path=/opt/yunohost/$app -sudo cp -r ../sources/* $final_path +wget https://github.com/asciimoo/searx/archive/v0.10.0.tar.gz +tar xvf v0.10.0.tar.gz && cp -rf searx-0.10.0/* ../sources +sudo cp -rf ../sources/* $final_path sudo bash -c "source $final_path/bin/activate && pip install -r $final_path/requirements-ynh.txt --upgrade" # Disable swapfile diff --git a/sources/.coveragerc b/sources/.coveragerc deleted file mode 100644 index 4f50efc..0000000 --- a/sources/.coveragerc +++ /dev/null @@ -1,20 +0,0 @@ -[run] -branch = True -source = - searx/engines - searx/__init__.py - searx/autocomplete.py - searx/https_rewrite.py - searx/languages.py - searx/search.py - searx/testing.py - searx/utils.py - searx/webapp.py - -[report] -show_missing = True -exclude_lines = - if __name__ == .__main__.: - -[html] -directory = coverage diff --git a/sources/.gitignore b/sources/.gitignore deleted file mode 100644 index 105f019..0000000 --- a/sources/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -.coverage -.installed.cfg -engines.cfg -env -robot_log.html -robot_output.xml -robot_report.html -test_basic/ -setup.cfg - -*.pyc -*/*.pyc -*~ - -node_modules/ - -.tx/ diff --git a/sources/.landscape.yaml b/sources/.landscape.yaml deleted file mode 100644 index 1bb3977..0000000 --- a/sources/.landscape.yaml +++ /dev/null @@ -1,3 +0,0 @@ -strictness: high -ignore-paths: - - bootstrap.py diff --git a/sources/.travis.yml b/sources/.travis.yml deleted file mode 100644 index 3bef5e5..0000000 --- a/sources/.travis.yml +++ /dev/null @@ -1,32 +0,0 @@ -sudo: false -cache: - - pip - - npm - - directories: - - $HOME/.cache/pip -language: python -python: - - "2.7" -before_install: - - "export DISPLAY=:99.0" - - "sh -e /etc/init.d/xvfb start" - - npm install less grunt-cli - - ( cd searx/static/themes/oscar;npm install; cd - ) -install: - - ./manage.sh update_dev_packages - - pip install coveralls -script: - - ./manage.sh pep8_check - - ./manage.sh styles - - ./manage.sh grunt_build - - ./manage.sh py_test_coverage - - ./manage.sh robot_tests -after_success: - coveralls -notifications: - irc: - channels: - - "irc.freenode.org#searx" - template: - - "%{repository}/#%{build_number}/%{branch} (%{author}): %{message} %{build_url}" - on_success: change diff --git a/sources/AUTHORS.rst b/sources/AUTHORS.rst deleted file mode 100644 index 5bc6807..0000000 --- a/sources/AUTHORS.rst +++ /dev/null @@ -1,53 +0,0 @@ -Searx was created by Adam Tauber and is maintained by Adam Tauber and Alexandre Flament. - -Major contributing authors: - -- Adam Tauber `@asciimoo `_ -- Matej Cotman -- Thomas Pointhuber -- Alexandre Flament `@dalf `_ -- @Cqoicebordel - -People who have submitted patches/translates, reported bugs, consulted features or -generally made searx better: - -- Laszlo Hammerl -- Stefan Marsiske -- Gabor Nagy -- @pw3t -- @rhapsodhy -- András Veres-Szentkirályi -- Benjamin Sonntag -- @HLFH -- @TheRadialActive -- @Okhin -- André Koot -- Alejandro León Aznar -- rike -- dp -- Martin Zimmermann -- @courgette -- @kernc -- @Reventl0v -- Caner Başaran -- Benjamin Sonntag -- @opi -- @dimqua -- Giorgos Logiotatidis -- Luc Didry -- Niklas Haas -- @underr -- Emmanuel Benazera -- @GreenLunar -- Noemi Vanyi -- Kang-min Liu -- Kirill Isakov -- Guilhem Bonnefille -- Marc Abonce Seguin - -- @jibe-b -- Christian Pietsch @pietsch -- @Maxqia -- Ashutosh Das @pyprism -- YuLun Shih @imZack -- Dmitry Mikhirev @mikhirev diff --git a/sources/CHANGELOG.rst b/sources/CHANGELOG.rst deleted file mode 100644 index 8907ab4..0000000 --- a/sources/CHANGELOG.rst +++ /dev/null @@ -1,164 +0,0 @@ -0.9.0 2016.05.24 -================ - -- New search category: science -- New engines - - - Wolframalpha (science) - - Frinkiac (images) - - Arch Linux (it) - - BASE - Bielefeld Academic Search Engine (science) - - Dokuwiki (general) - - Nyaa.se (files, images, music, video) - - Reddit (general, images, news, social media) - - Torrentz.eu (files, music, video) - - Tokyo Toshokan (files, music, video) - - F-Droid (files) - - Erowid (general) - - Bitbucket (it) - - GitLab (it) - - Geektimes (it) - - Habrahabr (it) -- New plugins - - - Open links in new tab - - Vim hotkeys for better navigation -- Wikipedia/Mediawiki engine improvements -- Configurable instance name -- Configurable connection pool size -- Fixed broken google engine -- Better docker image -- Images in standard results -- Fixed and refactored user settings (Warning: backward incompatibility - you have to reset your custom engine preferences) -- Suspending engines on errors -- Simplified development/deployment tooling -- Translation updates -- Multilingual autocompleter -- Qwant autocompleter backend - -0.8.1 2015.12.22 -================ - -- More efficient result parsing -- Rewritten google engine to prevent app crashes -- Other engine fixes/tweaks - - - Bing news - - Btdigg - - Gigablast - - Google images - - Startpage - - -News -~~~~ - -New documentation page is available: https://asciimoo.github.io/searx - - -0.8.0 2015.09.08 -================ - -- New engines - - - Blekko (image) - - Gigablast (general) - - Spotify (music) - - Swisscows (general, images) - - Qwant (general, images, news, social media) -- Plugin system -- New plugins - - - HTTPS rewrite - - Search on cagetory select - - User information - - Tracker url part remover -- Multiple outgoing IP and HTTP/HTTPS proxy support -- New autocompleter: startpage -- New theme: pix-art -- Settings file structure change -- Fabfile, docker deployment -- Optional safesearch result filter -- Force HTTPS in engines if possible -- Disabled HTTP referrer on outgoing links -- Display cookie information -- Prettier search URLs -- Right-to-left text handling in themes -- Translation updates (New locales: Chinese, Hebrew, Portuguese, Romanian) - - -New dependencies -~~~~~~~~~~~~~~~~ - -- pyopenssl -- ndg-httpsclient -- pyasn1 -- pyasn1-modules -- certifi - - -News -~~~~ - -@dalf joined the maintainer "team" - - -0.7.0 2015.02.03 -================ - -- New engines - - - Digg - - Google Play Store - - Deezer - - Btdigg - - Mixcloud - - 1px -- Image proxy -- Search speed improvements -- Autocompletition of engines, shortcuts and supported languages -- Translation updates (New locales: Turkish, Russian) -- Default theme changed to oscar -- Settings option to disable engines by default -- UI code cleanup and restructure -- Engine tests -- Multiple engine bug fixes and tweaks -- Config option to set default interface locale -- Flexible result template handling -- Application logging and sophisticated engine exception tracebacks -- Kickass torrent size display (oscar theme) - - -New dependencies -~~~~~~~~~~~~~~~~ - -- pygments - http://pygments.org/ - - -0.6.0 - 2014.12.25 -================== - -- Changelog added -- New engines - - - Flickr (api) - - Subtitleseeker - - photon - - 500px - - Searchcode - - Searchcode doc - - Kickass torrent -- Precise search request timeout handling -- Better favicon support -- Stricter config parsing -- Translation updates -- Multiple ui fixes -- Flickr (noapi) engine fix -- Pep8 fixes - - -News -~~~~ - -Health status of searx instances and engines: http://stats.searx.oe5tpo.com -(source: https://github.com/pointhi/searx_stats) diff --git a/sources/Dockerfile b/sources/Dockerfile deleted file mode 100644 index 387669b..0000000 --- a/sources/Dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -FROM alpine:3.3 -MAINTAINER searx -LABEL description "A privacy-respecting, hackable metasearch engine." - -ENV BASE_URL=False IMAGE_PROXY=False -EXPOSE 8888 -WORKDIR /usr/local/searx -CMD ["/usr/bin/tini","--","/usr/local/searx/run.sh"] - -RUN adduser -D -h /usr/local/searx -s /bin/sh searx searx \ - && echo '#!/bin/sh' >> run.sh \ - && echo 'sed -i "s|base_url : False|base_url : $BASE_URL|g" searx/settings.yml' >> run.sh \ - && echo 'sed -i "s/image_proxy : False/image_proxy : $IMAGE_PROXY/g" searx/settings.yml' >> run.sh \ - && echo 'sed -i "s/ultrasecretkey/`openssl rand -hex 16`/g" searx/settings.yml' >> run.sh \ - && echo 'python searx/webapp.py' >> run.sh \ - && chmod +x run.sh - -COPY requirements.txt ./requirements.txt - -RUN echo "@commuedge http://nl.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories \ - && apk -U add \ - build-base \ - python \ - python-dev \ - py-pip \ - libxml2 \ - libxml2-dev \ - libxslt \ - libxslt-dev \ - libffi-dev \ - openssl \ - openssl-dev \ - ca-certificates \ - tini@commuedge \ - && pip install --no-cache -r requirements.txt \ - && apk del \ - build-base \ - python-dev \ - py-pip\ - libffi-dev \ - openssl-dev \ - libxslt-dev \ - libxml2-dev \ - openssl-dev \ - ca-certificates \ - && rm -f /var/cache/apk/* - -COPY . . - -RUN chown -R searx:searx * - -USER searx - -RUN sed -i "s/127.0.0.1/0.0.0.0/g" searx/settings.yml diff --git a/sources/LICENSE b/sources/LICENSE deleted file mode 100644 index dba13ed..0000000 --- a/sources/LICENSE +++ /dev/null @@ -1,661 +0,0 @@ - GNU AFFERO GENERAL PUBLIC LICENSE - Version 3, 19 November 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 Affero General Public License is a free, copyleft license for -software and other kinds of works, specifically designed to ensure -cooperation with the community in the case of network server software. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -our General Public Licenses are 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. - - 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. - - Developers that use our General Public Licenses protect your rights -with two steps: (1) assert copyright on the software, and (2) offer -you this License which gives you legal permission to copy, distribute -and/or modify the software. - - A secondary benefit of defending all users' freedom is that -improvements made in alternate versions of the program, if they -receive widespread use, become available for other developers to -incorporate. Many developers of free software are heartened and -encouraged by the resulting cooperation. However, in the case of -software used on network servers, this result may fail to come about. -The GNU General Public License permits making a modified version and -letting the public access it on a server without ever releasing its -source code to the public. - - The GNU Affero General Public License is designed specifically to -ensure that, in such cases, the modified source code becomes available -to the community. It requires the operator of a network server to -provide the source code of the modified version running there to the -users of that server. Therefore, public use of a modified version, on -a publicly accessible server, gives the public access to the source -code of the modified version. - - An older license, called the Affero General Public License and -published by Affero, was designed to accomplish similar goals. This is -a different license, not a version of the Affero GPL, but Affero has -released a new version of the Affero GPL which permits relicensing under -this license. - - 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License. - - Notwithstanding any other provision of this License, if you modify the -Program, your modified version must prominently offer all users -interacting with it remotely through a computer network (if your version -supports such interaction) an opportunity to receive the Corresponding -Source of your version by providing access to the Corresponding Source -from a network server at no charge, through some standard or customary -means of facilitating copying of software. This Corresponding Source -shall include the Corresponding Source for any work covered by version 3 -of the GNU General Public License that is incorporated pursuant to the -following paragraph. - - 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 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 work with which it is combined will remain governed by version -3 of the GNU General Public License. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If your software can interact with users remotely through a computer -network, you should also make sure that it provides a way for users to -get its source. For example, if your program is a web application, its -interface could display a "Source" link that leads users to an archive -of the code. There are many ways you could offer source, and different -solutions will be better for different programs; see section 13 for the -specific requirements. - - 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 AGPL, see -. diff --git a/sources/README.rst b/sources/README.rst deleted file mode 100644 index 6563fe8..0000000 --- a/sources/README.rst +++ /dev/null @@ -1,45 +0,0 @@ -searx -===== - -A privacy-respecting, hackable `metasearch -engine `__. - -List of `running -instances `__. - -See the `documentation `__ and the `wiki `__ for more information. - -|Flattr searx| - -Installation -~~~~~~~~~~~~ - -- clone source: - ``git clone git@github.com:asciimoo/searx.git && cd searx`` -- install dependencies: ``./manage.sh update_packages`` -- edit your - `settings.yml `__ - (set your ``secret_key``!) -- run ``python searx/webapp.py`` to start the application - -For all the details, follow this `step by step -installation `__ - -Bugs -~~~~ - -Bugs or suggestions? Visit the `issue -tracker `__. - -`License `__ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -More about searx -~~~~~~~~~~~~~~~~ - -- `ohloh `__ -- `twitter `__ -- IRC: #searx @ freenode - -.. |Flattr searx| image:: http://api.flattr.com/button/flattr-badge-large.png - :target: https://flattr.com/submit/auto?user_id=asciimoo&url=https://github.com/asciimoo/searx&title=searx&language=&tags=github&category=software diff --git a/sources/babel.cfg b/sources/babel.cfg deleted file mode 100644 index f0234b3..0000000 --- a/sources/babel.cfg +++ /dev/null @@ -1,3 +0,0 @@ -[python: **.py] -[jinja2: **/templates/**.html] -extensions=jinja2.ext.autoescape,jinja2.ext.with_ diff --git a/sources/examples/basic_engine.py b/sources/examples/basic_engine.py deleted file mode 100644 index d786564..0000000 --- a/sources/examples/basic_engine.py +++ /dev/null @@ -1,25 +0,0 @@ - -categories = ['general'] # optional - -def request(query, params): - '''pre-request callback - params: - method : POST/GET - headers : {} - data : {} # if method == POST - url : '' - category: 'search category' - pageno : 1 # number of the requested page - ''' - - params['url'] = 'https://host/%s' % query - - return params - - -def response(resp): - '''post-response callback - resp: requests response object - ''' - return [{'url': '', 'title': '', 'content': ''}] - diff --git a/sources/manage.sh b/sources/manage.sh deleted file mode 100755 index 0a21f0e..0000000 --- a/sources/manage.sh +++ /dev/null @@ -1,95 +0,0 @@ -#!/bin/sh - -BASE_DIR=$(dirname `readlink -f $0`) -PYTHONPATH=$BASE_DIR -SEARX_DIR="$BASE_DIR/searx" -ACTION=$1 - -update_packages() { - pip install --upgrade -r "$BASE_DIR/requirements.txt" -} - -update_dev_packages() { - update_packages - pip install --upgrade -r "$BASE_DIR/requirements-dev.txt" -} - -pep8_check() { - echo '[!] Running pep8 check' - # ignored rules: - # E402 module level import not at top of file - # W503 line break before binary operator - pep8 --max-line-length=120 --ignore "E402,W503" "$SEARX_DIR" "$BASE_DIR/tests" -} - -unit_tests() { - echo '[!] Running unit tests' - python -m nose2 -s "$BASE_DIR/tests/unit" -} - -py_test_coverage() { - echo '[!] Running python test coverage' - PYTHONPATH=`pwd` python -m nose2 -C --coverage "$SEARX_DIR" -s "$BASE_DIR/tests/unit" - coverage report - coverage html -} - -robot_tests() { - echo '[!] Running robot tests' - PYTHONPATH=`pwd` python "$SEARX_DIR/testing.py" robot -} - -tests() { - set -e - pep8_check - unit_tests - robot_tests - set +e -} - -build_style() { - lessc -x "$BASE_DIR/searx/static/$1" "$BASE_DIR/searx/static/$2" -} - -styles() { - echo '[!] Building styles' - build_style themes/default/less/style.less themes/default/css/style.css - build_style themes/default/less/style-rtl.less themes/default/css/style-rtl.css - build_style themes/courgette/less/style.less themes/courgette/css/style.css - build_style themes/courgette/less/style-rtl.less themes/courgette/css/style-rtl.css - build_style less/bootstrap/bootstrap.less css/bootstrap.min.css - build_style themes/oscar/less/oscar/oscar.less themes/oscar/css/oscar.min.css - build_style themes/pix-art/less/style.less themes/pix-art/css/style.css -} - -grunt_build() { - grunt --gruntfile "$SEARX_DIR/static/themes/oscar/gruntfile.js" -} - -locales() { - pybabel compile -d "$SEARX_DIR/translations" -} - -help() { - [ -z "$1" ] || printf "Error: $1\n" - echo "Searx manage.sh help - -Commands -======== - grunt_build - Build js files - help - This text - locales - Compile locales - pep8_check - Pep8 validation - py_test_coverage - Unit test coverage - robot_tests - Run selenium tests - styles - Build less files - tests - Run all python tests (pep8, unit, robot) - unit_tests - Run unit tests - update_dev_packages - Check & update development and production dependency changes - update_packages - Check & update dependency changes -" -} - -[ "$(command -V "$ACTION" | grep ' function$')" = "" ] \ - && help "action not found" \ - || $ACTION diff --git a/sources/requirements-dev.txt b/sources/requirements-dev.txt deleted file mode 100644 index 38be888..0000000 --- a/sources/requirements-dev.txt +++ /dev/null @@ -1,10 +0,0 @@ -babel==2.2.0 -mock==1.0.1 -nose2[coverage-plugin] -pep8==1.7.0 -plone.testing==4.0.15 -robotframework-selenium2library==1.7.4 -robotsuite==1.7.0 -transifex-client==0.11 -unittest2==1.1.0 -zope.testrunner==4.4.10 diff --git a/sources/requirements.txt b/sources/requirements.txt deleted file mode 100644 index 80c08a4..0000000 --- a/sources/requirements.txt +++ /dev/null @@ -1,12 +0,0 @@ -certifi==2015.11.20.1 -flask==0.10.1 -flask-babel==0.9 -lxml==3.5.0 -ndg-httpsclient==0.4.0 -pyasn1==0.1.9 -pyasn1-modules==0.0.8 -pygments==2.0.2 -pyopenssl==0.15.1 -python-dateutil==2.4.2 -pyyaml==3.11 -requests==2.9.1 diff --git a/sources/searx/__init__.py b/sources/searx/__init__.py deleted file mode 100644 index 7b67a39..0000000 --- a/sources/searx/__init__.py +++ /dev/null @@ -1,59 +0,0 @@ -''' -searx is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -searx 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 Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with searx. If not, see < http://www.gnu.org/licenses/ >. - -(C) 2013- by Adam Tauber, -''' - -import certifi -import logging -from os import environ -from os.path import realpath, dirname, join, abspath -from ssl import OPENSSL_VERSION_INFO, OPENSSL_VERSION -try: - from yaml import load -except: - from sys import exit, stderr - stderr.write('[E] install pyyaml\n') - exit(2) - -searx_dir = abspath(dirname(__file__)) -engine_dir = dirname(realpath(__file__)) - -# if possible set path to settings using the -# enviroment variable SEARX_SETTINGS_PATH -if 'SEARX_SETTINGS_PATH' in environ: - settings_path = environ['SEARX_SETTINGS_PATH'] -# otherwise using default path -else: - settings_path = join(searx_dir, 'settings.yml') - -# load settings -with open(settings_path) as settings_yaml: - settings = load(settings_yaml) - -if settings.get('general', {}).get('debug'): - logging.basicConfig(level=logging.DEBUG) -else: - logging.basicConfig(level=logging.WARNING) - -logger = logging.getLogger('searx') - -# Workaround for openssl versions <1.0.2 -# https://github.com/certifi/python-certifi/issues/26 -if OPENSSL_VERSION_INFO[0:3] < (1, 0, 2): - if hasattr(certifi, 'old_where'): - environ['REQUESTS_CA_BUNDLE'] = certifi.old_where() - logger.warning('You are using an old openssl version({0}), please upgrade above 1.0.2!'.format(OPENSSL_VERSION)) - -logger.info('Initialisation done') diff --git a/sources/searx/autocomplete.py b/sources/searx/autocomplete.py deleted file mode 100644 index 5271040..0000000 --- a/sources/searx/autocomplete.py +++ /dev/null @@ -1,197 +0,0 @@ -''' -searx is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -searx 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 Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with searx. If not, see < http://www.gnu.org/licenses/ >. - -(C) 2013- by Adam Tauber, -''' - - -from lxml import etree -from json import loads -from urllib import urlencode -from searx import settings -from searx.languages import language_codes -from searx.engines import ( - categories, engines, engine_shortcuts -) -from searx.poolrequests import get as http_get - - -def get(*args, **kwargs): - if 'timeout' not in kwargs: - kwargs['timeout'] = settings['outgoing']['request_timeout'] - - return http_get(*args, **kwargs) - - -def searx_bang(full_query): - '''check if the searchQuery contain a bang, and create fitting autocompleter results''' - # check if there is a query which can be parsed - if len(full_query.getSearchQuery()) == 0: - return [] - - results = [] - - # check if current query stats with !bang - first_char = full_query.getSearchQuery()[0] - if first_char == '!' or first_char == '?': - if len(full_query.getSearchQuery()) == 1: - # show some example queries - # TODO, check if engine is not avaliable - results.append(first_char + "images") - results.append(first_char + "wikipedia") - results.append(first_char + "osm") - else: - engine_query = full_query.getSearchQuery()[1:] - - # check if query starts with categorie name - for categorie in categories: - if categorie.startswith(engine_query): - results.append(first_char + '{categorie}'.format(categorie=categorie)) - - # check if query starts with engine name - for engine in engines: - if engine.startswith(engine_query.replace('_', ' ')): - results.append(first_char + '{engine}'.format(engine=engine.replace(' ', '_'))) - - # check if query starts with engine shortcut - for engine_shortcut in engine_shortcuts: - if engine_shortcut.startswith(engine_query): - results.append(first_char + '{engine_shortcut}'.format(engine_shortcut=engine_shortcut)) - - # check if current query stats with :bang - elif first_char == ':': - if len(full_query.getSearchQuery()) == 1: - # show some example queries - results.append(":en") - results.append(":en_us") - results.append(":english") - results.append(":united_kingdom") - else: - engine_query = full_query.getSearchQuery()[1:] - - for lc in language_codes: - lang_id, lang_name, country = map(str.lower, lc) - - # check if query starts with language-id - if lang_id.startswith(engine_query): - if len(engine_query) <= 2: - results.append(':{lang_id}'.format(lang_id=lang_id.split('_')[0])) - else: - results.append(':{lang_id}'.format(lang_id=lang_id)) - - # check if query starts with language name - if lang_name.startswith(engine_query): - results.append(':{lang_name}'.format(lang_name=lang_name)) - - # check if query starts with country - if country.startswith(engine_query.replace('_', ' ')): - results.append(':{country}'.format(country=country.replace(' ', '_'))) - - # remove duplicates - result_set = set(results) - - # remove results which are already contained in the query - for query_part in full_query.query_parts: - if query_part in result_set: - result_set.remove(query_part) - - # convert result_set back to list - return list(result_set) - - -def dbpedia(query, lang): - # dbpedia autocompleter, no HTTPS - autocomplete_url = 'http://lookup.dbpedia.org/api/search.asmx/KeywordSearch?' - - response = get(autocomplete_url + urlencode(dict(QueryString=query))) - - results = [] - - if response.ok: - dom = etree.fromstring(response.content) - results = dom.xpath('//a:Result/a:Label//text()', - namespaces={'a': 'http://lookup.dbpedia.org/'}) - - return results - - -def duckduckgo(query, lang): - # duckduckgo autocompleter - url = 'https://ac.duckduckgo.com/ac/?{0}&type=list' - - resp = loads(get(url.format(urlencode(dict(q=query)))).text) - if len(resp) > 1: - return resp[1] - return [] - - -def google(query, lang): - # google autocompleter - autocomplete_url = 'https://suggestqueries.google.com/complete/search?client=toolbar&' - - response = get(autocomplete_url + urlencode(dict(hl=lang, q=query))) - - results = [] - - if response.ok: - dom = etree.fromstring(response.text) - results = dom.xpath('//suggestion/@data') - - return results - - -def startpage(query, lang): - # startpage autocompleter - url = 'https://startpage.com/do/suggest?{query}' - - resp = get(url.format(query=urlencode({'query': query}))).text.split('\n') - if len(resp) > 1: - return resp - return [] - - -def qwant(query, lang): - # qwant autocompleter (additional parameter : lang=en_en&count=xxx ) - url = 'https://api.qwant.com/api/suggest?{query}' - - resp = get(url.format(query=urlencode({'q': query, 'lang': lang}))) - - results = [] - - if resp.ok: - data = loads(resp.text) - if data['status'] == 'success': - for item in data['data']['items']: - results.append(item['value']) - - return results - - -def wikipedia(query, lang): - # wikipedia autocompleter - url = 'https://' + lang + '.wikipedia.org/w/api.php?action=opensearch&{0}&limit=10&namespace=0&format=json' - - resp = loads(get(url.format(urlencode(dict(search=query)))).text) - if len(resp) > 1: - return resp[1] - return [] - - -backends = {'dbpedia': dbpedia, - 'duckduckgo': duckduckgo, - 'google': google, - 'startpage': startpage, - 'qwant': qwant, - 'wikipedia': wikipedia - } diff --git a/sources/searx/data/currencies.json b/sources/searx/data/currencies.json deleted file mode 100644 index bfde5a7..0000000 --- a/sources/searx/data/currencies.json +++ /dev/null @@ -1,7655 +0,0 @@ -{ - "names": { - "francos franceses": [ - "FRF" - ], - "bulgarischer lew": [ - "BGN" - ], - "o\u0308rme\u0301ny dram": [ - "AMD" - ], - "oekrai\u0308ense hryvnja": [ - "UAH" - ], - "guatemalan quetzal": [ - "GTQ" - ], - "ghana cedi": [ - "GHS" - ], - "livre de sainte helene": [ - "SHP" - ], - "papua new guinean kina": [ - "PGK" - ], - "aud": [ - "AUD" - ], - "\u20ab": [ - "VND" - ], - "olasz li\u0301ra": [ - "ITL" - ], - "aserbaidschan manat": [ - "AZN" - ], - "ethiopian dollar": [ - "ETB" - ], - "norwegische krone": [ - "NOK" - ], - "papoea nieuw guinese kina": [ - "PGK" - ], - "som uzbeko": [ - "UZS" - ], - "yuan chino": [ - "CNY" - ], - "nuevo dolar de taiwan": [ - "TWD" - ], - "zweedse kronen": [ - "SEK" - ], - "dollar des i\u0302les cai\u0308mans": [ - "KYD" - ], - "do\u0301lar de singapur": [ - "SGD" - ], - "gru\u0301z lari": [ - "GEL" - ], - "escudo mozambiquen\u0303o": [ - "MZE" - ], - "peso filipino": [ - "PHP" - ], - "grivnia ucraniana": [ - "UAH" - ], - "salamon szigeteki dolla\u0301r": [ - "SBD" - ], - "barbados dollar": [ - "BBD" - ], - "fuang": [ - "THB" - ], - "dirham marroqui": [ - "MAD" - ], - "sri lankan rupees": [ - "LKR" - ], - "qindarka": [ - "ALL" - ], - "dinaro macedone": [ - "MKD" - ], - "togrog": [ - "MNT" - ], - "q\u0259pik": [ - "AZN" - ], - "special drawing rights": [ - "XDR" - ], - "gibralta\u0301ri font": [ - "GIP" - ], - "dinar bahraini": [ - "BHD" - ], - "marokkaanse dirham": [ - "MAD" - ], - "rouble sovie\u0301tique": [ - "SUR" - ], - "tanzanian shilling": [ - "TZS" - ], - "libra de siria": [ - "SYP" - ], - "rand sudafricano": [ - "ZAR" - ], - "seychelse roepie": [ - "SCR" - ], - "seychelse roepia": [ - "SCR" - ], - "forint": [ - "HUF" - ], - "dinar algerino": [ - "DZD" - ], - "roupie du sri lanka": [ - "LKR" - ], - "katar riyal": [ - "QAR" - ], - "schekalim": [ - "ILS" - ], - "corona checoslovaca": [ - "CSK" - ], - "baht tailande\u0301s": [ - "THB" - ], - "nuevo peso": [ - "ARS", - "UYU" - ], - "cuna croata": [ - "HRK" - ], - "nieuwe israe\u0308lische shekel": [ - "ILS" - ], - "nieuwe israelische shekel": [ - "ILS" - ], - "dollar des i\u0302les fidji": [ - "FJD" - ], - "nieuw zeelandse dollar": [ - "NZD" - ], - "tanza\u0301niai shilling": [ - "TZS" - ], - "gold franc": [ - "XFO" - ], - "tongan pa`anga": [ - "TOP" - ], - "francia frank": [ - "FRF" - ], - "brl": [ - "BRL" - ], - "isla\u0308ndische wa\u0308hrung": [ - "ISK" - ], - "guyana dollar": [ - "GYD" - ], - "dollaro australiano": [ - "AUD" - ], - "nakfa e\u0301rythre\u0301en": [ - "ERN" - ], - "kap verde escudo": [ - "CVE" - ], - "dinar iraqui\u0301": [ - "IQD" - ], - "vietnamese dong": [ - "VND" - ], - "neuer sol": [ - "PEN" - ], - "peso de argentina": [ - "ARS" - ], - "ddr mark": [ - "DDM" - ], - "br$": [ - "BND" - ], - "e\u0301szak koreai von": [ - "KPW" - ], - "japanse yen": [ - "JPY" - ], - "franco svizzero": [ - "CHF" - ], - "afghani afgano": [ - "AFN" - ], - "lira siriana": [ - "SYP" - ], - "boliviano": [ - "BOB" - ], - "vanuatui vatu": [ - "VUV" - ], - "tnd": [ - "TND" - ], - "manat turkmene": [ - "TMT" - ], - "namibia dollar": [ - "NAD" - ], - "ern": [ - "ERN" - ], - "manat turkmeno": [ - "TMT" - ], - "bds$": [ - "BBD" - ], - "bhutaanse ngultrum": [ - "BTN" - ], - "peso chilien": [ - "CLP" - ], - "dolar jamaicano": [ - "JMD" - ], - "bahamas dollar": [ - "BSD" - ], - "eritrese nakfa": [ - "ERN" - ], - "czk": [ - "CZK" - ], - "engels pond": [ - "GBP" - ], - "dolar de bermudas": [ - "BMD" - ], - "taka bangladeshi\u0301": [ - "BDT" - ], - "riyal del qatar": [ - "QAR" - ], - "kuwaiti dinar": [ - "KWD" - ], - "seychellen rupie": [ - "SCR" - ], - "boli\u0301var ve\u0301ne\u0301zue\u0301lien": [ - "VEF" - ], - "sri lanka rupie": [ - "LKR" - ], - "do\u0301lar de brunei": [ - "BND" - ], - "do\u0301lar de las islas salomo\u0301n": [ - "SBD" - ], - "lak": [ - "LAK" - ], - "sum uzbeko": [ - "UZS" - ], - "kurus\u0327": [ - "TRY" - ], - "iraqi dinar": [ - "IQD" - ], - "livre sterling": [ - "GBP" - ], - "angolai kwanza": [ - "AOA" - ], - "lat": [ - "LVL" - ], - "lek albanais": [ - "ALL" - ], - "brunei dolla\u0301r": [ - "BND" - ], - "tetri": [ - "GEL" - ], - "sterlina sudsudanese": [ - "SSP" - ], - "mo\u0308ngo\u0308": [ - "MNT" - ], - "mexican un peso coinage": [ - "MXN" - ], - "djiboutische frank": [ - "DJF" - ], - "seychelle i ru\u0301pia": [ - "SCR" - ], - "litauischer litas": [ - "LTL" - ], - "zambiaanse kwacha": [ - "ZMW" - ], - "maldi\u0301v szigeteki ru\u0301fia": [ - "MVR" - ], - "dinar bahreini\u0301": [ - "BHD" - ], - "barbadiaanse dollar": [ - "BBD" - ], - "drachme": [ - "GRD" - ], - "emalangeni": [ - "SZL" - ], - "canadese dollar": [ - "CAD" - ], - "mx$": [ - "MXN" - ], - "chinesischer renminbi": [ - "CNY" - ], - "macedonian denar": [ - "MKD" - ], - "uic franc": [ - "XFU" - ], - "won surcoreano": [ - "KRW" - ], - "nuevo shekel": [ - "ILS" - ], - "arubaanse florin": [ - "AWG" - ], - "ruanda franc": [ - "RWF" - ], - "franco burundes": [ - "BIF" - ], - "makao\u0301i pataca": [ - "MOP" - ], - "koruna c\u030ceska\u0301": [ - "CZK" - ], - "dirham des e\u0301mirats": [ - "AED" - ], - "mozambiki metical": [ - "MZN" - ], - "panamanian balboa": [ - "PAB" - ], - "syrian pound": [ - "SYP" - ], - "ki\u0301nai ju\u0308an": [ - "CNY" - ], - "mxn": [ - "MXN" - ], - "dolar fijiano": [ - "FJD" - ], - "a\u0308thiopischer birr": [ - "ETB" - ], - "kirgiz szom": [ - "KGS" - ], - "dinar du ye\u0301men du sud": [ - "YER" - ], - "peso moneda nacional": [ - "ARS" - ], - "scellino somalo": [ - "SOS" - ], - "cseh korona": [ - "CZK" - ], - "uruguayan peso": [ - "UYU" - ], - "cl$": [ - "CLP" - ], - "convertibele peso": [ - "CUC" - ], - "britisches pfund": [ - "GBP" - ], - "tonga dollar": [ - "TOP" - ], - "peso cubain convertible": [ - "CUC" - ], - "argentin peso": [ - "ARS" - ], - "lira maltesa": [ - "MTL" - ], - "bosnische konvertibilna marka": [ - "BAM" - ], - "francs suisse": [ - "CHF" - ], - "gourde haitienne": [ - "HTG" - ], - "shilling somali": [ - "SOS" - ], - "nt$": [ - "TWD" - ], - "rp": [ - "IDR" - ], - "dolar de las bahamas": [ - "BSD" - ], - "rs": [ - "BRL" - ], - "monnaie danoise": [ - "DKK" - ], - "swaziland lilangeni": [ - "SZL" - ], - "tugrig": [ - "MNT" - ], - "gersh": [ - "ETB" - ], - "rouble russe": [ - "RUB" - ], - "tugrik": [ - "MNT" - ], - "kip": [ - "LAK" - ], - "dirham de los emiratos arabes unidos": [ - "AED" - ], - "escudo capverdien": [ - "CVE" - ], - "jemeni ria\u0301l": [ - "YER" - ], - "fcfp": [ - "XPF" - ], - "rwanda franc": [ - "RWF" - ], - "bolivar venezolano": [ - "VEF" - ], - "zambiai kwacha": [ - "ZMW" - ], - "lev bulgaro": [ - "BGN" - ], - "lev bulgare": [ - "BGN" - ], - "nakfa eritreo": [ - "ERN" - ], - "danish krone": [ - "DKK" - ], - "monnaie britannique": [ - "GBP" - ], - "r$": [ - "BRL" - ], - "di\u0301rham marroqui\u0301": [ - "MAD" - ], - "institut d'e\u0301mission d'outre mer": [ - "XPF" - ], - "manat azerbaiyano": [ - "AZN" - ], - "vietnami \u0111o\u0302\u0300ng": [ - "VND" - ], - "riyal iraniano": [ - "IRR" - ], - "franco guineano": [ - "GNF" - ], - "fiorino arubano": [ - "AWG" - ], - "rand": [ - "ZAR" - ], - "schekel": [ - "ILS" - ], - "sterlina di sant'elena": [ - "SHP" - ], - "pound sterling": [ - "GBP" - ], - "nacfa eritreo": [ - "ERN" - ], - "dolar taiwanes": [ - "TWD" - ], - "koruna c\u030ceska": [ - "CZK" - ], - "\u20ad": [ - "LAK" - ], - "kro\u0301na": [ - "ISK" - ], - "denar macedonio": [ - "MKD" - ], - "libra libanesa": [ - "LBP" - ], - "dolar belicen\u0303o": [ - "BZD" - ], - "lesotho\u0301i loti": [ - "LSL" - ], - "colombian peso": [ - "COP" - ], - "do\u0301lar de brune\u0301i": [ - "BND" - ], - "szingapu\u0301ri dolla\u0301r": [ - "SGD" - ], - "franc poincare": [ - "XFO" - ], - "metical mozambiqueno": [ - "MZN" - ], - "filipijnse peso": [ - "PHP" - ], - "somoni": [ - "TJS" - ], - "lempire hondurien": [ - "HNL" - ], - "angolan kwanza": [ - "AOA" - ], - "schwedenkrone": [ - "SEK" - ], - "lire maltaise": [ - "MTL" - ], - "balboa paname\u0301en": [ - "PAB" - ], - "israelische lire": [ - "ILS" - ], - "nzd": [ - "NZD" - ], - "hryvnia ucraina": [ - "UAH" - ], - "pataca": [ - "MOP" - ], - "coronas suecas": [ - "SEK" - ], - "cape verde escudo": [ - "CVE" - ], - "rupia pakistani": [ - "PKR" - ], - "hungarian forint": [ - "HUF" - ], - "rupia pakistana": [ - "PKR" - ], - "bs.": [ - "BOB" - ], - "kopeken": [ - "RUB" - ], - "dolar bahameno": [ - "BSD" - ], - "de\u0301l koreai von": [ - "KRW" - ], - "zo\u0308ld foki ko\u0308zta\u0301rsasa\u0301gi escudo": [ - "CVE" - ], - "romanian leu": [ - "RON" - ], - "etio\u0301p birr": [ - "ETB" - ], - "indiai ru\u0301pia": [ - "INR" - ], - "livre de gibraltar": [ - "GIP" - ], - "pa\u2019anga": [ - "TOP" - ], - "mexiko\u0301i pezo\u0301": [ - "MXN" - ], - "tansania schilling": [ - "TZS" - ], - "omanitische rial": [ - "OMR" - ], - "rial omani\u0301": [ - "OMR" - ], - "milandor": [ - "RSD" - ], - "canadischer dollar": [ - "CAD" - ], - "dollaro delle isole salomone": [ - "SBD" - ], - "noorse kronen": [ - "NOK" - ], - "samoan ta\u0304la\u0304": [ - "WST" - ], - "aruban florin": [ - "AWG" - ], - "iraakse dinar": [ - "IQD" - ], - "malaysian ringgit": [ - "MYR" - ], - "som usbeco": [ - "UZS" - ], - "ariary": [ - "MGA" - ], - "kyat": [ - "MMK" - ], - "austral (moneda de argentina)": [ - "ARA" - ], - "bruneise dollar": [ - "BND" - ], - "leu romeno": [ - "RON" - ], - "kolumbiai peso": [ - "COP" - ], - "oezbeekse sum": [ - "UZS" - ], - "burundese frank": [ - "BIF" - ], - "austral (argentina)": [ - "ARA" - ], - "riyal qatarien": [ - "QAR" - ], - "quetzal guatemalteque": [ - "GTQ" - ], - "taiwan dollar": [ - "TWD" - ], - "dolar de namibia": [ - "NAD" - ], - "indiase rupee": [ - "INR" - ], - "dollaro delle figi": [ - "FJD" - ], - "cfa franc beac": [ - "XAF" - ], - "hrk": [ - "HRK" - ], - "peso dominicano": [ - "DOP" - ], - "sh.so.": [ - "SOS" - ], - "kwacha zambiano": [ - "ZMW" - ], - "\u0441\u043e\u043c": [ - "KGS" - ], - "roupie nepalaise": [ - "NPR" - ], - "bermudian dollar": [ - "BMD" - ], - "cookinseln dollar": [ - "NZD" - ], - "bam": [ - "BAM" - ], - "kwanza angolen\u0303o": [ - "AOA" - ], - "dinaro libico": [ - "LYD" - ], - "malagasy ariary": [ - "MGA" - ], - "dolar liberiano": [ - "LRD" - ], - "falklandeilands pond": [ - "FKP" - ], - "nouvelle livre turque": [ - "TRY" - ], - "szovjet rubel": [ - "SUR" - ], - "magyar forint": [ - "HUF" - ], - "peso cubain": [ - "CUP" - ], - "xfo": [ - "XFO" - ], - "pakiszta\u0301ni ru\u0301pia": [ - "PKR" - ], - "georgische lari": [ - "GEL" - ], - "loti": [ - "LSL" - ], - "moldawischer leu": [ - "MDL" - ], - "dollaro statunitense": [ - "USD" - ], - "do\u0301lar bahame\u0301s": [ - "BSD" - ], - "lat leto\u0301n": [ - "LVL" - ], - "peso cileno": [ - "CLP" - ], - "dinar libio": [ - "LYD" - ], - "salomon dollar": [ - "SBD" - ], - "rupia nepali": [ - "NPR" - ], - "cop": [ - "COP" - ], - "sri\u0301 lanka i ru\u0301pia": [ - "LKR" - ], - "maloti": [ - "LSL" - ], - "drtrigonbot:exchange rate data:hrk": [ - "HRK" - ], - "franco ruandese": [ - "RWF" - ], - "ils": [ - "ILS" - ], - "bangladeshi taka": [ - "BDT" - ], - "konvertierbarer peso": [ - "CUC" - ], - "she\u0301kel": [ - "ILS" - ], - "kwd": [ - "KWD" - ], - "bahrain dinar": [ - "BHD" - ], - "sfr.": [ - "CHF" - ], - "livre syrienne": [ - "SYP" - ], - "macao pataca": [ - "MOP" - ], - "dolar de las islas caiman": [ - "KYD" - ], - "dollaro del brunei": [ - "BND" - ], - "chil$": [ - "CLP" - ], - "honduranischer lempira": [ - "HNL" - ], - "frf": [ - "FRF" - ], - "nakfa": [ - "ERN" - ], - "ghanese cedi": [ - "GHS" - ], - "dalasi gambien": [ - "GMD" - ], - "braziliaanse real": [ - "BRL" - ], - "frw": [ - "RWF" - ], - "libra falkland": [ - "FKP" - ], - "algerijnse dinar": [ - "DZD" - ], - "dinar du bahrei\u0308n": [ - "BHD" - ], - "dinar serbio": [ - "RSD" - ], - "rupias indias": [ - "INR" - ], - "lesotho loti": [ - "LSL" - ], - "do\u0301lar guyane\u0301s": [ - "GYD" - ], - "mauritanian ouguiya": [ - "MRO" - ], - "greek drachma": [ - "GRD" - ], - "east caribbean dollar": [ - "XCD" - ], - "dirham de emiratos a\u0301rabes unidos": [ - "AED" - ], - "scellino tanzaniano": [ - "TZS" - ], - "aurar": [ - "ISK" - ], - "oost duitse mark": [ - "DDM" - ], - "franc guine\u0301en": [ - "GNF" - ], - "dollaro hongkonghese": [ - "HKD" - ], - "sll": [ - "SLL" - ], - "\u09f3": [ - "BDT" - ], - "rial saudita": [ - "SAR" - ], - "tzs": [ - "TZS" - ], - "real bresilien": [ - "BRL" - ], - "irakischer dinar": [ - "IQD" - ], - "rupias": [ - "INR" - ], - "sistema u\u0301nico de compensacio\u0301n regional": [ - "XSU" - ], - "franco frances": [ - "FRF" - ], - "costaricaanse colo\u0301n": [ - "CRC" - ], - "lita lituano": [ - "LTL" - ], - "\u20ae": [ - "MNT" - ], - "\u0434\u043e\u043b\u0430\u0440": [ - "MKD" - ], - "peso filippino": [ - "PHP" - ], - "dolar neocelandes": [ - "NZD" - ], - "to\u0308gro\u0308g": [ - "MNT" - ], - "rupiah": [ - "IDR" - ], - "zersto\u0308\u00dft sterling": [ - "GBP" - ], - "can$": [ - "CAD" - ], - "pgk": [ - "PGK" - ], - "rupia india": [ - "INR" - ], - "do\u0301lar belicen\u0303o": [ - "BZD" - ], - "nis": [ - "ILS" - ], - "letse lats": [ - "LVL" - ], - "slrs": [ - "LKR" - ], - "dominikanischer peso": [ - "DOP" - ], - "emira\u0301tusi dirham": [ - "AED" - ], - "litas lituano": [ - "LTL" - ], - "litas lituana": [ - "LTL" - ], - "rupia nepali\u0301": [ - "NPR" - ], - "thb": [ - "THB" - ], - "swazi lilangeni": [ - "SZL" - ], - "yen": [ - "JPY" - ], - "flori\u0301n hungaro": [ - "HUF" - ], - "gourde hai\u0308tienne": [ - "HTG" - ], - "yer": [ - "YER" - ], - "argentinischer austral": [ - "ARA" - ], - "bolivar ve\u0301ne\u0301zue\u0301lien": [ - "VEF" - ], - "bolivianischer boliviano": [ - "BOB" - ], - "sheqalim": [ - "ILS" - ], - "\u20af": [ - "GRD" - ], - "brits pond": [ - "GBP" - ], - "sterlina sudanese": [ - "SDG" - ], - "koruna cesko slovenska": [ - "CSK" - ], - "argent chinois": [ - "CNY" - ], - "libische dinar": [ - "LYD" - ], - "libanese pond": [ - "LBP" - ], - "burundian franc": [ - "BIF" - ], - "nuevo sol peruano": [ - "PEN" - ], - "singapore dollar": [ - "SGD" - ], - "dollar hai\u0308tien": [ - "HTG" - ], - "balboa panameen": [ - "PAB" - ], - "aserbaidschanischer manat": [ - "AZN" - ], - "co\u0301rdoba": [ - "NIO" - ], - "sterlina delle falkland": [ - "FKP" - ], - "peso messicano": [ - "MXN" - ], - "millime": [ - "TND" - ], - "omaanse rial": [ - "OMR" - ], - "sjekel": [ - "ILS" - ], - "vatu": [ - "VUV" - ], - "colo\u0301n": [ - "CRC" - ], - "bosnisch herzegowinische konvertible mark": [ - "BAM" - ], - "dollar guyanien": [ - "GYD" - ], - "cedi": [ - "GHS" - ], - "rupia de mauricio": [ - "MUR" - ], - "cny": [ - "CNY" - ], - "pataca di macao": [ - "MOP" - ], - "argentine austral": [ - "ARA" - ], - "austral (wa\u0308hrung)": [ - "ARA" - ], - "nuevo do\u0301lar taiwane\u0301s": [ - "TWD" - ], - "dinar bahraini\u0301": [ - "BHD" - ], - "som kirghizo": [ - "KGS" - ], - "baht": [ - "THB" - ], - "sri lanka rupee": [ - "LKR" - ], - "zsenminpi": [ - "CNY" - ], - "ryal saoudien": [ - "SAR" - ], - "djibouti franc": [ - "DJF" - ], - "pula del botswana": [ - "BWP" - ], - "mauritiaanse rupee": [ - "MUR" - ], - "syrische lira": [ - "SYP" - ], - "centas": [ - "LTL" - ], - "dollars": [ - "USD" - ], - "guineai frank": [ - "GNF" - ], - "panamai balboa": [ - "PAB" - ], - "dollaro": [ - "BBD", - "BZD" - ], - "us dollar": [ - "USD" - ], - "ta\u0304la\u0304": [ - "WST" - ], - "peso dominicain": [ - "DOP" - ], - "\u4eba\u6c11\u5e01": [ - "CNY" - ], - "libra de gibraltar": [ - "GIP" - ], - "mark est allemand": [ - "DDM" - ], - "libra jamaicana": [ - "JMD" - ], - "eritrean nakfa": [ - "ERN" - ], - "som": [ - "KGS", - "UZS" - ], - "sol": [ - "PEN" - ], - "bath": [ - "THB" - ], - "do\u0301lar surinames": [ - "SRD" - ], - "srilankaanse roepie": [ - "LKR" - ], - "oma\u0301ni ria\u0301l": [ - "OMR" - ], - "dolar guyane\u0301s": [ - "GYD" - ], - "dollaro delle bahamas": [ - "BSD" - ], - "georgischer lari": [ - "GEL" - ], - "sa\u0303o tome\u0301 e\u0301s pri\u0301ncipe i dobra": [ - "STD" - ], - "namibische dollar": [ - "NAD" - ], - "lira turca": [ - "TRY" - ], - "austral": [ - "ARA" - ], - "tune\u0301ziai dina\u0301r": [ - "TND" - ], - "pyg": [ - "PYG" - ], - "\u060b": [ - "AFN" - ], - "tajikistani somoni": [ - "TJS" - ], - "fiji dollar": [ - "FJD" - ], - "south african rand": [ - "ZAR" - ], - "seychelse rupee": [ - "SCR" - ], - "anciens francs": [ - "FRF" - ], - "nuevo sheqel": [ - "ILS" - ], - "amerikai dolla\u0301r": [ - "USD" - ], - "do\u0301lar canadiense": [ - "CAD" - ], - "turkmenistan manat": [ - "TMT" - ], - "litas": [ - "LTL" - ], - "peso cubano": [ - "CUP" - ], - "maltese lira": [ - "MTL" - ], - "azn": [ - "AZN" - ], - "maltese lire": [ - "MTL" - ], - "sve\u0301d korona": [ - "SEK" - ], - "konvertibilna marka": [ - "BAM" - ], - "peso": [ - "COP", - "DOP", - "MXN" - ], - "franse frank": [ - "FRF" - ], - "mexiko\u0301i peso": [ - "MXN" - ], - "pesos": [ - "MXN" - ], - "shilling kenyan": [ - "KES" - ], - "iqd": [ - "IQD" - ], - "colo\u0301n costaricain": [ - "CRC" - ], - "dinar soudanais": [ - "SDG" - ], - "peso colombien": [ - "COP" - ], - "renminbi cinese": [ - "CNY" - ], - "mark der deutschen notenbank": [ - "DDM" - ], - "re\u0301al": [ - "BRL" - ], - "mauritius rupie": [ - "MUR" - ], - "tongai pa'anga": [ - "TOP" - ], - "deutsche mark der deutschen notenbank": [ - "DDM" - ], - "ddr geld": [ - "DDM" - ], - "usbekistan som": [ - "UZS" - ], - "trinidad und tobago dollar": [ - "TTD" - ], - "guyanai dolla\u0301r": [ - "GYD" - ], - "do\u0301lar de bermuda": [ - "BMD" - ], - "peso convertible": [ - "CUC" - ], - "livre britannique": [ - "GBP" - ], - "italienische lira": [ - "ITL" - ], - "italienische lire": [ - "ITL" - ], - "kenyai shilling": [ - "KES" - ], - "li\u0301biai dina\u0301r": [ - "LYD" - ], - "nuevo dolar taiwanes": [ - "TWD" - ], - "fijan dollar": [ - "FJD" - ], - "uruguayischer peso": [ - "UYU" - ], - "neuseela\u0308ndischer dollar": [ - "NZD" - ], - "csendes o\u0301cea\u0301ni valutako\u0308zo\u0308sse\u0301gi frank": [ - "XPF" - ], - "poisha": [ - "BDT" - ], - "lat letton": [ - "LVL" - ], - "n$": [ - "NAD" - ], - "rwandan franc": [ - "RWF" - ], - "lempira": [ - "HNL" - ], - "speciale trekkingsrechten": [ - "XDR" - ], - "maldivian rufiyaa": [ - "MVR" - ], - "rwandan frank": [ - "RWF" - ], - "israe\u0308lische lire": [ - "ILS" - ], - "afgani": [ - "AFN" - ], - "rol": [ - "RON" - ], - "u+20bd": [ - "RUB" - ], - "s\u0192": [ - "SRD" - ], - "dinar bahreini": [ - "BHD" - ], - "tongai pa\u02bbanga": [ - "TOP" - ], - "franco suizo": [ - "CHF" - ], - "marco convertible": [ - "BAM" - ], - "forint hongrois": [ - "HUF" - ], - "som kirguis": [ - "KGS" - ], - "israeli new shekel": [ - "ILS" - ], - "som kirguiz": [ - "KGS" - ], - "albanischer lek": [ - "ALL" - ], - "vef": [ - "VEF" - ], - "kongo franc": [ - "CDF" - ], - "mexicaanse peso": [ - "MXN" - ], - "argentine peso": [ - "ARS" - ], - "guatemaltekischer quetzal": [ - "GTQ" - ], - "novo kwanza": [ - "AOA" - ], - "zuid soedanese pond": [ - "SSP" - ], - "horva\u0301t kuna": [ - "HRK" - ], - "dolar neozelandes": [ - "NZD" - ], - "tu\u0308rkme\u0301n manat": [ - "TMT" - ], - "lilangeni sign": [ - "SZL" - ], - "new taiwan dollar": [ - "TWD" - ], - "swazische lilangeni": [ - "SZL" - ], - "stotinki": [ - "BGN" - ], - "\u0111o\u0302\u0300ng vietnamita": [ - "VND" - ], - "franco burunde\u0301s": [ - "BIF" - ], - "stotinka": [ - "BGN" - ], - "cordoba nicaragu\u0308ense": [ - "NIO" - ], - "lebanese pound": [ - "LBP" - ], - "flori\u0301n aruben\u0303o": [ - "AWG" - ], - "algerian dinar": [ - "DZD" - ], - "dinar jordano": [ - "JOD" - ], - "rial saoudien": [ - "SAR" - ], - "litva\u0301n litas": [ - "LTL" - ], - "scellino ugandese": [ - "UGX" - ], - "zai\u0308re": [ - "CDF" - ], - "florin d\u2019aruba": [ - "AWG" - ], - "grivnia ucraina": [ - "UAH" - ], - "sambischer kwacha": [ - "ZMW" - ], - "filler": [ - "HUF" - ], - "ringgit": [ - "MYR" - ], - "rupia del pakistan": [ - "PKR" - ], - "nieuwe turkse lira": [ - "TRY" - ], - "chilei peso": [ - "CLP" - ], - "iranian rial": [ - "IRR" - ], - "tadzjiekse somoni": [ - "TJS" - ], - "metical mozambiquen\u0303o": [ - "MZN" - ], - "sterlina inglese": [ - "GBP" - ], - "mauritian rupee": [ - "MUR" - ], - "dinaro del bahrain": [ - "BHD" - ], - "venezuelai boli\u0301var": [ - "VEF" - ], - "ruma\u0308nischer ban": [ - "RON" - ], - "dolar de las islas salomo\u0301n": [ - "SBD" - ], - "roepiah": [ - "IDR" - ], - "dinaro serbo": [ - "RSD" - ], - "riyal catari\u0301": [ - "QAR" - ], - "dollaro surinamese": [ - "SRD" - ], - "libra sursudanesa": [ - "SSP" - ], - "south sudanese pound": [ - "SSP" - ], - "boli\u0301var venezuelano": [ - "VEF" - ], - "shilling ke\u0301nyan": [ - "KES" - ], - "dolar suriname\u0301s": [ - "SRD" - ], - "bolivares fuertes": [ - "VEF" - ], - "francos suizos": [ - "CHF" - ], - "botsuanischer pula": [ - "BWP" - ], - "nieuwe israe\u0308lische sjekel": [ - "ILS" - ], - "bahama dollar": [ - "BSD" - ], - "sierra leonischer leone": [ - "SLL" - ], - "bob": [ - "BOB" - ], - "botswana pula": [ - "BWP" - ], - "nepa\u0301li ru\u0301pia": [ - "NPR" - ], - "dollaro taiwanese": [ - "TWD" - ], - "dolar de belice": [ - "BZD" - ], - "sierra leonean leone": [ - "SLL" - ], - "franco gibutiano": [ - "DJF" - ], - "franco": [ - "RWF", - "DJF", - "CDF", - "XPF" - ], - "nouveau dollar de tai\u0308wan": [ - "TWD" - ], - "libras esterlinas": [ - "GBP" - ], - "paraguayischer guarani\u0301": [ - "PYG" - ], - "drachme (antike)": [ - "GRD" - ], - "\u20b1": [ - "PHP" - ], - "s\u20a3": [ - "CHF" - ], - "csehszlova\u0301k korona": [ - "CSK" - ], - "lithuanian litas": [ - "LTL" - ], - "malagassische ariary": [ - "MGA" - ], - "afl.": [ - "AWG" - ], - "flori\u0301n hu\u0301ngaro": [ - "HUF" - ], - "izraeli u\u0301j se\u0301kel": [ - "ILS" - ], - "nigeriaanse naira": [ - "NGN" - ], - "kazakhstani tenge": [ - "KZT" - ], - "south korean won": [ - "KRW" - ], - "dollar de hong kong": [ - "HKD" - ], - "su\u0308dkoreanischer won": [ - "KRW" - ], - "peso mejicano": [ - "MXN" - ], - "won nordcoreano": [ - "KPW" - ], - "mark der ddr": [ - "DDM" - ], - "tschechische krone": [ - "CZK" - ], - "solomon islands dollar": [ - "SBD" - ], - "boli\u0301viai boliviano": [ - "BOB" - ], - "costaricaanse colon": [ - "CRC" - ], - "jemen rial": [ - "YER" - ], - "mga": [ - "MGA" - ], - "kyd": [ - "KYD" - ], - "mauritaanse ouguiya": [ - "MRO" - ], - "gambiaanse dalasi": [ - "GMD" - ], - "gibraltar pound": [ - "GIP" - ], - "tsjechoslowaakse kroon": [ - "CSK" - ], - "gourde": [ - "HTG" - ], - "corona sueca": [ - "SEK" - ], - "colon costaricano": [ - "CRC" - ], - "franc congolais": [ - "CDF" - ], - "florin arubeno": [ - "AWG" - ], - "kaapverdische escudo": [ - "CVE" - ], - "venezolaanse bolivar": [ - "VEF" - ], - "s/": [ - "PEN" - ], - "dolar de nueva zelanda": [ - "NZD" - ], - "do\u0301lar suriname\u0301s": [ - "SRD" - ], - "francs suisses": [ - "CHF" - ], - "s$": [ - "SGD" - ], - "italiaanse lire": [ - "ITL" - ], - "italiaanse lira": [ - "ITL" - ], - "bahreinse dinar": [ - "BHD" - ], - "sr": [ - "SAR" - ], - "corona": [ - "SEK" - ], - "font sterling": [ - "GBP" - ], - "peso chileno": [ - "CLP" - ], - "tala": [ - "WST" - ], - "libra gibraltarena": [ - "GIP" - ], - "saoedi arabische riyal": [ - "SAR" - ], - "guinese frank": [ - "GNF" - ], - "dracma (moderna)": [ - "GRD" - ], - "franco de burundi": [ - "BIF" - ], - "thaise baht": [ - "THB" - ], - "koruna": [ - "CZK" - ], - "koruna ceska": [ - "CZK" - ], - "dram armeno": [ - "AMD" - ], - "st. helena pfund": [ - "SHP" - ], - "lek albanese": [ - "ALL" - ], - "trinidad en tobagodollar": [ - "TTD" - ], - "cuban peso": [ - "CUP" - ], - "gtq": [ - "GTQ" - ], - "djf": [ - "DJF" - ], - "east german mark": [ - "DDM" - ], - "yuan cinese": [ - "CNY" - ], - "jordaanse dinar": [ - "JOD" - ], - "guinean franc": [ - "GNF" - ], - "szoma\u0301liai shilling": [ - "SOS" - ], - "nok": [ - "NOK" - ], - "do\u0301lar de namibia": [ - "NAD" - ], - "shilingi": [ - "TZS" - ], - "franco yibuti": [ - "DJF" - ], - "rufiyah": [ - "MVR" - ], - "col$": [ - "COP" - ], - "rufiyaa": [ - "MVR" - ], - "tt$": [ - "TTD" - ], - "cheli\u0301n": [ - "UGX", - "TZS", - "SOS" - ], - "gryvnia": [ - "UAH" - ], - "cfp franc": [ - "XPF" - ], - "real brasiliano": [ - "BRL" - ], - "cfp frank": [ - "XPF" - ], - "taka bengalese": [ - "BDT" - ], - "ngwee": [ - "ZMW" - ], - "metical mozambicano": [ - "MZN" - ], - "lempira honduregna": [ - "HNL" - ], - "libra malvinense": [ - "FKP" - ], - "nuevo she\u0301quel": [ - "ILS" - ], - "rial omanais": [ - "OMR" - ], - "arg$": [ - "ARS" - ], - "nicaraguanischer co\u0301rdoba": [ - "NIO" - ], - "colon costaricien": [ - "CRC" - ], - "drtrigonbot:exchange rate data:dkk": [ - "DKK" - ], - "goldfranken": [ - "XFO" - ], - "roupie indienne": [ - "INR" - ], - "afghani": [ - "AFN" - ], - "franc cfp": [ - "XPF" - ], - "seychelle szigeteki ru\u0301pia": [ - "SCR" - ], - "franco ruandes": [ - "RWF" - ], - "pesification": [ - "ARS" - ], - "dirham des emirats arabes unis": [ - "AED" - ], - "$can": [ - "CAD" - ], - "franc cfa": [ - "XAF", - "XOF" - ], - "nepalese roepie": [ - "NPR" - ], - "lwei": [ - "AOA" - ], - "nuovo peso argentino": [ - "ARS" - ], - "indonesian rupiah": [ - "IDR" - ], - "guatemalai quetzal": [ - "GTQ" - ], - "dolar de singapur": [ - "SGD" - ], - "peso de me\u0301xico": [ - "MXN" - ], - "surinamese guilder": [ - "SRG" - ], - "nigerian naira": [ - "NGN" - ], - "peso philippin": [ - "PHP" - ], - "mongoolse tugrik": [ - "MNT" - ], - "franc pacifique": [ - "XPF" - ], - "haitianischer gourde": [ - "HTG" - ], - "jemenitische rial": [ - "YER" - ], - "do\u0301lar": [ - "USD", - "FJD" - ], - "kolumbianischer peso": [ - "COP" - ], - "co\u0301rdoba nicaraguense": [ - "NIO" - ], - "dollar ne\u0301oze\u0301landais": [ - "NZD" - ], - "meticais": [ - "MZN" - ], - "uqiya": [ - "MRO" - ], - "grivnia": [ - "UAH" - ], - "lakhs": [ - "BDT" - ], - "zar": [ - "ZAR" - ], - "bahamian dollar": [ - "BSD" - ], - "qa\u0308pik": [ - "AZN" - ], - "ukp": [ - "GBP" - ], - "paraguayaanse guarani\u0301": [ - "PYG" - ], - "mauritiusi ru\u0301pia": [ - "MUR" - ], - "philippinischer peso": [ - "PHP" - ], - "kambodschanischer riel": [ - "KHR" - ], - "huf": [ - "HUF" - ], - "dollar de singapour": [ - "SGD" - ], - "dom$": [ - "DOP" - ], - "dinar du kowei\u0308t": [ - "KWD" - ], - "australian dollar": [ - "AUD" - ], - "namibian dollar": [ - "NAD" - ], - "arubaanse gulden": [ - "AWG" - ], - "drachme moderne grecque": [ - "GRD" - ], - "dinar kowe\u0301itien": [ - "KWD" - ], - "nieuwe israelische sheqel": [ - "ILS" - ], - "salyn": [ - "THB" - ], - "moldova\u0301n lej": [ - "MDL" - ], - "nepalesische rupie": [ - "NPR" - ], - "marka convertible": [ - "BAM" - ], - "bulgarian lev": [ - "BGN" - ], - "tengue": [ - "KZT" - ], - "currency of somalia": [ - "SOS" - ], - "franc franc\u0327ais": [ - "FRF" - ], - "do\u0301lar bahames": [ - "BSD" - ], - "som de kirguistan": [ - "KGS" - ], - "kip laotiano": [ - "LAK" - ], - "sar": [ - "SAR" - ], - "ngultrum butane\u0301s": [ - "BTN" - ], - "birr etiope": [ - "ETB" - ], - "fening": [ - "BAM" - ], - "dominicaanse peso": [ - "DOP" - ], - "taka": [ - "BDT" - ], - "\u20b2": [ - "PYG" - ], - "do\u0301lar neozelandes": [ - "NZD" - ], - "rial ye\u0301me\u0301nite": [ - "YER" - ], - "sterlina sud sudanese": [ - "SSP" - ], - "dolar de bermuda": [ - "BMD" - ], - "dollar taiwanais": [ - "TWD" - ], - "afghanis": [ - "AFN" - ], - "uyu": [ - "UYU" - ], - "cordoba": [ - "NIO" - ], - "bahamaanse dollar": [ - "BSD" - ], - "\u0111ong": [ - "VND" - ], - "baiza": [ - "OMR" - ], - "kazachse tenge": [ - "KZT" - ], - "vietnamesischer \u0111o\u0302\u0300ng": [ - "VND" - ], - "dollar de brunei": [ - "BND" - ], - "dollar du belize": [ - "BZD" - ], - "jordanian dinar": [ - "JOD" - ], - "nuevo sol peruviano": [ - "PEN" - ], - "livre turque": [ - "TRY" - ], - "fidschi dollar": [ - "FJD" - ], - "franco cfa de africa central": [ - "XAF" - ], - "kyrgyzstani som": [ - "KGS" - ], - "dolar taiwane\u0301s": [ - "TWD" - ], - "quetzales": [ - "GTQ" - ], - "pa\u0301pua u\u0301j guineai kina": [ - "PGK" - ], - "won nord core\u0301en": [ - "KPW" - ], - "couronne danoise": [ - "DKK" - ], - "nuevo do\u0301lar de taiwa\u0301n": [ - "TWD" - ], - "uruguay peso": [ - "UYU" - ], - "boli\u0301vares fuertes": [ - "VEF" - ], - "rupia de pakistan": [ - "PKR" - ], - "lilangeni": [ - "SZL" - ], - "rupia dell'india": [ - "INR" - ], - "libra esterlina": [ - "GBP" - ], - "koruna ceska\u0301": [ - "CZK" - ], - "\u20b3": [ - "ARA" - ], - "co\u0301rdoba nicaragu\u0308ense": [ - "NIO" - ], - "hongaarse forint": [ - "HUF" - ], - "loti lesothan": [ - "LSL" - ], - "baht thailandese": [ - "THB" - ], - "real brasileno": [ - "BRL" - ], - "katari ria\u0301l": [ - "QAR" - ], - "uzbekistani som": [ - "UZS" - ], - "armenischer dram": [ - "AMD" - ], - "jorda\u0301n dina\u0301r": [ - "JOD" - ], - "bulgaarse lev": [ - "BGN" - ], - "hondurasi lempira": [ - "HNL" - ], - "do\u0302\u0300ng vietnamita": [ - "VND" - ], - "gel": [ - "GEL" - ], - "trinidad en tobago dollar": [ - "TTD" - ], - "rupia de maldivas": [ - "MVR" - ], - "do\u0301lar liberiano": [ - "LRD" - ], - "vanuatuaanse vatu": [ - "VUV" - ], - "libe\u0301riai dolla\u0301r": [ - "LRD" - ], - "colon costarricense": [ - "CRC" - ], - "dobra di sa\u0303o tome\u0301 e pri\u0301ncipe": [ - "STD" - ], - "croatian kuna": [ - "HRK" - ], - "nouveau sol": [ - "PEN" - ], - "wo\u0306n norcoreano": [ - "KPW" - ], - "de\u0301l afrikai rand": [ - "ZAR" - ], - "dolar bermuden\u0303o": [ - "BMD" - ], - "tu\u0308rkische lira": [ - "TRY" - ], - "rmb": [ - "CNY" - ], - "ringgit malese": [ - "MYR" - ], - "marco de la republica democra\u0301tica alemana": [ - "DDM" - ], - "j$": [ - "JMD" - ], - "lire turque": [ - "TRY" - ], - "tunisian dinar": [ - "TND" - ], - "falkland pfund": [ - "FKP" - ], - "pakistani rupee": [ - "PKR" - ], - "central african cfa franc": [ - "XAF" - ], - "rouble": [ - "SUR" - ], - "ytl": [ - "TRY" - ], - "trinidad e\u0301s tobago\u0301 i dolla\u0301r": [ - "TTD" - ], - "orosz rubel": [ - "RUB" - ], - "dollar de surinam": [ - "SRD" - ], - "franco delle comore": [ - "KMF" - ], - "so\u02bbm": [ - "UZS" - ], - "franse franc": [ - "FRF" - ], - "kuna croata": [ - "HRK" - ], - "droits de tirage spe\u0301ciaux": [ - "XDR" - ], - "kuna croate": [ - "HRK" - ], - "dinar de kuwait": [ - "KWD" - ], - "dschibuti franc": [ - "DJF" - ], - "guinea franc": [ - "GNF" - ], - "kwacha zambese": [ - "ZMW" - ], - "guatemalteekse quetzal": [ - "GTQ" - ], - "chelin keniano": [ - "KES" - ], - "livre libanaise": [ - "LBP" - ], - "dkk": [ - "DKK" - ], - "ouguiya della mauritana": [ - "MRO" - ], - "kaaimaneilandse dollar": [ - "KYD" - ], - "drtrigonbot:exchange rate data:ltl": [ - "LTL" - ], - "comorese frank": [ - "KMF" - ], - "us $": [ - "USD" - ], - "lats lettone": [ - "LVL" - ], - "griwna": [ - "UAH" - ], - "qatari riyal": [ - "QAR" - ], - "colon": [ - "CRC" - ], - "franc germinal": [ - "FRF", - "XFO" - ], - "roupie ne\u0301palaise": [ - "NPR" - ], - "dollar jamai\u0308cain": [ - "JMD" - ], - "mark": [ - "DDM" - ], - "indische rupie": [ - "INR" - ], - "angolese kwanza": [ - "AOA" - ], - "dollar de fidji": [ - "FJD" - ], - "khr": [ - "KHR" - ], - "krona": [ - "SEK" - ], - "dollaro di trinidad e tobago": [ - "TTD" - ], - "krone": [ - "DKK" - ], - "szoma\u0301li shilling": [ - "SOS" - ], - "rupia indiana": [ - "INR" - ], - "bolivar fuerte": [ - "VEF" - ], - "euro\u0301": [ - "EUR" - ], - "rupia de indonesia": [ - "IDR" - ], - "libra gibraltaren\u0303a": [ - "GIP" - ], - "indonesische rupiah": [ - "IDR" - ], - "panamaischer balboa": [ - "PAB" - ], - "ethiopian birr": [ - "ETB" - ], - "kubai konvertibilis peso": [ - "CUC" - ], - "clp": [ - "CLP" - ], - "florin d'aruba": [ - "AWG" - ], - "dolar bahames": [ - "BSD" - ], - "ouguiya mauritanien": [ - "MRO" - ], - "salomonen dollar": [ - "SBD" - ], - "chavito": [ - "CUC" - ], - "kanadai dolla\u0301r": [ - "CAD" - ], - "britische pfund": [ - "GBP" - ], - "singaporese dollar": [ - "SGD" - ], - "chinese renminbi": [ - "CNY" - ], - "saudische riyal": [ - "SAR" - ], - "neuer taiwan dollar": [ - "TWD" - ], - "do\u0301lar taiwanes": [ - "TWD" - ], - "keniaanse shilling": [ - "KES" - ], - "do\u0301lar de bahamas": [ - "BSD" - ], - "bhutanese ngultrum": [ - "BTN" - ], - "corona noruega": [ - "NOK" - ], - "dollaro giamaicano": [ - "JMD" - ], - "afgani afgano": [ - "AFN" - ], - "pab": [ - "PAB" - ], - "aruba florin": [ - "AWG" - ], - "tajikistani ruble": [ - "TJR" - ], - "franzo\u0308sischer franc": [ - "FRF" - ], - "lira italiana": [ - "ITL" - ], - "$ can": [ - "CAD" - ], - "marco de la rda": [ - "DDM" - ], - "ostkaribische wa\u0308hrungsunion": [ - "XCD" - ], - "naf": [ - "ANG" - ], - "drtrigonbot:exchange rate data:jpy": [ - "JPY" - ], - "afghaanse afghani": [ - "AFN" - ], - "peruviaanse sol": [ - "PEN" - ], - "livre de sainte he\u0301le\u0300ne": [ - "SHP" - ], - "sa\u0303o tome\u0301 and pri\u0301ncipe dobra": [ - "STD" - ], - "co\u0301rdoba oro": [ - "NIO" - ], - "moneda nacional": [ - "CUP" - ], - "macanese pataca": [ - "MOP" - ], - "couronne tcheque": [ - "CZK" - ], - "chelin ugande\u0301s": [ - "UGX" - ], - "peso cubano convertible": [ - "CUC" - ], - "eritreai nakfa": [ - "ERN" - ], - "ira\u0301ni ria\u0301l": [ - "IRR" - ], - "dollar canadien": [ - "CAD" - ], - "litouwse litas": [ - "LTL" - ], - "venezuelan boli\u0301var": [ - "VEF" - ], - "lib$": [ - "LRD" - ], - "cheli\u0301n keniata": [ - "KES" - ], - "riyal saoudien": [ - "SAR" - ], - "usbekistan sum": [ - "UZS" - ], - "chelin keniata": [ - "KES" - ], - "peso cubano convertibile": [ - "CUC" - ], - "euros": [ - "EUR" - ], - "dollar des bermudes": [ - "BMD" - ], - "liberianischer dollar": [ - "LRD" - ], - "peso convertibile": [ - "CUC" - ], - "grd": [ - "GRD" - ], - "tschechoslowakische krone": [ - "CSK" - ], - "tongan pa'anga": [ - "TOP" - ], - "szamoai tala": [ - "WST" - ], - "namibischer dollar": [ - "NAD" - ], - "manat azerbai\u0308djanais": [ - "AZN" - ], - "real": [ - "BRL" - ], - "tanzanian shilingi": [ - "TZS" - ], - "dollar liberien": [ - "LRD" - ], - "do\u0301lar neocelandes": [ - "NZD" - ], - "do\u0301lar taiwane\u0301s": [ - "TWD" - ], - "dinaro del bahrein": [ - "BHD" - ], - "florin hu\u0301ngaro": [ - "HUF" - ], - "zambian kwacha": [ - "ZMW" - ], - "dracma greca": [ - "GRD" - ], - "italian lira": [ - "ITL" - ], - "antilliaanse gulden": [ - "ANG" - ], - "som uzbeco": [ - "UZS" - ], - "yuan renminbi": [ - "CNY" - ], - "tenge kazajo": [ - "KZT" - ], - "dolar trinitense": [ - "TTD" - ], - "dollaro bahamense": [ - "BSD" - ], - "yeni kurus\u0327": [ - "TRY" - ], - "brunei dollar": [ - "BND" - ], - "lek albanes": [ - "ALL" - ], - "yua\u0301n chino": [ - "CNY" - ], - "\u20adn": [ - "LAK" - ], - "som kirgui\u0301s": [ - "KGS" - ], - "britse pond": [ - "GBP" - ], - "\u20b4": [ - "UAH" - ], - "nuevo dolar de taiwa\u0301n": [ - "TWD" - ], - "dominican peso": [ - "DOP" - ], - "mosambikanischer escudo": [ - "MZE" - ], - "do\u0301lar de las islas caima\u0301n": [ - "KYD" - ], - "gibraltar pfund": [ - "GIP" - ], - "lats leto\u0301n": [ - "LVL" - ], - "kanadische dollar": [ - "CAD" - ], - "srd": [ - "SRD" - ], - "sre": [ - "SCR" - ], - "comore i frank": [ - "KMF" - ], - "peso colombiano": [ - "COP" - ], - "leke\u0308": [ - "ALL" - ], - "\u0433\u0440\u0438\u0432\u043d\u044f": [ - "UAH" - ], - "alu chip": [ - "DDM" - ], - "kanadischer dollar": [ - "CAD" - ], - "suriname dollar": [ - "SRD" - ], - "corona ceca": [ - "CZK" - ], - "serbischer dinar": [ - "RSD" - ], - "dollar de brune\u0301i": [ - "BND" - ], - "denar": [ - "MKD" - ], - "dinar macedonio": [ - "MKD" - ], - "lira maltese": [ - "MTL" - ], - "frans geld": [ - "FRF" - ], - "naira nigeriana": [ - "NGN" - ], - "nuevo do\u0301lar taiwanes": [ - "TWD" - ], - "dollaro neozelandese": [ - "NZD" - ], - "dinar bahrei\u0308nien": [ - "BHD" - ], - "zweedse kroon": [ - "SEK" - ], - "swedish krona": [ - "SEK" - ], - "new israeli shekel": [ - "ILS" - ], - "leu moldave": [ - "MDL" - ], - "rupia de nepal": [ - "NPR" - ], - "leu moldavo": [ - "MDL" - ], - "fidzsi dolla\u0301r": [ - "FJD" - ], - "pula": [ - "BWP" - ], - "drachmai": [ - "GRD" - ], - "marco bosnio": [ - "BAM" - ], - "roupie seychelloise": [ - "SCR" - ], - "u\u0308zbe\u0301g szom": [ - "UZS" - ], - "tanzanian schilling": [ - "TZS" - ], - "gib\u00a3": [ - "GIP" - ], - "lett lat": [ - "LVL" - ], - "kc\u030cs": [ - "CSK" - ], - "mark der deutschen demokratischen republik": [ - "DDM" - ], - "yeni tu\u0308rk liras\u0131": [ - "TRY" - ], - "\u3012": [ - "KZT" - ], - "bosnische convertibele mark": [ - "BAM" - ], - "libra siria": [ - "SYP" - ], - "peso oro": [ - "DOP" - ], - "rupia indonesia": [ - "IDR" - ], - "pakistaanse rupee": [ - "PKR" - ], - "riel cambogiano": [ - "KHR" - ], - "haitian gourde": [ - "HTG" - ], - "tschechische wa\u0308hrung": [ - "CZK" - ], - "bosnia and herzegovina convertible mark": [ - "BAM" - ], - "francs franc\u0327ais": [ - "FRF" - ], - "griechische drachme": [ - "GRD" - ], - "nuovo sol": [ - "PEN" - ], - "swiss franc": [ - "CHF" - ], - "swiss frank": [ - "CHF" - ], - "somoni tayiko": [ - "TJS" - ], - "rial yemeni\u0301": [ - "YER" - ], - "nueva lira turca": [ - "TRY" - ], - "engelse pond": [ - "GBP" - ], - "chelin tanzano": [ - "TZS" - ], - "peso de repu\u0301blica dominicana": [ - "DOP" - ], - "dalasi gambese": [ - "GMD" - ], - "nicaraguaanse co\u0301rdoba": [ - "NIO" - ], - "lira libanese": [ - "LBP" - ], - "baht tailandes": [ - "THB" - ], - "khoum": [ - "MRO" - ], - "lek albane\u0301s": [ - "ALL" - ], - "botswanischer pula": [ - "BWP" - ], - "dinar mace\u0301donien": [ - "MKD" - ], - "dollar": [ - "USD" - ], - "dolar bahame\u0301s": [ - "BSD" - ], - "\u20ac": [ - "EUR" - ], - "dollar singapourien": [ - "SGD" - ], - "israe\u0308lische sjekel": [ - "ILS" - ], - "wo\u0306n surcoreano": [ - "KRW" - ], - "ukra\u0301n hrivnya": [ - "UAH" - ], - "dinar algerien": [ - "DZD" - ], - "cedi ghanese": [ - "GHS" - ], - "cfa franc bceao": [ - "XOF" - ], - "scr": [ - "SCR" - ], - "\u0442\u04e9\u0433\u0440\u04e9\u0433": [ - "MNT" - ], - "izlandi korona": [ - "ISK" - ], - "englisches pfund": [ - "GBP" - ], - "ws$": [ - "WST" - ], - "wikipedia:raadsel/netties20070405": [ - "GRD" - ], - "dolar neozelande\u0301s": [ - "NZD" - ], - "samoanischer tala": [ - "WST" - ], - "syrisch pond": [ - "SYP" - ], - "caymaneilandse dollar": [ - "KYD" - ], - "cordoba oro": [ - "NIO" - ], - "kina papuana": [ - "PGK" - ], - "szent ilona i font": [ - "SHP" - ], - "sudanese pound": [ - "SDG" - ], - "gourde haitiano": [ - "HTG" - ], - "dollar hongkongais": [ - "HKD" - ], - "haiti gourde": [ - "HTG" - ], - "eyrir": [ - "ISK" - ], - "australes": [ - "ARA" - ], - "livres turques": [ - "TRY" - ], - "dollar barbadien": [ - "BBD" - ], - "congolese franc": [ - "CDF" - ], - "wst": [ - "WST" - ], - "t$": [ - "TOP" - ], - "congolese frank": [ - "CDF" - ], - "nafka": [ - "ERN" - ], - "dansk krone": [ - "DKK" - ], - "jordanischer dinar": [ - "JOD" - ], - "dolar de bahamas": [ - "BSD" - ], - "brasilianischer real": [ - "BRL" - ], - "nz$": [ - "NZD" - ], - "leone sierra le\u0301onais": [ - "SLL" - ], - "tunesische dinar": [ - "TND" - ], - "do\u0301lar namibio": [ - "NAD" - ], - "$ca": [ - "CAD" - ], - "bengalese taka": [ - "BDT" - ], - "dollar fidjien": [ - "FJD" - ], - "ungarischer forint": [ - "HUF" - ], - "dinar serbe": [ - "RSD" - ], - "do\u0301lar de trinidad y tobago": [ - "TTD" - ], - "belize dollar": [ - "BZD" - ], - "sum": [ - "UZS" - ], - "franc rwandais": [ - "RWF" - ], - "dinar jordanien": [ - "JOD" - ], - "moldauischer leu": [ - "MDL" - ], - "dolar de las islas salomon": [ - "SBD" - ], - "lire italienne": [ - "ITL" - ], - "ang": [ - "ANG" - ], - "\u0e3f": [ - "THB" - ], - "sucre": [ - "XSU" - ], - "kzt": [ - "KZT" - ], - "kronor": [ - "SEK" - ], - "somalische shilling": [ - "SOS" - ], - "dollaro namibiano": [ - "NAD" - ], - "omanischer rial": [ - "OMR" - ], - "do\u0301lar bermuden\u0303o": [ - "BMD" - ], - "marka": [ - "BAM" - ], - "marco convertibile": [ - "BAM" - ], - "rublo ruso": [ - "RUB" - ], - "uae dirham": [ - "AED" - ], - "vae dirham": [ - "AED" - ], - "ngultrum del bhutan": [ - "BTN" - ], - "samoaanse tala": [ - "WST" - ], - "maltesische lira": [ - "MTL" - ], - "couronne norvegienne": [ - "NOK" - ], - "franc burundais": [ - "BIF" - ], - "flori\u0301n arubeno": [ - "AWG" - ], - "georgian kupon lari": [ - "GEL" - ], - "dollar de trinidad et tobago": [ - "TTD" - ], - "t\u0323a\u0304ka\u0304": [ - "BDT" - ], - "tonga pa\u02bbanga": [ - "TOP" - ], - "dinar kuwaiti": [ - "KWD" - ], - "kenia schilling": [ - "KES" - ], - "\u20a1": [ - "CRC" - ], - "guarani paraguayen": [ - "PYG" - ], - "lats letton": [ - "LVL" - ], - "quetzal guate\u0301malte\u0300que": [ - "GTQ" - ], - "netherlands antillean guilder": [ - "ANG" - ], - "balboa panamen\u0303o": [ - "PAB" - ], - "dolar de brune\u0301i": [ - "BND" - ], - "sheqel": [ - "ILS" - ], - "escudo capoverdiano": [ - "CVE" - ], - "boli\u0301var fuerte": [ - "VEF" - ], - "franco della guinea": [ - "GNF" - ], - "boli\u0301var": [ - "VEF" - ], - "lilangeni swazilandais": [ - "SZL" - ], - "dracma griega moderna": [ - "GRD" - ], - "tenge kazako": [ - "KZT" - ], - "tenge kazakh": [ - "KZT" - ], - "mexican centavo": [ - "MXN" - ], - "peso uruguaiano": [ - "UYU" - ], - "franco cfp": [ - "XPF" - ], - "so'm": [ - "UZS" - ], - "drtrigonbot:exchange rate data:chf": [ - "CHF" - ], - "konvertible mark": [ - "BAM" - ], - "nouveau manat aze\u0301ri": [ - "AZN" - ], - "nordjemenitischer rial": [ - "YER" - ], - "bolivares": [ - "VEF" - ], - "\u043b\u0435\u0432": [ - "BGN" - ], - "deg": [ - "XDR" - ], - "guarani paraguaiano": [ - "PYG" - ], - "scellino keniano": [ - "KES" - ], - "f$": [ - "FJD" - ], - "couronne islandaise": [ - "ISK" - ], - "dollar de la barbade": [ - "BBD" - ], - "macause pataca": [ - "MOP" - ], - "do\u0301lar bermudeno": [ - "BMD" - ], - "isk": [ - "ISK" - ], - "west african cfa franc": [ - "XOF" - ], - "armeense dram": [ - "AMD" - ], - "renminbi yuan": [ - "CNY" - ], - "aussie dollar": [ - "AUD" - ], - "franco francese": [ - "FRF" - ], - "tetradrachmon": [ - "GRD" - ], - "dinar irakien": [ - "IQD" - ], - "tongan pa\u02bbanga": [ - "TOP" - ], - "fr": [ - "FRF" - ], - "ft": [ - "HUF" - ], - "nuevo sol": [ - "PEN" - ], - "peso convertible argentino": [ - "ARS" - ], - "ff": [ - "FRF" - ], - "dollar de taiwan": [ - "TWD" - ], - "azerbaijani manat": [ - "AZN" - ], - "dirham": [ - "AED" - ], - "antillen gulden": [ - "ANG" - ], - "lari ge\u0301orgien": [ - "GEL" - ], - "fijian dollar": [ - "FJD" - ], - "mark convertible de bosnie herze\u0301govine": [ - "BAM" - ], - "nuovo siclo israeliano": [ - "ILS" - ], - "bhuta\u0301ni ngultrum": [ - "BTN" - ], - "guarani\u0301 paraguayen": [ - "PYG" - ], - "jamaican dollar": [ - "JMD" - ], - "rupia": [ - "LKR", - "SCR", - "INR", - "NPR" - ], - "dinar libyen": [ - "LYD" - ], - "dinaro giordano": [ - "JOD" - ], - "paraguayan guarani\u0301": [ - "PYG" - ], - "maldivische rufiyaa": [ - "MVR" - ], - "marokkanischer dirham": [ - "MAD" - ], - "franco pacifico": [ - "XPF" - ], - "lats": [ - "LVL" - ], - "forinto": [ - "HUF" - ], - "dollar be\u0301lizien": [ - "BZD" - ], - "forints": [ - "HUF" - ], - "do\u0301lar bahameno": [ - "BSD" - ], - "hrywen": [ - "UAH" - ], - "roupie pakistanaise": [ - "PKR" - ], - "rwf": [ - "RWF" - ], - "iraanse rial": [ - "IRR" - ], - "chetrum": [ - "BTN" - ], - "do\u0301lar de las bahamas": [ - "BSD" - ], - "lesothischer loti": [ - "LSL" - ], - "djiboutian franc": [ - "DJF" - ], - "soviet ruble": [ - "SUR" - ], - "madagascan ariary": [ - "MGA" - ], - "hryvna": [ - "UAH" - ], - "komoren franc": [ - "KMF" - ], - "sterlina britannica": [ - "GBP" - ], - "sonderziehungsrecht": [ - "XDR" - ], - "jamaicai dolla\u0301r": [ - "JMD" - ], - "sierra leone i leone": [ - "SLL" - ], - "laoszi kip": [ - "LAK" - ], - "ma\u0301ltai li\u0301ra": [ - "MTL" - ], - "dolar de fiji": [ - "FJD" - ], - "dirham de los emiratos a\u0301rabes unidos": [ - "AED" - ], - "dollaro della namibia": [ - "NAD" - ], - "vn\u0111": [ - "VND" - ], - "dollar des carai\u0308bes orientales": [ - "XCD" - ], - "kelet karibi dolla\u0301r": [ - "XCD" - ], - "dinar argelino": [ - "DZD" - ], - "dolar de barbados": [ - "BBD" - ], - "sbd": [ - "SBD" - ], - "saoedische riyal": [ - "SAR" - ], - "dinar bareini\u0301": [ - "BHD" - ], - "do\u0301lar de guyana": [ - "GYD" - ], - "won norcoreano": [ - "KPW" - ], - "dram arme\u0301nien": [ - "AMD" - ], - "peso de me\u0301jico": [ - "MXN" - ], - "kuna": [ - "HRK" - ], - "kubanischer peso": [ - "CUP" - ], - "sambia kwacha": [ - "ZMW" - ], - "sri lankaanse roepie": [ - "LKR" - ], - "neue tu\u0308rkische lira": [ - "TRY" - ], - "algerischer dinar": [ - "DZD" - ], - "hong kong dollar": [ - "HKD" - ], - "$a": [ - "ARP" - ], - "rupia nepalese": [ - "NPR" - ], - "bhat": [ - "THB" - ], - "maleisische ringgit": [ - "MYR" - ], - "rupia nepalesa": [ - "NPR" - ], - "tsjechische kroon": [ - "CZK" - ], - "dong": [ - "VND" - ], - "xof": [ - "XOF" - ], - "chilean peso": [ - "CLP" - ], - "nordkoreanischer won": [ - "KPW" - ], - "soedanese pond": [ - "SDG" - ], - "angol font": [ - "GBP" - ], - "kip laosiano": [ - "LAK" - ], - "dollaro delle barbados": [ - "BBD" - ], - "gpb": [ - "GBP" - ], - "nuovo dollaro taiwanese": [ - "TWD" - ], - "pond sterling": [ - "GBP" - ], - "nouveau shekel": [ - "ILS" - ], - "libanees pond": [ - "LBP" - ], - "kuvaiti dina\u0301r": [ - "KWD" - ], - "kenyan shilling": [ - "KES" - ], - "dolar bahamen\u0303o": [ - "BSD" - ], - "surinaamse gulden": [ - "SRG" - ], - "tschang": [ - "THB" - ], - "north korean won": [ - "KPW" - ], - "fiorino ungherese": [ - "HUF" - ], - "franco yibuti\u0301": [ - "DJF" - ], - "servische dinar": [ - "RSD" - ], - "manat turkme\u0300ne": [ - "TMT" - ], - "swiss franken": [ - "CHF" - ], - "costa rica colo\u0301n": [ - "CRC" - ], - "franco yibutiense": [ - "DJF" - ], - "venezolaanse boli\u0301var": [ - "VEF" - ], - "marco de la repu\u0301blica democratica alemana": [ - "DDM" - ], - "karod": [ - "NPR" - ], - "riyal": [ - "SAR" - ], - "birr e\u0301thiopien": [ - "ETB" - ], - "francs pacifique": [ - "XPF" - ], - "rufiyaa delle maldive": [ - "MVR" - ], - "libyan dinar": [ - "LYD" - ], - "siclo israeliano": [ - "ILS" - ], - "santomese dobra": [ - "STD" - ], - "mauritiaanse roepie": [ - "MUR" - ], - "srilankaanse rupee": [ - "LKR" - ], - "sum uzbeco": [ - "UZS" - ], - "laari": [ - "MVR" - ], - "dolar de trinidad y tobago": [ - "TTD" - ], - "austral argentino": [ - "ARA" - ], - "do\u0301lar fijiano": [ - "FJD" - ], - "bz$": [ - "BZD" - ], - "argentijnse peso": [ - "ARS" - ], - "vnd": [ - "VND" - ], - "dong vietnamien": [ - "VND" - ], - "ngultrum butanes": [ - "BTN" - ], - "do\u0301lar del caribe este": [ - "XCD" - ], - "pakistaanse roepie": [ - "PKR" - ], - "drtrigonbot:exchange rate data:usd": [ - "USD" - ], - "indone\u0301z ru\u0301pia": [ - "IDR" - ], - "riyal dell'oman": [ - "OMR" - ], - "gambiai dalasi": [ - "GMD" - ], - "dollaro delle salomone": [ - "SBD" - ], - "bermuda dollar": [ - "BMD" - ], - "km": [ - "BAM" - ], - "kr": [ - "DKK" - ], - "mozambican escudo": [ - "MZE" - ], - "samoan tala": [ - "WST" - ], - "brazil real": [ - "BRL" - ], - "dollaro della guyana": [ - "GYD" - ], - "norve\u0301g korona": [ - "NOK" - ], - "dobra di sao tome\u0301 e principe": [ - "STD" - ], - "cdf": [ - "CDF" - ], - "azerbeidzjaanse manat": [ - "AZN" - ], - "droits de tirage speciaux": [ - "XDR" - ], - "paanga": [ - "TOP" - ], - "livre des i\u0302les malouines": [ - "FKP" - ], - "ugx": [ - "UGX" - ], - "holland antilla\u0301kbeli forint": [ - "ANG" - ], - "\u20a3": [ - "FRF" - ], - "costa rican colo\u0301n": [ - "CRC" - ], - "roupie indone\u0301sienne": [ - "IDR" - ], - "rd$": [ - "DOP" - ], - "dollar australien": [ - "AUD" - ], - "russian ruble": [ - "RUB" - ], - "mianmari kjap": [ - "MMK" - ], - "nicaraguan co\u0301rdoba": [ - "NIO" - ], - "florin aruben\u0303o": [ - "AWG" - ], - "rupie indiane": [ - "INR" - ], - "florin arubain": [ - "AWG" - ], - "dinar kuwaiti\u0301": [ - "KWD" - ], - "hryvnya": [ - "UAH" - ], - "tamil rupee": [ - "LKR" - ], - "oegandese shilling": [ - "UGX" - ], - "corona cecoslovacca": [ - "CSK" - ], - "clp$": [ - "CLP" - ], - "cheli\u0301n ugandes": [ - "UGX" - ], - "kina": [ - "PGK" - ], - "noord koreaanse won": [ - "KPW" - ], - "chilenischer peso": [ - "CLP" - ], - "uganda schilling": [ - "UGX" - ], - "uruguayaanse peso": [ - "UYU" - ], - "metical": [ - "MZN" - ], - "\u0440\u0443\u0431": [ - "RUB" - ], - "marokko\u0301i dirham": [ - "MAD" - ], - "ars": [ - "ARS" - ], - "iraki dina\u0301r": [ - "IQD" - ], - "tugrik mongolo": [ - "MNT" - ], - "soedanees pond": [ - "SDG" - ], - "honduran lempira": [ - "HNL" - ], - "rial dell'oman": [ - "OMR" - ], - "sek": [ - "SEK" - ], - "franc malgache": [ - "MGA" - ], - "fille\u0301r": [ - "HUF" - ], - "piso": [ - "PHP" - ], - "cayman islands dollar": [ - "KYD" - ], - "guyaanse dollar": [ - "GYD" - ], - "won": [ - "KRW" - ], - "barbadosi dolla\u0301r": [ - "BBD" - ], - "bosnische inwisselbare mark": [ - "BAM" - ], - "\u20b8": [ - "KZT" - ], - "dollar neo zelandais": [ - "NZD" - ], - "leone sierraleonese": [ - "SLL" - ], - "franco comorano": [ - "KMF" - ], - "guineese frank": [ - "GNF" - ], - "renminbi": [ - "CNY" - ], - "alba\u0301n lek": [ - "ALL" - ], - "ethiopische birr": [ - "ETB" - ], - "sterlina di sant\u2019elena": [ - "SHP" - ], - "corona islandesa": [ - "ISK" - ], - "corona islandese": [ - "ISK" - ], - "dolar bermudeno": [ - "BMD" - ], - "surinamese dollar": [ - "SRD" - ], - "nicaraguaanse cordoba": [ - "NIO" - ], - "loti lesothiano": [ - "LSL" - ], - "australischer dollar": [ - "AUD" - ], - "canadian dollar": [ - "CAD" - ], - "yen giapponese": [ - "JPY" - ], - "mongolian to\u0308gro\u0308g": [ - "MNT" - ], - "chelin ugandes": [ - "UGX" - ], - "chinese yuan": [ - "CNY" - ], - "shilling somalien": [ - "SOS" - ], - "hongkongse dollar": [ - "HKD" - ], - "bolivar": [ - "VEF" - ], - "riyal yemenita": [ - "YER" - ], - "florin des antilles ne\u0301erlandaises": [ - "ANG" - ], - "\u20b9": [ - "INR" - ], - "xaf": [ - "XAF" - ], - "philippine peso": [ - "PHP" - ], - "afghan afghani": [ - "AFN" - ], - "dominikai peso": [ - "DOP" - ], - "zuid koreaanse won": [ - "KRW" - ], - "cubaanse peso": [ - "CUP" - ], - "nepalese rupee": [ - "NPR" - ], - "kyat birmano": [ - "MMK" - ], - "franc or": [ - "XFO" - ], - "fiorino surinamese": [ - "SRG" - ], - "czech koruna": [ - "CZK" - ], - "verenigde arabische emiraten dirham": [ - "AED" - ], - "tanzaniaanse shilling": [ - "TZS" - ], - "rupia mauriziana": [ - "MUR" - ], - "monnaie canadienne": [ - "CAD" - ], - "do\u0301lar bruneano": [ - "BND" - ], - "koruna c\u030cesko slovenska\u0301": [ - "CSK" - ], - "pound": [ - "GBP" - ], - "pounds sterling": [ - "GBP" - ], - "jpy": [ - "JPY" - ], - "bs$": [ - "BSD" - ], - "pula botswanais": [ - "BWP" - ], - "haitiaanse gourde": [ - "HTG" - ], - "dinar de bahrein": [ - "BHD" - ], - "dollar jamaicain": [ - "JMD" - ], - "peso ley": [ - "ARS" - ], - "do\u0301lares neozelandeses": [ - "NZD" - ], - "ten\u030cn\u030ce": [ - "TMT" - ], - "pondteken": [ - "GBP" - ], - "\u5143": [ - "CNY" - ], - "franc uic": [ - "XFU" - ], - "syp": [ - "SYP" - ], - "dzsibuti frank": [ - "DJF" - ], - "dollar de la jamai\u0308que": [ - "JMD" - ], - "dinaro tunisino": [ - "TND" - ], - "yuan": [ - "CNY" - ], - "sudanesisches pfund": [ - "SDG" - ], - "euro": [ - "EUR" - ], - "peruanischer nuevo sol": [ - "PEN" - ], - "falkland pound": [ - "FKP" - ], - "forint hungaro": [ - "HUF" - ], - "couronne suedoise": [ - "SEK" - ], - "peso uruguayen": [ - "UYU" - ], - "nami\u0301biai dolla\u0301r": [ - "NAD" - ], - "do\u0301lar bahamen\u0303o": [ - "BSD" - ], - "leone": [ - "SLL" - ], - "libanon pfund": [ - "LBP" - ], - "riyal saudi": [ - "SAR" - ], - "mozambican metical": [ - "MZN" - ], - "dollaro liberiano": [ - "LRD" - ], - "dolar de guyana": [ - "GYD" - ], - "brazilian real": [ - "BRL" - ], - "do\u0301lar de las islas caiman": [ - "KYD" - ], - "$": [ - "USD", - "MXN", - "ARS", - "CAD" - ], - "cup": [ - "CUP" - ], - "real brasilen\u0303o": [ - "BRL" - ], - "peso mexicain": [ - "MXN" - ], - "cuc": [ - "CUC" - ], - "\u0433\u0440\u043d": [ - "UAH" - ], - "monnaie franc\u0327aise": [ - "FRF" - ], - "guarani\u0301 de paraguay": [ - "PYG" - ], - "pa\u02bbanga": [ - "TOP" - ], - "marco": [ - "DDM" - ], - "panamese balboa": [ - "PAB" - ], - "dolar caimano": [ - "KYD" - ], - "feninga": [ - "BAM" - ], - "kazah tenge": [ - "KZT" - ], - "na\u0192": [ - "ANG" - ], - "belgian congolese franc": [ - "CDF" - ], - "jamaika dollar": [ - "JMD" - ], - "to\u0308ro\u0308k u\u0301j li\u0301ra": [ - "TRY" - ], - "nige\u0301riai naira": [ - "NGN" - ], - "oude metical": [ - "MZN" - ], - "singapur dollar": [ - "SGD" - ], - "b$": [ - "BSD" - ], - "metical del mozambico": [ - "MZN" - ], - "ariary malgascio": [ - "MGA" - ], - "bolivar venezuelano": [ - "VEF" - ], - "corona norvegese": [ - "NOK" - ], - "s/.": [ - "PEN" - ], - "franco del burundi": [ - "BIF" - ], - "yemeni rial": [ - "YER" - ], - "dirham de emiratos arabes unidos": [ - "AED" - ], - "riel": [ - "KHR" - ], - "venezolanischer boli\u0301var": [ - "VEF" - ], - "de\u0301l szuda\u0301ni font": [ - "SSP" - ], - "\u20a4": [ - "ITL" - ], - "dolar de brunei": [ - "BND" - ], - "colo\u0301n costaricano": [ - "CRC" - ], - "dinaro kuwaitiano": [ - "KWD" - ], - "re\u0301aux bre\u0301siliens": [ - "BRL" - ], - "pen": [ - "PEN" - ], - "indiase roepie": [ - "INR" - ], - "rupia delle seychelles": [ - "SCR" - ], - "lari": [ - "GEL" - ], - "dollaro di barbados": [ - "BBD" - ], - "xang": [ - "THB" - ], - "taiwanese dollar": [ - "TWD" - ], - "paraguayi guarani\u0301": [ - "PYG" - ], - "cambodian riel": [ - "KHR" - ], - "rub": [ - "RUB" - ], - "dinaro algerino": [ - "DZD" - ], - "bs": [ - "BSD", - "BOB" - ], - "syrisches pfund": [ - "SYP" - ], - "rial iranien": [ - "IRR" - ], - "dollar namibien": [ - "NAD" - ], - "couronne tche\u0301coslovaque": [ - "CSK" - ], - "couronne tchecoslovaque": [ - "CSK" - ], - "peruvian nuevo sol": [ - "PEN" - ], - "lat leton": [ - "LVL" - ], - "costa ricaanse colon": [ - "CRC" - ], - "schweizer franken": [ - "CHF" - ], - "dollar tai\u0308wanais": [ - "TWD" - ], - "japanese yen": [ - "JPY" - ], - "malediven rupie": [ - "MVR" - ], - "arubaanse florijn": [ - "AWG" - ], - "grivna": [ - "UAH" - ], - "ostkaribischer dollar": [ - "XCD" - ], - "mkd": [ - "MKD" - ], - "\u00a5": [ - "JPY" - ], - "ci$": [ - "KYD" - ], - "yuans": [ - "CNY" - ], - "xpf": [ - "XPF" - ], - "lao kip": [ - "LAK" - ], - "franco congoleno": [ - "CDF" - ], - "marco bosnioherzegovino": [ - "BAM" - ], - "sdr": [ - "XDR" - ], - "dollaro del belize": [ - "BZD" - ], - "peso argentino": [ - "ARP" - ], - "dinaro iracheno": [ - "IQD" - ], - "hongkong dollar": [ - "HKD" - ], - "guarani\u0301 paraguaiano": [ - "PYG" - ], - "flori\u0301n antillano neerlande\u0301s": [ - "ANG" - ], - "dirham marocain": [ - "MAD" - ], - "rial irani": [ - "IRR" - ], - "peso d'uruguay": [ - "UYU" - ], - "forinto hu\u0301ngaro": [ - "HUF" - ], - "escudo cap verdien": [ - "CVE" - ], - "mongol tugrik": [ - "MNT" - ], - "gha\u0301nai cedi": [ - "GHS" - ], - "do\u0301lar del caribe oriental": [ - "XCD" - ], - "riyal saudita": [ - "SAR" - ], - "omani rial": [ - "OMR" - ], - "dinar tunisien": [ - "TND" - ], - "cape verdean escudo": [ - "CVE" - ], - "peso do\u0301lar": [ - "ARS" - ], - "dolar namibio": [ - "NAD" - ], - "lyd": [ - "LYD" - ], - "sint heleens pond": [ - "SHP" - ], - "nieuwe israe\u0308lische sheqel": [ - "ILS" - ], - "laotiaanse kip": [ - "LAK" - ], - "bolivian boliviano": [ - "BOB" - ], - "kirgizische som": [ - "KGS" - ], - "denaro macedone": [ - "MKD" - ], - "swiss franco": [ - "CHF" - ], - "birr eti\u0301ope": [ - "ETB" - ], - "barbadian dollar": [ - "BBD" - ], - "dolar canadiense": [ - "CAD" - ], - "swiss francs": [ - "CHF" - ], - "tonga pa`anga": [ - "TOP" - ], - "dinar de bahrei\u0308n": [ - "BHD" - ], - "dollar des iles salomon": [ - "SBD" - ], - "dobra santotomense": [ - "STD" - ], - "leu rumano": [ - "RON" - ], - "lisente": [ - "LSL" - ], - "manat turcomano": [ - "TMT" - ], - "taka bangladeshi": [ - "BDT" - ], - "dram": [ - "AMD" - ], - "macedonische denar": [ - "MKD" - ], - "israelische sjekel": [ - "ILS" - ], - "dop": [ - "DOP" - ], - "vanuatu vatu": [ - "VUV" - ], - "dollar des i\u0302les salomon": [ - "SBD" - ], - "franzo\u0308sischer franken": [ - "FRF" - ], - "guarani": [ - "PYG" - ], - "su\u0308dsudan pfund": [ - "SSP" - ], - "roemeense leu": [ - "RON" - ], - "mark convertible": [ - "BAM" - ], - "franco de djibouti": [ - "DJF" - ], - "ugandan shilling": [ - "UGX" - ], - "pazifik franc": [ - "XPF" - ], - "rublo tayiko": [ - "TJR" - ], - "argentinischer peso": [ - "ARS" - ], - "bahraini dinar": [ - "BHD" - ], - "amerikaanse dollar": [ - "USD" - ], - "franc comorien": [ - "KMF" - ], - "dolar neocelande\u0301s": [ - "NZD" - ], - "libra sudanesa": [ - "SDG" - ], - "ugandai shilling": [ - "UGX" - ], - "peso argentin": [ - "ARS" - ], - "tugrik mongol": [ - "MNT" - ], - "fiorino delle antille olandesi": [ - "ANG" - ], - "hryvnia": [ - "UAH" - ], - "ma\u0308tonya": [ - "ETB" - ], - "dalasi": [ - "GMD" - ], - "couronne tche\u0300que": [ - "CZK" - ], - "lkr": [ - "LKR" - ], - "clps": [ - "CLP" - ], - "dolar surinames": [ - "SRD" - ], - "kuwait dinar": [ - "KWD" - ], - "ruma\u0308nischer leu": [ - "RON" - ], - "do\u0301lar jamaicano": [ - "JMD" - ], - "nuevo dolar taiwane\u0301s": [ - "TWD" - ], - "venezolanischer bolivar": [ - "VEF" - ], - "qatarese rial": [ - "QAR" - ], - "do\u0301lar de surinam": [ - "SRD" - ], - "livres sterling": [ - "GBP" - ], - "g$": [ - "GYD" - ], - "ruma\u0308nischer lei": [ - "RON" - ], - "leone della sierra leone": [ - "SLL" - ], - "manat azero": [ - "AZN" - ], - "rwandese frank": [ - "RWF" - ], - "ancien franc": [ - "FRF" - ], - "naira": [ - "NGN" - ], - "koruna ceskoslovenska": [ - "CSK" - ], - "colo\u0301n costarricense": [ - "CRC" - ], - "kubai peso": [ - "CUP" - ], - "riel camboyano": [ - "KHR" - ], - "pa'anga tongano": [ - "TOP" - ], - "sri lankan rupee": [ - "LKR" - ], - "hk$": [ - "HKD" - ], - "dollar libe\u0301rien": [ - "LRD" - ], - "pa'anga di tonga": [ - "TOP" - ], - "norwegian krone": [ - "NOK" - ], - "scudo capoverdiano": [ - "CVE" - ], - "franco congolese": [ - "CDF" - ], - "birr": [ - "ETB" - ], - "schwedische krone": [ - "SEK" - ], - "boliviano bolivien": [ - "BOB" - ], - "bdt": [ - "BTN" - ], - "do\u0301lar guyanes": [ - "GYD" - ], - "lilangeni dello swaziland": [ - "SZL" - ], - "libanesisches pfund": [ - "LBP" - ], - "schottische pfund": [ - "GBP" - ], - "griekse drachme": [ - "GRD" - ], - "moldovan leu": [ - "MDL" - ], - "lek": [ - "ALL" - ], - "\u00a3": [ - "GBP" - ], - "do\u0301lar australiano": [ - "AUD" - ], - "lev": [ - "BGN" - ], - "lew": [ - "BGN" - ], - "uganda shilling": [ - "UGX" - ], - "hkd": [ - "HKD" - ], - "bd$": [ - "BMD" - ], - "re\u0301al bre\u0301silien": [ - "BRL" - ], - "tunesischer dinar": [ - "TND" - ], - "austral (monnaie)": [ - "ARA" - ], - "tongaanse pa'anga": [ - "TOP" - ], - "couronne sue\u0301doise": [ - "SEK" - ], - "franc de djibouti": [ - "DJF" - ], - "madagaszka\u0301ri ariary": [ - "MGA" - ], - "rupia mauricia": [ - "MUR" - ], - "solomon dollar": [ - "SBD" - ], - "kro\u0301nur": [ - "ISK" - ], - "khoums": [ - "MRO" - ], - "su\u0308dsudan pound": [ - "SSP" - ], - "sgd": [ - "SGD" - ], - "russischer rubel": [ - "RUB" - ], - "usd": [ - "USD" - ], - "livre des i\u0302les falkland": [ - "FKP" - ], - "comorian franc": [ - "KMF" - ], - "chf": [ - "CHF" - ], - "ush": [ - "UGX" - ], - "costa rica colon": [ - "CRC" - ], - "rial yemenita": [ - "YER" - ], - "marco bosniaco": [ - "BAM" - ], - "rial yemenite": [ - "YER" - ], - "brit font": [ - "GBP" - ], - "tercera dracma griega": [ - "GRD" - ], - "tala samoano": [ - "WST" - ], - "manat azeri": [ - "AZN" - ], - "santi\u0304ms": [ - "LVL" - ], - "ostmark": [ - "DDM" - ], - "f": [ - "ANG" - ], - "nuova lira turca": [ - "TRY" - ], - "zuid soedanees pond": [ - "SSP" - ], - "turkish lira": [ - "TRY" - ], - "rupia indonesiana": [ - "IDR" - ], - "da\u0308nische krone": [ - "DKK" - ], - "diritti speciali di prelievo": [ - "XDR" - ], - "do\u0301lar de nueva zelanda": [ - "NZD" - ], - "aluchip": [ - "DDM" - ], - "peso uruguayo": [ - "UYU" - ], - "xcd": [ - "XCD" - ], - "nuevo do\u0301lar de taiwan": [ - "TWD" - ], - "k.s.": [ - "KGS" - ], - "dinars alge\u0301rien": [ - "DZD" - ], - "russische roebel": [ - "RUB" - ], - "afn": [ - "AFN" - ], - "\u20a6": [ - "NGN" - ], - "corona danese": [ - "DKK" - ], - "corona danesa": [ - "DKK" - ], - "moneda canadiense": [ - "CAD" - ], - "ruandai frank": [ - "RWF" - ], - "libra de santa helena": [ - "SHP" - ], - "manat azeri\u0301": [ - "AZN" - ], - "do\u0301lar de hong kong": [ - "HKD" - ], - "armenian dram": [ - "AMD" - ], - "tetradrachme": [ - "GRD" - ], - "chileense peso": [ - "CLP" - ], - "franchi svizzeri": [ - "CHF" - ], - "boliviaanse boliviano": [ - "BOB" - ], - "do\u0301lar de bermudas": [ - "BMD" - ], - "colon costaricain": [ - "CRC" - ], - "dollar bahame\u0301en": [ - "BSD" - ], - "dollaro delle cayman": [ - "KYD" - ], - "do\u0301lar neozelande\u0301s": [ - "NZD" - ], - "riyal saudi\u0301": [ - "SAR" - ], - "georgian lari": [ - "GEL" - ], - "kiwi dollar": [ - "NZD" - ], - "shekkel": [ - "ILS" - ], - "si$": [ - "SBD" - ], - "dobra santome\u0301en": [ - "STD" - ], - "dolar neoze\u0301landes": [ - "NZD" - ], - "fiorino di aruba": [ - "AWG" - ], - "dobra": [ - "STD" - ], - "british pound": [ - "GBP" - ], - "to\u0308mling": [ - "THB" - ], - "afg": [ - "AFN" - ], - "thai ba\u0301t": [ - "THB" - ], - "fu\u0308lo\u0308p szigeteki peso": [ - "PHP" - ], - "noorse kroon": [ - "NOK" - ], - "dollar de trinite\u0301 et tobago": [ - "TTD" - ], - "tsh": [ - "TZS" - ], - "lm": [ - "MTL" - ], - "saudi arabische riyal": [ - "SAR" - ], - "ausztra\u0301l dolla\u0301r": [ - "AUD" - ], - "oekraiense hryvnja": [ - "UAH" - ], - "deense kroon": [ - "DKK" - ], - "eur": [ - "EUR" - ], - "uruguayi peso": [ - "UYU" - ], - "liberian dollar": [ - "LRD" - ], - "livre sud soudanaise": [ - "SSP" - ], - "do\u0301lar de fiji": [ - "FJD" - ], - "dollar de la carai\u0308be orientale": [ - "XCD" - ], - "franc poincare\u0301": [ - "XFO" - ], - "gepik": [ - "AZN" - ], - "fl\u00a3": [ - "FKP" - ], - "mexican peso": [ - "MXN" - ], - "diram": [ - "TJS" - ], - "denar mace\u0301donien": [ - "MKD" - ], - "hongkongi dolla\u0301r": [ - "HKD" - ], - "belizaanse dollar": [ - "BZD" - ], - "azeri manat": [ - "AZN" - ], - "dong vietnamita": [ - "VND" - ], - "rublo russo": [ - "RUB" - ], - "dolar beliceno": [ - "BZD" - ], - "su\u0308dsudanesisches pfund": [ - "SSP" - ], - "dolar de las islas caima\u0301n": [ - "KYD" - ], - "ec$": [ - "XCD" - ], - "dirham degli emirati arabi uniti": [ - "AED" - ], - "surinaamse dollar": [ - "SRD" - ], - "franco cfa de africa occidental": [ - "XOF" - ], - "french franc": [ - "FRF" - ], - "\u0192": [ - "ANG" - ], - "roma\u0301n lej": [ - "RON" - ], - "pa'anga": [ - "TOP" - ], - "dollaro dei caraibi orientali": [ - "XCD" - ], - "tyiyn": [ - "KGS" - ], - "cuban convertible peso": [ - "CUC" - ], - "dirham des e\u0301mirats arabes unis": [ - "AED" - ], - "japa\u0301n jen": [ - "JPY" - ], - "kroatische kuna": [ - "HRK" - ], - "sowjetischer rubel": [ - "SUR" - ], - "won sudcoreano": [ - "KRW" - ], - "chelin somali\u0301": [ - "SOS" - ], - "santims": [ - "LVL" - ], - "franc": [ - "CHF", - "FRF" - ], - "halalas": [ - "SAR" - ], - "sva\u0301jci frank": [ - "CHF" - ], - "shekel": [ - "ILS" - ], - "dinar kowei\u0308tien": [ - "KWD" - ], - "l\u00a3": [ - "LBP" - ], - "moroccan dirham": [ - "MAD" - ], - "goldfranc": [ - "XFO" - ], - "jod": [ - "JOD" - ], - "oost carai\u0308bische dollar": [ - "XCD" - ], - "ouguiya mauritana": [ - "MRO" - ], - "cambodjaanse riel": [ - "KHR" - ], - "taka bangladesi\u0301": [ - "BDT" - ], - "ltl": [ - "LTL" - ], - "lettischer lat": [ - "LVL" - ], - "santi\u0304mu": [ - "LVL" - ], - "marco de la repu\u0301blica democra\u0301tica alemana": [ - "DDM" - ], - "franco di gibuti": [ - "DJF" - ], - "santi\u0304mi": [ - "LVL" - ], - "couronne norve\u0301gienne": [ - "NOK" - ], - "libanoni font": [ - "LBP" - ], - "belize i dolla\u0301r": [ - "BZD" - ], - "da\u0301n korona": [ - "DKK" - ], - "serbian dinar": [ - "RSD" - ], - "rial omani": [ - "OMR" - ], - "mark convertible bosniaque": [ - "BAM" - ], - "dollar du be\u0301lize": [ - "BZD" - ], - "pesos argentinos": [ - "ARS" - ], - "lesothaanse loti": [ - "LSL" - ], - "tu\u0308rk liras\u0131": [ - "TRY" - ], - "kwacha zambien": [ - "ZMW" - ], - "dollar trinidadien": [ - "TTD" - ], - "moldavische leu": [ - "MDL" - ], - "tughrik": [ - "MNT" - ], - "leu roumain": [ - "RON" - ], - "szva\u0301zifo\u0308ldi lilangeni": [ - "SZL" - ], - "morocota": [ - "VEF" - ], - "haitianische gourde": [ - "HTG" - ], - "eritreischer nakfa": [ - "ERN" - ], - "mongolischer to\u0308gro\u0308g": [ - "MNT" - ], - "escudo di capo verde": [ - "CVE" - ], - "zwitserse frank": [ - "CHF" - ], - "afga\u0301n afga\u0301ni": [ - "AFN" - ], - "neet": [ - "GBP" - ], - "zwitserse franc": [ - "CHF" - ], - "roupie mauricienne": [ - "MUR" - ], - "do\u0301lar trinitense": [ - "TTD" - ], - "marco de la republica democratica alemana": [ - "DDM" - ], - "tongai pa\u2019anga": [ - "TOP" - ], - "israeli new sheqel": [ - "ILS" - ], - "bermudai dolla\u0301r": [ - "BMD" - ], - "\u20ba": [ - "TRY" - ], - "oost caribische dollar": [ - "XCD" - ], - "ugandese shilling": [ - "UGX" - ], - "derechos especiales de giro": [ - "XDR" - ], - "rupaya": [ - "INR" - ], - "suriname gulden": [ - "SRD" - ], - "tajvani u\u0301j dolla\u0301r": [ - "TWD" - ], - "costa rica i colo\u0301n": [ - "CRC" - ], - "pakistanische rupie": [ - "PKR" - ], - "irak dinar": [ - "IQD" - ], - "alge\u0301riai dina\u0301r": [ - "DZD" - ], - "perui u\u0301j sol": [ - "PEN" - ], - "do\u0301lar caribe este": [ - "XCD" - ], - "kurus": [ - "TRY" - ], - "sfr": [ - "CHF" - ], - "huard canadien": [ - "CAD" - ], - "new zealand dollar": [ - "NZD" - ], - "so\u0308m": [ - "UZS" - ], - "awg": [ - "AWG" - ], - "dollar de guyana": [ - "GYD" - ], - "bosnya\u0301k konvertibilis ma\u0301rka": [ - "BAM" - ], - "suriname i dolla\u0301r": [ - "SRD" - ], - "ukrainische hrywnja": [ - "UAH" - ], - "ngultrum": [ - "BTN" - ], - "gde.": [ - "HTG" - ], - "mexican nuevo peso": [ - "MXN" - ], - "fjd": [ - "FJD" - ], - "dolar jamaiquino": [ - "JMD" - ], - "libyscher dinar": [ - "LYD" - ], - "nuevo shequel": [ - "ILS" - ], - "cheli\u0301n keniano": [ - "KES" - ], - "dollar surinamien": [ - "SRD" - ], - "rublo sovietico": [ - "SUR" - ], - "kaiman dollar": [ - "KYD" - ], - "dollar ne\u0301o ze\u0301landais": [ - "NZD" - ], - "bolga\u0301r leva": [ - "BGN" - ], - "cub$": [ - "CUP" - ], - "szl": [ - "SZL" - ], - "aruba gulden": [ - "AWG" - ], - "mexikanischer peso": [ - "MXN" - ], - "australische dollar": [ - "AUD" - ], - "roupie indonesienne": [ - "IDR" - ], - "albanese lek": [ - "ALL" - ], - "lettische wa\u0308hrung": [ - "LVL" - ], - "dollar ame\u0301ricain": [ - "USD" - ], - "zo\u0308ld foki szigeteki escudo": [ - "CVE" - ], - "saudi riyal": [ - "SAR" - ], - "libra": [ - "GBP" - ], - "isla\u0308ndische krone": [ - "ISK" - ], - "saudi rial": [ - "SAR" - ], - "dollaro della bermuda": [ - "BMD" - ], - "macedo\u0301n de\u0301na\u0301r": [ - "MKD" - ], - "kwanza": [ - "AOA" - ], - "dollar du guyana": [ - "GYD" - ], - "nuevo peso argentino": [ - "ARS" - ], - "dollaro del suriname": [ - "SRD" - ], - "ariary malgache": [ - "MGA" - ], - "saint helena pound": [ - "SHP" - ], - "kambodzsai riel": [ - "KHR" - ], - "surinam dollar": [ - "SRD" - ], - "ouguiya": [ - "MRO" - ], - "mala\u0301j ringgit": [ - "MYR" - ], - "united states dollar": [ - "USD" - ], - "icelandic kro\u0301na": [ - "ISK" - ], - "gbp": [ - "GBP" - ], - "falkland szigeteki font": [ - "FKP" - ], - "sa\u0303o tome\u0301ischer dobra": [ - "STD" - ], - "kwanza angolano": [ - "AOA" - ], - "scellino": [ - "KES" - ], - "dollars canadiens": [ - "CAD" - ], - "guarani\u0301": [ - "PYG" - ], - "kwanza angolana": [ - "AOA" - ], - "litas lituanien": [ - "LTL" - ], - "kajma\u0301n szigeteki dolla\u0301r": [ - "KYD" - ], - "som de kirguista\u0301n": [ - "KGS" - ], - "btn": [ - "BTN" - ], - "chelin somali": [ - "SOS" - ], - "dracma griego moderno": [ - "GRD" - ], - "hai\u0308tiaanse gourde": [ - "HTG" - ], - "kc\u030c": [ - "CZK" - ], - "peso de chile": [ - "CLP" - ], - "mazedonischer denar": [ - "MKD" - ], - "sierra leoonse leone": [ - "SLL" - ], - "franco france\u0301s": [ - "FRF" - ], - "marco della germania est": [ - "DDM" - ], - "cordoba nicaraguense": [ - "NIO" - ], - "do\u0301lar jamaiquino": [ - "JMD" - ], - "cordoba nicaraguayen": [ - "NIO" - ], - "rupia de pakista\u0301n": [ - "PKR" - ], - "pfund sterling": [ - "GBP" - ], - "dollar jamai\u0308quain": [ - "JMD" - ], - "koruna c\u030ceskoslovenska\u0301": [ - "CSK" - ], - "vatu di vanuatu": [ - "VUV" - ], - "nicaraguai co\u0301rdoba": [ - "NIO" - ], - "salu\u0308ng": [ - "THB" - ], - "drachmon": [ - "GRD" - ], - "somalia schilling": [ - "SOS" - ], - "dinar iraqui": [ - "IQD" - ], - "escudo": [ - "CVE" - ], - "hrywni": [ - "UAH" - ], - "libra de santa elena": [ - "SHP" - ], - "couronnes tche\u0300ques": [ - "CZK" - ], - "dolar fiyiano": [ - "FJD" - ], - "\u20a9": [ - "KRW" - ], - "rial iraniano": [ - "IRR" - ], - "bbd": [ - "BBD" - ], - "e\u0301szak i\u0301r font": [ - "GBP" - ], - "$ ca": [ - "CAD" - ], - "quid": [ - "GBP" - ], - "ta\u0301dzsik szomoni": [ - "TJS" - ], - "dram armenio": [ - "AMD" - ], - "rupia singalese": [ - "LKR" - ], - "botswaanse pula": [ - "BWP" - ], - "co\u0301rdoba nicaraguayen": [ - "NIO" - ], - "c$": [ - "NIO", - "CAD" - ], - "oost caraibische dollar": [ - "XCD" - ], - "guyanese dollar": [ - "GYD" - ], - "indonesische roepia": [ - "IDR" - ], - "corone ceche": [ - "CZK" - ], - "franco cfa de a\u0301frica occidental": [ - "XOF" - ], - "currency of mexico": [ - "MXN" - ], - "kwanza reajustado": [ - "AOA" - ], - "botswanai pula": [ - "BWP" - ], - "reais": [ - "BRL" - ], - "cve": [ - "CVE" - ], - "flori\u0301n suriname\u0301s": [ - "SRG" - ], - "franc djibouti": [ - "DJF" - ], - "do\u0301lar beliceno": [ - "BZD" - ], - "forint hu\u0301ngaro": [ - "HUF" - ], - "iranischer rial": [ - "IRR" - ], - "tenge": [ - "KZT" - ], - "czechoslovak koruna": [ - "CSK" - ], - "grivna ucraniana": [ - "UAH" - ], - "dinar alge\u0301rien": [ - "DZD" - ], - "rupia esrilanquesa": [ - "LKR" - ], - "kyrgyz som": [ - "KGS" - ], - "turkmeense manat": [ - "TMT" - ], - "hryvnia ukrainienne": [ - "UAH" - ], - "dollaro di singapore": [ - "SGD" - ], - "dolar de belize": [ - "BZD" - ], - "boli\u0301vares": [ - "VEF" - ], - "sterlina di gibilterra": [ - "GIP" - ], - "shilling ougandais": [ - "UGX" - ], - "rupia pakistani\u0301": [ - "PKR" - ], - "united arab emirates dirham": [ - "AED" - ], - "php": [ - "PHP" - ], - "\u03b4\u03c1": [ - "GRD" - ], - "lari georgiano": [ - "GEL" - ], - "kip laotien": [ - "LAK" - ], - "uquiya": [ - "MRO" - ], - "francs or": [ - "XFO" - ], - "dinar": [ - "TND", - "DZD" - ], - "shilling tanzanien": [ - "TZS" - ], - "kongo\u0301i frank": [ - "CDF" - ], - "franco de yibuti": [ - "DJF" - ], - "dirham marroqui\u0301": [ - "MAD" - ], - "florin hungaro": [ - "HUF" - ], - "tyjyn": [ - "KGS" - ], - "di\u0301rham de los emiratos a\u0301rabes unidos": [ - "AED" - ], - "florin arubais": [ - "AWG" - ], - "la couronne danoise": [ - "DKK" - ], - "gambian dalasi": [ - "GMD" - ], - "szuda\u0301ni font": [ - "SDG" - ], - "corona svedese": [ - "SEK" - ], - "colombiaanse peso": [ - "COP" - ], - "dirham marocchino": [ - "MAD" - ], - "won sud core\u0301en": [ - "KRW" - ], - "seychellois rupee": [ - "SCR" - ], - "gibraltarees pond": [ - "GIP" - ], - "franc fort": [ - "FRF" - ], - "schweizerfranken": [ - "CHF" - ], - "livre soudanaise": [ - "SDG" - ], - "manat aze\u0301ri": [ - "AZN" - ], - "nuevo she\u0301kel": [ - "ILS" - ], - "paraguayaanse guarani": [ - "PYG" - ], - "trinidad and tobago dollar": [ - "TTD" - ], - "tiyin": [ - "UZS" - ], - "dollar de belize": [ - "BZD" - ], - "nuovo siclo": [ - "ILS" - ], - "pyas": [ - "MMK" - ], - "liberiaanse dollar": [ - "LRD" - ], - "quetzal guatemalteco": [ - "GTQ" - ], - "naira nige\u0301rian": [ - "NGN" - ], - "balboa panameno": [ - "PAB" - ], - "indian rupee": [ - "INR" - ], - "bahreini dina\u0301r": [ - "BHD" - ], - "zuid afrikaanse rand": [ - "ZAR" - ], - "roepia": [ - "IDR" - ], - "dollar bermudien": [ - "BMD" - ], - "loti del lesotho": [ - "LSL" - ], - "hondurese lempira": [ - "HNL" - ], - "tsjecho slowaakse kroon": [ - "CSK" - ], - "do\u0301lar de barbados": [ - "BBD" - ], - "su\u0308dafrikanischer rand": [ - "ZAR" - ], - "szau\u0301di ria\u0301l": [ - "SAR" - ], - "szerb dina\u0301r": [ - "RSD" - ], - "roupie du ne\u0301pal": [ - "NPR" - ], - "dinaro": [ - "BHD" - ], - "balboa": [ - "PAB" - ], - "rublo sovie\u0301tico": [ - "SUR" - ], - "dollar de la caraibe orientale": [ - "XCD" - ], - "dolar bruneano": [ - "BND" - ], - "dollaro canadese": [ - "CAD" - ], - "arubai florin": [ - "AWG" - ], - "somali shilling": [ - "SOS" - ], - "peso oro dominicano": [ - "DOP" - ], - "bangladesi taka": [ - "BDT" - ], - "lettischer lats": [ - "LVL" - ], - "marco della repubblica democratica tedesca": [ - "DDM" - ], - "ijslandse kroon": [ - "ISK" - ], - "burundi franc": [ - "BIF" - ], - "rand sud africain": [ - "ZAR" - ], - "corone norvegesi": [ - "NOK" - ], - "do\u0301lar caimano": [ - "KYD" - ], - "burundi frank": [ - "BIF" - ], - "new israeli sheqel": [ - "ILS" - ], - "metical mozambicain": [ - "MZN" - ], - "dolar de surinam": [ - "SRD" - ], - "falkland islands pound": [ - "FKP" - ], - "maurita\u0301niai ouguiya": [ - "MRO" - ], - "u\u0301j ze\u0301landi dolla\u0301r": [ - "NZD" - ], - "lats leton": [ - "LVL" - ], - "somoni tagico": [ - "TJS" - ], - "mozambikaanse metical": [ - "MZN" - ], - "dollaro delle bermuda": [ - "BMD" - ], - "dolar de hong kong": [ - "HKD" - ], - "dollaro delle bermude": [ - "BMD" - ], - "balboa panamense": [ - "PAB" - ], - "roupie srilankaise": [ - "LKR" - ], - "fya\u0308n": [ - "THB" - ], - "dolar guyanes": [ - "GYD" - ], - "franc suisse": [ - "CHF" - ], - "rial irani\u0301": [ - "IRR" - ], - "myanmarese kyat": [ - "MMK" - ], - "costa ricaanse colo\u0301n": [ - "CRC" - ], - "corona checa": [ - "CZK" - ], - "thai baht": [ - "THB" - ], - "djiboutiaanse frank": [ - "DJF" - ], - "schkalim": [ - "ILS" - ], - "\u17db": [ - "KHR" - ], - "franc djiboutien": [ - "DJF" - ], - "dinar koweitien": [ - "KWD" - ], - "loonie": [ - "CAD" - ], - "denari": [ - "MKD" - ], - "lvl": [ - "LVL" - ], - "hryvnja": [ - "UAH" - ], - "lempira hondurien": [ - "HNL" - ], - "franc guineen": [ - "GNF" - ], - "seychelles rupee": [ - "SCR" - ], - "leu rumeno": [ - "RON" - ], - "dirham emirati": [ - "AED" - ], - "co\u0301rdoba nicarague\u0301en": [ - "NIO" - ], - "neuseeland dollar": [ - "NZD" - ], - "\u20aa": [ - "ILS" - ], - "bahamai dolla\u0301r": [ - "BSD" - ], - "szi\u0301r font": [ - "SYP" - ], - "nieuwe israelische sjekel": [ - "ILS" - ], - "franc francais": [ - "FRF" - ], - "jamaicaanse dollar": [ - "JMD" - ], - "burmese kyat": [ - "MMK" - ], - "do\u0301lar de belize": [ - "BZD" - ], - "tunis dinar": [ - "TND" - ], - "hrywnja": [ - "UAH" - ], - "do\u0301lar de belice": [ - "BZD" - ], - "koeweitse dinar": [ - "KWD" - ], - "rial yemeni": [ - "YER" - ], - "quetzal": [ - "GTQ" - ], - "livres sterlings": [ - "GBP" - ], - "hnl": [ - "HNL" - ], - "franco cfa de a\u0301frica central": [ - "XAF" - ], - "scellino keniota": [ - "KES" - ] - }, - "iso4217": { - "DZD": { - "fr": "Dinar alg\u00e9rien", - "en": "Algerian dinar", - "nl": "Algerijnse dinar", - "de": "Algerischer Dinar", - "it": "Dinaro algerino", - "hu": "alg\u00e9riai din\u00e1r", - "es": "Dinar argelino" - }, - "NAD": { - "fr": "Dollar namibien", - "en": "Namibian dollar", - "nl": "Namibische dollar", - "de": "Namibia-Dollar", - "it": "Dollaro namibiano", - "hu": "Nam\u00edbiai doll\u00e1r", - "es": "D\u00f3lar namibio" - }, - "GHS": { - "fr": "Cedi", - "en": "Ghana cedi", - "nl": "Ghanese cedi", - "de": "Cedi", - "it": "Cedi ghanese", - "hu": "Gh\u00e1nai cedi", - "es": "Cedi" - }, - "BZD": { - "fr": "Dollar b\u00e9lizien", - "en": "Belize dollar", - "nl": "Belizaanse dollar", - "de": "Belize-Dollar", - "it": "Dollaro del Belize", - "hu": "Belize-i doll\u00e1r", - "es": "D\u00f3lar belice\u00f1o" - }, - "BGN": { - "fr": "Lev bulgare", - "en": "Bulgarian lev", - "nl": "Bulgaarse lev", - "de": "Lew", - "it": "Lev bulgaro", - "hu": "bolg\u00e1r leva", - "es": "Lev" - }, - "PAB": { - "fr": "Balboa", - "en": "Panamanian balboa", - "nl": "Panamese balboa", - "de": "Panamaischer Balboa", - "it": "Balboa panamense", - "hu": "Panamai balboa", - "es": "Balboa" - }, - "BOB": { - "fr": "boliviano", - "en": "boliviano", - "nl": "Boliviaanse boliviano", - "de": "Boliviano", - "it": "boliviano", - "hu": "bol\u00edviai boliviano", - "es": "boliviano" - }, - "DKK": { - "fr": "Couronne danoise", - "en": "Danish krone", - "nl": "Deense kroon", - "de": "D\u00e4nische Krone", - "it": "Corona danese", - "hu": "d\u00e1n korona", - "es": "Corona danesa" - }, - "BWP": { - "fr": "Pula", - "en": "Botswana pula", - "nl": "Botswaanse pula", - "de": "Botswanischer Pula", - "it": "Pula del Botswana", - "hu": "Botswanai pula", - "es": "Pula" - }, - "LBP": { - "fr": "livre libanaise", - "en": "Lebanese pound", - "nl": "Libanees pond", - "de": "Libanesisches Pfund", - "it": "Lira libanese", - "hu": "libanoni font", - "es": "Libra libanesa" - }, - "TZS": { - "fr": "shilling tanzanien", - "en": "Tanzanian shilling", - "nl": "Tanzaniaanse shilling", - "de": "Tansania-Schilling", - "it": "Scellino tanzaniano", - "hu": "Tanz\u00e1niai shilling", - "es": "chel\u00edn" - }, - "VND": { - "fr": "Dong", - "en": "Vietnamese dong", - "nl": "Vietnamese dong", - "de": "Vietnamesischer \u0110\u1ed3ng", - "it": "\u0110\u1ed3ng vietnamita", - "hu": "vietnami \u0111\u1ed3ng", - "es": "\u0111\u1ed3ng vietnamita" - }, - "AOA": { - "fr": "Kwanza", - "en": "Angolan kwanza", - "nl": "Angolese kwanza", - "de": "Kwanza", - "it": "Kwanza angolano", - "hu": "angolai kwanza", - "es": "Kwanza angole\u00f1o" - }, - "KHR": { - "fr": "Riel", - "en": "riel", - "nl": "Cambodjaanse riel", - "de": "Kambodschanischer Riel", - "it": "Riel cambogiano", - "hu": "kambodzsai riel", - "es": "Riel camboyano" - }, - "MYR": { - "fr": "Ringgit", - "en": "Malaysian ringgit", - "nl": "Maleisische ringgit", - "de": "Ringgit", - "it": "Ringgit malese", - "hu": "mal\u00e1j ringgit", - "es": "Ringgit" - }, - "KYD": { - "fr": "Dollar des \u00eeles Ca\u00efmans", - "en": "Cayman Islands dollar", - "nl": "Kaaimaneilandse dollar", - "de": "Kaiman-Dollar", - "it": "Dollaro delle Cayman", - "hu": "Kajm\u00e1n-szigeteki doll\u00e1r", - "es": "D\u00f3lar de las Islas Caim\u00e1n" - }, - "LYD": { - "fr": "Dinar libyen", - "en": "Libyan dinar", - "nl": "Libische dinar", - "de": "Libyscher Dinar", - "it": "Dinaro libico", - "hu": "L\u00edbiai din\u00e1r", - "es": "Dinar libio" - }, - "UAH": { - "fr": "Hryvnia", - "en": "hryvnia", - "nl": "Oekra\u00efense hryvnja", - "de": "Hrywnja", - "it": "Grivnia ucraina", - "hu": "ukr\u00e1n hrivnya", - "es": "Grivna" - }, - "JOD": { - "fr": "Dinar jordanien", - "en": "Jordanian dinar", - "nl": "Jordaanse dinar", - "de": "Jordanischer Dinar", - "it": "Dinaro giordano", - "hu": "jord\u00e1n din\u00e1r", - "es": "Dinar jordano" - }, - "SUR": { - "fr": "Rouble sovi\u00e9tique", - "en": "Soviet ruble", - "de": "Sowjetischer Rubel", - "it": "Rublo sovietico", - "hu": "Szovjet rubel", - "es": "Rublo sovi\u00e9tico" - }, - "AWG": { - "fr": "Florin arubais", - "en": "Aruban florin", - "nl": "Arubaanse florin", - "de": "Aruba-Florin", - "it": "Fiorino arubano", - "hu": "Arubai florin", - "es": "Flor\u00edn arube\u00f1o" - }, - "SAR": { - "fr": "Riyal saoudien", - "en": "Saudi riyal", - "nl": "Saoedi-Arabische riyal", - "de": "Saudi-Rial", - "it": "Riyal saudita", - "hu": "sza\u00fadi ri\u00e1l", - "es": "Riyal saud\u00ed" - }, - "EUR": { - "fr": "euro", - "en": "euro", - "nl": "euro", - "de": "Euro", - "it": "euro", - "hu": "eur\u00f3", - "es": "euro" - }, - "HKD": { - "fr": "Dollar de Hong Kong", - "en": "Hong Kong dollar", - "nl": "Hongkongse dollar", - "de": "Hongkong-Dollar", - "it": "dollaro hongkonghese", - "hu": "hongkongi doll\u00e1r", - "es": "D\u00f3lar de Hong Kong" - }, - "SRG": { - "en": "Surinamese guilder", - "nl": "Surinaamse gulden", - "it": "Fiorino surinamese", - "es": "Flor\u00edn surinam\u00e9s" - }, - "CHF": { - "fr": "Franc suisse", - "en": "Swiss franc", - "nl": "Zwitserse frank", - "de": "Schweizer Franken", - "it": "franco svizzero", - "hu": "sv\u00e1jci frank", - "es": "franco suizo" - }, - "GIP": { - "fr": "Livre de Gibraltar", - "en": "Gibraltar pound", - "nl": "Gibraltarees pond", - "de": "Gibraltar-Pfund", - "it": "Sterlina di Gibilterra", - "hu": "Gibralt\u00e1ri font", - "es": "Libra gibraltare\u00f1a" - }, - "ALL": { - "fr": "Lek", - "en": "lek", - "nl": "Albanese lek", - "de": "Albanischer Lek", - "it": "Lek albanese", - "hu": "alb\u00e1n lek", - "es": "Lek alban\u00e9s" - }, - "MRO": { - "fr": "Ouguiya", - "en": "Mauritanian ouguiya", - "nl": "Mauritaanse ouguiya", - "de": "Ouguiya", - "it": "Ouguiya mauritana", - "hu": "Maurit\u00e1niai ouguiya", - "es": "Uquiya" - }, - "HRK": { - "fr": "Kuna croate", - "en": "Croatian kuna", - "nl": "Kroatische kuna", - "de": "Kroatische Kuna", - "it": "Kuna croata", - "hu": "horv\u00e1t kuna", - "es": "Kuna croata" - }, - "DJF": { - "fr": "franc Djibouti", - "en": "Djiboutian franc", - "nl": "Djiboutiaanse frank", - "de": "Dschibuti-Franc", - "it": "Franco gibutiano", - "hu": "Dzsibuti frank", - "es": "franco" - }, - "THB": { - "fr": "Baht", - "en": "Thai baht", - "nl": "Thaise baht", - "de": "Baht", - "it": "Baht thailandese", - "hu": "thai b\u00e1t", - "es": "Baht tailand\u00e9s" - }, - "XAF": { - "fr": "Franc CFA", - "en": "Central African CFA franc", - "de": "CFA-Franc BEAC", - "es": "Franco CFA de \u00c1frica Central" - }, - "BND": { - "fr": "Dollar de Brunei", - "en": "Brunei dollar", - "nl": "Bruneise dollar", - "de": "Brunei-Dollar", - "it": "Dollaro del Brunei", - "hu": "brunei doll\u00e1r", - "es": "D\u00f3lar de Brun\u00e9i" - }, - "VUV": { - "fr": "Vatu", - "en": "Vanuatu vatu", - "nl": "Vanuatuaanse vatu", - "de": "Vatu", - "it": "Vatu di Vanuatu", - "hu": "Vanuatui vatu", - "es": "Vatu" - }, - "UYU": { - "fr": "Peso uruguayen", - "en": "Uruguayan peso", - "nl": "Uruguayaanse peso", - "de": "Uruguayischer Peso", - "it": "Peso uruguaiano", - "hu": "Uruguayi peso", - "es": "peso" - }, - "NIO": { - "fr": "C\u00f3rdoba", - "en": "Nicaraguan c\u00f3rdoba", - "nl": "Nicaraguaanse c\u00f3rdoba", - "de": "C\u00f3rdoba Oro", - "it": "C\u00f3rdoba nicaraguense", - "hu": "Nicaraguai c\u00f3rdoba", - "es": "C\u00f3rdoba" - }, - "LAK": { - "fr": "Kip laotien", - "en": "Lao kip", - "nl": "Laotiaanse kip", - "de": "Kip", - "it": "Kip laotiano", - "hu": "laoszi kip", - "es": "Kip laosiano" - }, - "MZE": { - "de": "Mosambikanischer Escudo", - "en": "Mozambican escudo", - "es": "Escudo mozambique\u00f1o" - }, - "SYP": { - "fr": "Livre syrienne", - "en": "Syrian pound", - "nl": "Syrisch pond", - "de": "Syrische Lira", - "it": "Lira siriana", - "hu": "Sz\u00edr font", - "es": "Libra siria" - }, - "MAD": { - "fr": "Dirham marocain", - "en": "Moroccan dirham", - "nl": "Marokkaanse dirham", - "de": "Marokkanischer Dirham", - "it": "Dirham marocchino", - "hu": "Marokk\u00f3i dirham", - "es": "D\u00edrham marroqu\u00ed" - }, - "MZN": { - "fr": "Metical", - "en": "Mozambican metical", - "nl": "Mozambikaanse metical", - "de": "Metical", - "it": "Metical mozambicano", - "hu": "Mozambiki metical", - "es": "Metical mozambique\u00f1o" - }, - "SCR": { - "fr": "roupie seychelloise", - "en": "Seychellois rupee", - "nl": "Seychelse roepie", - "de": "Seychellen-Rupie", - "it": "Rupia delle Seychelles", - "hu": "Seychelle-i r\u00fapia", - "es": "rupia" - }, - "ZAR": { - "fr": "rand", - "en": "South African rand", - "nl": "Zuid-Afrikaanse rand", - "de": "S\u00fcdafrikanischer Rand", - "it": "Rand sudafricano", - "hu": "D\u00e9l-afrikai rand", - "es": "Rand sudafricano" - }, - "NPR": { - "fr": "Roupie n\u00e9palaise", - "en": "Nepalese rupee", - "nl": "Nepalese roepie", - "de": "Nepalesische Rupie", - "it": "Rupia nepalese", - "hu": "nep\u00e1li r\u00fapia", - "es": "Rupia nepal\u00ed" - }, - "XSU": { - "fr": "Sucre", - "en": "SUCRE", - "nl": "SUCRE", - "es": "SUCRE", - "de": "SUCRE" - }, - "NGN": { - "fr": "Naira", - "en": "Nigerian naira", - "nl": "Nigeriaanse naira", - "de": "Naira", - "it": "Naira nigeriana", - "hu": "Nig\u00e9riai naira", - "es": "Naira" - }, - "CRC": { - "fr": "col\u00f3n", - "en": "Costa Rican col\u00f3n", - "nl": "Costa Ricaanse colon", - "de": "Costa-Rica-Col\u00f3n", - "it": "Col\u00f3n costaricano", - "hu": "Costa Rica-i col\u00f3n", - "es": "Col\u00f3n" - }, - "AED": { - "fr": "Dirham des \u00c9mirats arabes unis", - "en": "United Arab Emirates dirham", - "nl": "VAE-Dirham", - "de": "VAE-Dirham", - "it": "Dirham degli Emirati Arabi Uniti", - "hu": "emir\u00e1tusi dirham", - "es": "D\u00edrham de los Emiratos \u00c1rabes Unidos" - }, - "GBP": { - "fr": "livre sterling", - "en": "pound sterling", - "nl": "pond sterling", - "de": "Pfund Sterling", - "it": "sterlina britannica", - "hu": "font sterling", - "es": "libra esterlina" - }, - "LKR": { - "fr": "roupie srilankaise", - "en": "Sri Lankan rupee", - "nl": "Sri Lankaanse roepie", - "de": "Sri-Lanka-Rupie", - "it": "Rupia singalese", - "hu": "Sr\u00ed Lanka-i r\u00fapia", - "es": "rupia" - }, - "PKR": { - "fr": "Roupie pakistanaise", - "en": "Pakistani rupee", - "nl": "Pakistaanse roepie", - "de": "Pakistanische Rupie", - "it": "Rupia pakistana", - "hu": "pakiszt\u00e1ni r\u00fapia", - "es": "Rupia pakistan\u00ed" - }, - "HUF": { - "fr": "Forint", - "en": "Hungarian forint", - "nl": "Hongaarse forint", - "de": "Forint", - "it": "Fiorino ungherese", - "hu": "magyar forint", - "es": "Forinto h\u00fangaro" - }, - "SZL": { - "fr": "Lilangeni", - "en": "Swazi lilangeni", - "nl": "Swazische lilangeni", - "de": "Lilangeni", - "it": "Lilangeni dello Swaziland", - "hu": "Szv\u00e1zif\u00f6ldi lilangeni", - "es": "lilangeni" - }, - "LSL": { - "fr": "Loti", - "en": "Lesotho loti", - "nl": "Lesothaanse loti", - "de": "Lesothischer Loti", - "it": "Loti lesothiano", - "hu": "Lesoth\u00f3i loti", - "es": "Loti" - }, - "MNT": { - "fr": "Tugrik", - "en": "Mongolian t\u00f6gr\u00f6g", - "nl": "Mongoolse tugrik", - "de": "T\u00f6gr\u00f6g", - "it": "Tugrik mongolo", - "hu": "mongol tugrik", - "es": "Tugrik mongol" - }, - "AMD": { - "fr": "Dram", - "en": "Armenian dram", - "nl": "Armeense dram", - "de": "Armenischer Dram", - "it": "Dram armeno", - "hu": "\u00f6rm\u00e9ny dram", - "es": "Dram armenio" - }, - "UGX": { - "fr": "shilling ougandais", - "en": "Ugandan shilling", - "nl": "Oegandese shilling", - "de": "Uganda-Schilling", - "it": "Scellino ugandese", - "hu": "Ugandai shilling", - "es": "chel\u00edn" - }, - "QAR": { - "fr": "Riyal qatarien", - "en": "Qatari riyal", - "nl": "Qatarese rial", - "de": "Katar-Riyal", - "it": "Riyal del Qatar", - "hu": "katari ri\u00e1l", - "es": "Riyal catar\u00ed" - }, - "XDR": { - "fr": "Droits de tirage sp\u00e9ciaux", - "en": "Special drawing rights", - "nl": "Speciale trekkingsrechten", - "de": "Sonderziehungsrecht", - "it": "Diritti speciali di prelievo", - "hu": "SDR", - "es": "Derechos Especiales de Giro" - }, - "ITL": { - "fr": "Lire italienne", - "en": "Italian lira", - "nl": "Italiaanse lire", - "de": "Italienische Lira", - "it": "lira italiana", - "hu": "Olasz l\u00edra", - "es": "Lira italiana" - }, - "JMD": { - "fr": "Dollar jama\u00efcain", - "en": "Jamaican dollar", - "nl": "Jamaicaanse dollar", - "de": "Jamaika-Dollar", - "it": "Dollaro giamaicano", - "hu": "Jamaicai doll\u00e1r", - "es": "D\u00f3lar jamaiquino" - }, - "GEL": { - "fr": "lari", - "en": "Georgian lari", - "nl": "Georgische lari", - "de": "Georgischer Lari", - "it": "Lari georgiano", - "hu": "gr\u00faz lari", - "es": "lari" - }, - "SHP": { - "fr": "Livre de Sainte-H\u00e9l\u00e8ne", - "en": "Saint Helena pound", - "nl": "Sint-Heleens pond", - "de": "St.-Helena-Pfund", - "it": "Sterlina di Sant'Elena", - "hu": "Szent Ilona-i font", - "es": "Libra de Santa Elena" - }, - "AFN": { - "fr": "Afghani", - "en": "Afghan afghani", - "nl": "Afghaanse afghani", - "de": "Afghani", - "it": "Afghani afgano", - "hu": "afg\u00e1n afg\u00e1ni", - "es": "Afgani afgano" - }, - "MMK": { - "fr": "Kyat", - "en": "kyat", - "nl": "Myanmarese kyat", - "de": "Kyat", - "it": "Kyat birmano", - "hu": "mianmari kjap", - "es": "Kyat birmano" - }, - "CSK": { - "fr": "couronne tch\u00e9coslovaque", - "en": "Czechoslovak koruna", - "nl": "Tsjecho-Slowaakse kroon", - "de": "Tschechoslowakische Krone", - "it": "Corona cecoslovacca", - "hu": "csehszlov\u00e1k korona", - "es": "Corona checoslovaca" - }, - "KPW": { - "fr": "Won nord-cor\u00e9en", - "en": "North Korean won", - "nl": "Noord-Koreaanse won", - "de": "Nordkoreanischer Won", - "it": "Won nordcoreano", - "hu": "\u00e9szak-koreai von", - "es": "W\u014fn norcoreano" - }, - "TRY": { - "fr": "Livre turque", - "en": "Turkish lira", - "nl": "Nieuwe Turkse lira", - "de": "T\u00fcrkische Lira", - "it": "Nuova lira turca", - "hu": "t\u00f6r\u00f6k \u00faj l\u00edra", - "es": "Lira turca" - }, - "BDT": { - "fr": "Taka", - "en": "taka", - "nl": "Bengalese taka", - "de": "Taka", - "it": "Taka bengalese", - "hu": "bangladesi taka", - "es": "Taka banglades\u00ed" - }, - "GRD": { - "fr": "Drachme moderne grecque", - "en": "Greek drachma", - "nl": "Drachme", - "de": "Griechische Drachme", - "it": "Dracma greca", - "es": "Dracma griega moderna" - }, - "YER": { - "fr": "rial y\u00e9m\u00e9nite", - "en": "Yemeni rial", - "nl": "Jemenitische rial", - "de": "Jemen-Rial", - "it": "riyal yemenita", - "hu": "Jemeni ri\u00e1l", - "es": "rial yemen\u00ed" - }, - "DDM": { - "fr": "Mark est-allemand", - "en": "East German mark", - "nl": "Oost-Duitse mark", - "de": "Mark", - "it": "Marco della Repubblica Democratica Tedesca", - "es": "Marco de la Rep\u00fablica Democr\u00e1tica Alemana" - }, - "HTG": { - "fr": "Gourde", - "en": "Haitian gourde", - "nl": "Ha\u00eftiaanse gourde", - "de": "Gourde", - "it": "Gourde haitiano", - "hu": "haiti gourde", - "es": "Gourde" - }, - "XOF": { - "fr": "Franc CFA", - "en": "West African CFA franc", - "de": "CFA-Franc BCEAO", - "es": "Franco CFA de \u00c1frica Occidental" - }, - "MGA": { - "fr": "ariary", - "en": "Malagasy ariary", - "nl": "Malagassische ariary", - "de": "Ariary", - "it": "Ariary malgascio", - "hu": "Madagaszk\u00e1ri ariary", - "es": "ariary" - }, - "PHP": { - "fr": "peso philippin", - "en": "Philippine peso", - "nl": "Filipijnse peso", - "de": "Philippinischer Peso", - "it": "peso filippino", - "hu": "F\u00fcl\u00f6p-szigeteki peso", - "es": "peso" - }, - "LRD": { - "fr": "Dollar lib\u00e9rien", - "en": "Liberian dollar", - "nl": "Liberiaanse dollar", - "de": "Liberianischer Dollar", - "it": "Dollaro liberiano", - "hu": "Lib\u00e9riai doll\u00e1r", - "es": "D\u00f3lar liberiano" - }, - "RWF": { - "fr": "franc rwandais", - "en": "Rwandan franc", - "nl": "Rwandese frank", - "de": "Ruanda-Franc", - "it": "Franco ruandese", - "hu": "Ruandai frank", - "es": "franco" - }, - "NOK": { - "fr": "Couronne norv\u00e9gienne", - "en": "Norwegian krone", - "nl": "Noorse kroon", - "de": "Norwegische Krone", - "it": "Corona norvegese", - "hu": "norv\u00e9g korona", - "es": "Corona noruega" - }, - "MOP": { - "fr": "Pataca", - "en": "Macanese pataca", - "nl": "Macause pataca", - "de": "Macao-Pataca", - "it": "Pataca di Macao", - "hu": "Maka\u00f3i pataca", - "es": "Pataca" - }, - "SSP": { - "fr": "Livre sud-soudanaise", - "en": "South Sudanese pound", - "nl": "Zuid-Soedanees pond", - "de": "S\u00fcdsudanesisches Pfund", - "it": "Sterlina sudsudanese", - "hu": "D\u00e9l-szud\u00e1ni font", - "es": "Libra sursudanesa" - }, - "INR": { - "fr": "Roupie indienne", - "en": "Indian rupee", - "nl": "Indiase roepie", - "de": "Indische Rupie", - "it": "rupia indiana", - "hu": "Indiai r\u00fapia", - "es": "Rupia india" - }, - "MXN": { - "fr": "peso mexicain", - "en": "Mexican peso", - "nl": "Mexicaanse peso", - "de": "Mexikanischer Peso", - "it": "Peso messicano", - "hu": "mexik\u00f3i peso", - "es": "peso" - }, - "CZK": { - "fr": "Couronne tch\u00e8que", - "en": "Czech koruna", - "nl": "Tsjechische kroon", - "de": "Tschechische Krone", - "it": "Corona ceca", - "hu": "cseh korona", - "es": "Corona checa" - }, - "TJS": { - "fr": "Somoni", - "en": "Tajikistani somoni", - "nl": "Tadzjiekse somoni", - "de": "Somoni", - "it": "Somoni tagico", - "hu": "t\u00e1dzsik szomoni", - "es": "Somoni tayiko" - }, - "TJR": { - "en": "Tajikistani ruble", - "es": "Rublo tayiko" - }, - "BTN": { - "fr": "ngultrum", - "en": "Bhutanese ngultrum", - "nl": "Bhutaanse ngultrum", - "de": "Ngultrum", - "it": "Ngultrum del Bhutan", - "hu": "bhut\u00e1ni ngultrum", - "es": "Ngultrum butan\u00e9s" - }, - "KMF": { - "fr": "Franc comorien", - "en": "Comorian franc", - "nl": "Comorese frank", - "de": "Komoren-Franc", - "it": "Franco delle Comore", - "hu": "Comore-i frank", - "es": "Franco comorano" - }, - "TMT": { - "fr": "Manat turkm\u00e8ne", - "en": "Turkmenistan manat", - "nl": "Turkmeense manat", - "de": "Turkmenistan-Manat", - "it": "Manat turkmeno", - "hu": "T\u00fcrkm\u00e9n manat", - "es": "Manat turkmeno" - }, - "MUR": { - "fr": "Roupie mauricienne", - "en": "Mauritian rupee", - "nl": "Mauritiaanse roepie", - "de": "Mauritius-Rupie", - "it": "Rupia mauriziana", - "hu": "Mauritiusi r\u00fapia", - "es": "Rupia de Mauricio" - }, - "IDR": { - "fr": "Roupie indon\u00e9sienne", - "en": "Indonesian Rupiah", - "nl": "Indonesische roepia", - "de": "Indonesische Rupiah", - "it": "Rupia indonesiana", - "hu": "indon\u00e9z r\u00fapia", - "es": "Rupia indonesia" - }, - "HNL": { - "fr": "Lempira", - "en": "Honduran lempira", - "nl": "Hondurese lempira", - "de": "Lempira", - "it": "Lempira honduregna", - "hu": "hondurasi lempira", - "es": "lempira" - }, - "ETB": { - "fr": "Birr", - "en": "Ethiopian birr", - "nl": "Ethiopische birr", - "de": "\u00c4thiopischer Birr", - "it": "Birr etiope", - "hu": "eti\u00f3p birr", - "es": "Birr et\u00edope" - }, - "FJD": { - "fr": "dollar de Fidji", - "en": "Fijian dollar", - "nl": "Fiji-dollar", - "de": "Fidschi-Dollar", - "it": "Dollaro delle Figi", - "hu": "Fidzsi doll\u00e1r", - "es": "d\u00f3lar" - }, - "ISK": { - "fr": "Couronne islandaise", - "en": "Icelandic kr\u00f3na", - "nl": "IJslandse kroon", - "de": "Isl\u00e4ndische Krone", - "it": "Corona islandese", - "hu": "izlandi korona", - "es": "corona islandesa" - }, - "PEN": { - "fr": "nouveau sol", - "en": "Peruvian nuevo sol", - "nl": "Peruviaanse sol", - "de": "Nuevo Sol", - "it": "nuevo sol peruviano", - "hu": "perui \u00faj sol", - "es": "nuevo sol" - }, - "MKD": { - "fr": "Dinar mac\u00e9donien", - "en": "Macedonian denar", - "nl": "Macedonische denar", - "de": "Mazedonischer Denar", - "it": "Denaro macedone", - "hu": "maced\u00f3n d\u00e9n\u00e1r", - "es": "Denar macedonio" - }, - "ILS": { - "fr": "Shekel", - "en": "Israeli new shekel", - "nl": "Isra\u00eblische sjekel", - "de": "Schekel", - "it": "nuovo siclo israeliano", - "hu": "izraeli \u00faj s\u00e9kel", - "es": "Nuevo sh\u00e9quel" - }, - "DOP": { - "fr": "Peso dominicain", - "en": "Dominican peso", - "nl": "Dominicaanse peso", - "de": "Dominikanischer Peso", - "it": "Peso dominicano", - "hu": "Dominikai peso", - "es": "peso" - }, - "AZN": { - "fr": "Manat azerba\u00efdjanais", - "en": "Azerbaijani manat", - "nl": "Azerbeidzjaanse manat", - "de": "Aserbaidschan-Manat", - "it": "Manat azero", - "hu": "Azeri manat", - "es": "Manat azerbaiyano" - }, - "MDL": { - "fr": "Leu moldave", - "en": "Moldovan leu", - "nl": "Moldavische leu", - "de": "Moldauischer Leu", - "it": "Leu moldavo", - "hu": "moldov\u00e1n lej", - "es": "Leu moldavo" - }, - "BSD": { - "fr": "Dollar baham\u00e9en", - "en": "Bahamian dollar", - "nl": "Bahamaanse dollar", - "de": "Bahama-Dollar", - "it": "Dollaro delle Bahamas", - "hu": "bahamai doll\u00e1r", - "es": "D\u00f3lar bahame\u00f1o" - }, - "SEK": { - "fr": "Couronne su\u00e9doise", - "en": "Swedish krona", - "nl": "Zweedse kroon", - "de": "Schwedische Krone", - "it": "Corona svedese", - "hu": "Sv\u00e9d korona", - "es": "Corona sueca" - }, - "MVR": { - "fr": "Rufiyaa", - "en": "Maldivian rufiyaa", - "nl": "Maldivische rufiyaa", - "de": "Rufiyaa", - "it": "Rufiyaa delle Maldive", - "hu": "Mald\u00edv-szigeteki r\u00fafia", - "es": "Rupia de Maldivas" - }, - "FRF": { - "fr": "Franc fran\u00e7ais", - "en": "French franc", - "nl": "Franse frank", - "de": "Franz\u00f6sischer Franc", - "it": "Franco francese", - "hu": "Francia frank", - "es": "Franco franc\u00e9s" - }, - "SRD": { - "fr": "Dollar de Surinam", - "en": "Surinamese dollar", - "nl": "Surinaamse dollar", - "de": "Suriname-Dollar", - "it": "Dollaro surinamese", - "hu": "suriname-i doll\u00e1r", - "es": "D\u00f3lar surinam\u00e9s" - }, - "CUP": { - "fr": "peso cubain", - "en": "Cuban peso", - "nl": "Cubaanse peso", - "de": "Kubanischer Peso", - "it": "peso cubano", - "hu": "kubai peso", - "es": "peso" - }, - "BBD": { - "fr": "dollar barbadien", - "en": "Barbadian dollar", - "nl": "Barbadiaanse dollar", - "de": "Barbados-Dollar", - "it": "Dollaro di Barbados", - "hu": "barbadosi doll\u00e1r", - "es": "D\u00f3lar de Barbados" - }, - "KRW": { - "fr": "Won sud-cor\u00e9en", - "en": "South Korean won", - "nl": "Zuid-Koreaanse won", - "de": "S\u00fcdkoreanischer Won", - "it": "Won sudcoreano", - "hu": "D\u00e9l-koreai von", - "es": "W\u014fn surcoreano" - }, - "GMD": { - "fr": "Dalasi", - "en": "Gambian dalasi", - "nl": "Gambiaanse dalasi", - "de": "Dalasi", - "it": "Dalasi gambese", - "hu": "Gambiai dalasi", - "es": "Dalasi" - }, - "VEF": { - "fr": "Bol\u00edvar v\u00e9n\u00e9zu\u00e9lien", - "en": "Venezuelan bol\u00edvar", - "nl": "Venezolaanse bol\u00edvar", - "de": "Venezolanischer Bol\u00edvar", - "it": "Bol\u00edvar venezuelano", - "hu": "venezuelai bol\u00edvar", - "es": "Bol\u00edvar" - }, - "GTQ": { - "fr": "Quetzal", - "en": "Guatemalan quetzal", - "nl": "Guatemalteekse quetzal", - "de": "Guatemaltekischer Quetzal", - "it": "Quetzal guatemalteco", - "hu": "Guatemalai quetzal", - "es": "Quetzal" - }, - "ANG": { - "fr": "Florin des Antilles n\u00e9erlandaises", - "en": "Netherlands Antillean guilder", - "nl": "Antilliaanse gulden", - "de": "Antillen-Gulden", - "it": "Fiorino delle Antille Olandesi", - "hu": "Holland antill\u00e1kbeli forint", - "es": "Flor\u00edn antillano neerland\u00e9s" - }, - "CUC": { - "fr": "Peso cubain convertible", - "en": "Cuban convertible peso", - "nl": "Convertibele peso", - "de": "Peso convertible", - "it": "Peso cubano convertibile", - "hu": "Kubai konvertibilis peso", - "es": "peso convertible" - }, - "CLP": { - "fr": "Peso chilien", - "en": "Chilean peso", - "nl": "Chileense peso", - "de": "Chilenischer Peso", - "it": "Peso cileno", - "hu": "chilei peso", - "es": "peso" - }, - "ZMW": { - "fr": "Kwacha zambien", - "en": "Zambian kwacha", - "nl": "Zambiaanse kwacha", - "de": "Sambischer Kwacha", - "it": "Kwacha zambiano", - "hu": "Zambiai kwacha", - "es": "Kwacha zambiano" - }, - "LTL": { - "fr": "Litas", - "en": "Lithuanian litas", - "nl": "Litouwse litas", - "de": "Litas", - "it": "Litas lituano", - "hu": "litv\u00e1n litas", - "es": "Litas lituana" - }, - "CDF": { - "fr": "Franc congolais", - "en": "Congolese franc", - "nl": "Congolese frank", - "de": "Kongo-Franc", - "it": "Franco congolese", - "hu": "Kong\u00f3i frank", - "es": "franco" - }, - "XCD": { - "fr": "dollar des Cara\u00efbes orientales", - "en": "East Caribbean dollar", - "nl": "Oost-Caribische dollar", - "de": "ostkaribischer Dollar", - "it": "dollaro dei Caraibi Orientali", - "hu": "kelet-karibi doll\u00e1r", - "es": "d\u00f3lar del Caribe Oriental" - }, - "KZT": { - "fr": "Tenge kazakh", - "en": "Kazakhstani tenge", - "nl": "Kazachse tenge", - "de": "Tenge", - "it": "Tenge kazako", - "hu": "kazah tenge", - "es": "Tenge kazajo" - }, - "XPF": { - "fr": "Franc Pacifique", - "en": "CFP Franc", - "nl": "CFP-frank", - "de": "CFP-Franc", - "it": "Franco CFP", - "hu": "Csendes-\u00f3ce\u00e1ni valutak\u00f6z\u00f6ss\u00e9gi frank", - "es": "Franco CFP" - }, - "RUB": { - "fr": "Rouble russe", - "en": "Russian ruble", - "nl": "Russische roebel", - "de": "Russischer Rubel", - "it": "Rublo russo", - "hu": "orosz rubel", - "es": "Rublo ruso" - }, - "XFU": { - "fr": "Franc UIC", - "en": "UIC franc" - }, - "TTD": { - "fr": "Dollar de Trinit\u00e9-et-Tobago", - "en": "Trinidad and Tobago dollar", - "nl": "Trinidad en Tobagodollar", - "de": "Trinidad-und-Tobago-Dollar", - "it": "Dollaro di Trinidad e Tobago", - "hu": "Trinidad \u00e9s Tobag\u00f3-i doll\u00e1r", - "es": "D\u00f3lar trinitense" - }, - "RON": { - "fr": "Leu roumain", - "en": "Romanian leu", - "nl": "Roemeense leu", - "de": "Rum\u00e4nischer Leu", - "it": "Leu romeno", - "hu": "rom\u00e1n lej", - "es": "Leu rumano" - }, - "OMR": { - "fr": "Rial omanais", - "en": "Omani rial", - "nl": "Omaanse rial", - "de": "Omanischer Rial", - "it": "Riyal dell'Oman", - "hu": "Om\u00e1ni ri\u00e1l", - "es": "Rial oman\u00ed" - }, - "BRL": { - "fr": "r\u00e9al br\u00e9silien", - "en": "Brazilian real", - "nl": "Braziliaanse real", - "de": "Brasilianischer Real", - "it": "Real brasiliano", - "hu": "brazil real", - "es": "Real brasile\u00f1o" - }, - "SBD": { - "fr": "dollar des \u00eeles Salomon", - "en": "Solomon Islands dollar", - "nl": "Salomon-dollar", - "de": "Salomonen-Dollar", - "it": "Dollaro delle Salomone", - "hu": "Salamon-szigeteki doll\u00e1r", - "es": "d\u00f3lar de las Islas Salom\u00f3n" - }, - "PYG": { - "fr": "Guaran\u00ed", - "en": "Paraguayan guaran\u00ed", - "nl": "Paraguayaanse guaran\u00ed", - "de": "Paraguayischer Guaran\u00ed", - "it": "Guaran\u00ed paraguaiano", - "hu": "Paraguayi guaran\u00ed", - "es": "Guaran\u00ed" - }, - "KES": { - "fr": "Shilling k\u00e9nyan", - "en": "Kenyan shilling", - "nl": "Keniaanse shilling", - "de": "Kenia-Schilling", - "it": "Scellino keniota", - "hu": "Kenyai shilling", - "es": "Chel\u00edn keniano" - }, - "USD": { - "fr": "dollar am\u00e9ricain", - "en": "United States dollar", - "nl": "Amerikaanse dollar", - "de": "US-Dollar", - "it": "dollaro statunitense", - "hu": "amerikai doll\u00e1r", - "es": "d\u00f3lar" - }, - "TWD": { - "fr": "Nouveau dollar de Ta\u00efwan", - "en": "New Taiwan dollar", - "nl": "Taiwanese dollar", - "de": "Neuer Taiwan-Dollar", - "it": "Dollaro taiwanese", - "hu": "Tajvani \u00faj doll\u00e1r", - "es": "Nuevo d\u00f3lar taiwan\u00e9s" - }, - "TOP": { - "fr": "pa\u2019anga", - "en": "Tongan pa\u02bbanga", - "nl": "Tongaanse pa'anga", - "de": "Pa\u02bbanga", - "it": "Pa'anga tongano", - "hu": "Tongai pa\u02bbanga", - "es": "pa\u02bbanga" - }, - "COP": { - "fr": "Peso colombien", - "en": "peso", - "nl": "Colombiaanse peso", - "de": "Kolumbianischer Peso", - "it": "Peso colombiano", - "hu": "Kolumbiai peso", - "es": "peso" - }, - "GNF": { - "fr": "Franc guin\u00e9en", - "en": "Guinean franc", - "nl": "Guineese frank", - "de": "Franc Guin\u00e9en", - "it": "Franco guineano", - "hu": "Guineai frank", - "es": "Franco guineano" - }, - "WST": { - "fr": "Tala", - "en": "Samoan t\u0101l\u0101", - "nl": "Samoaanse tala", - "de": "Samoanischer Tala", - "it": "Tala samoano", - "hu": "Szamoai tala", - "es": "tala" - }, - "IQD": { - "fr": "Dinar irakien", - "en": "Iraqi dinar", - "nl": "Iraakse dinar", - "de": "Irakischer Dinar", - "it": "Dinaro iracheno", - "hu": "iraki din\u00e1r", - "es": "Dinar iraqu\u00ed" - }, - "ERN": { - "fr": "Nakfa \u00e9rythr\u00e9en", - "en": "Eritrean nakfa", - "nl": "Eritrese nakfa", - "de": "Eritreischer Nakfa", - "it": "Nacfa eritreo", - "hu": "Eritreai nakfa", - "es": "Nakfa" - }, - "CVE": { - "fr": "Escudo cap-verdien", - "en": "Cape Verdean escudo", - "nl": "Kaapverdische escudo", - "de": "Kap-Verde-Escudo", - "it": "Escudo capoverdiano", - "hu": "Z\u00f6ld-foki k\u00f6zt\u00e1rsas\u00e1gi escudo", - "es": "escudo" - }, - "AUD": { - "fr": "dollar australien", - "en": "Australian dollar", - "nl": "Australische dollar", - "de": "Australischer Dollar", - "it": "Dollaro australiano", - "hu": "Ausztr\u00e1l doll\u00e1r", - "es": "D\u00f3lar australiano" - }, - "BAM": { - "fr": "Mark convertible de Bosnie-Herz\u00e9govine", - "en": "Bosnia and Herzegovina convertible mark", - "nl": "Bosnische inwisselbare mark", - "de": "Konvertible Mark", - "it": "Marco bosniaco", - "hu": "bosny\u00e1k konvertibilis m\u00e1rka", - "es": "Marco bosnioherzegovino" - }, - "KWD": { - "fr": "Dinar kowe\u00eftien", - "en": "Kuwaiti dinar", - "nl": "Koeweitse dinar", - "de": "Kuwait-Dinar", - "it": "Dinaro kuwaitiano", - "hu": "kuvaiti din\u00e1r", - "es": "Dinar kuwait\u00ed" - }, - "BIF": { - "fr": "Franc burundais", - "en": "Burundian franc", - "nl": "Burundese frank", - "de": "Burundi-Franc", - "it": "Franco del Burundi", - "hu": "Burundi frank", - "es": "Franco de Burundi" - }, - "PGK": { - "fr": "Kina", - "en": "Papua New Guinean kina", - "nl": "Papoea-Nieuw-Guinese kina", - "de": "Kina", - "it": "Kina papuana", - "hu": "P\u00e1pua \u00faj-guineai kina", - "es": "Kina" - }, - "SOS": { - "fr": "shilling somalien", - "en": "Somali shilling", - "nl": "Somalische shilling", - "de": "Somalia-Schilling", - "it": "Scellino somalo", - "hu": "Szom\u00e1liai shilling", - "es": "chel\u00edn" - }, - "CAD": { - "fr": "Dollar canadien", - "en": "Canadian dollar", - "nl": "Canadese dollar", - "de": "Kanadischer Dollar", - "it": "Dollaro canadese", - "hu": "kanadai doll\u00e1r", - "es": "D\u00f3lar canadiense" - }, - "SGD": { - "fr": "Dollar de Singapour", - "en": "Singapore dollar", - "nl": "Singaporese dollar", - "de": "Singapur-Dollar", - "it": "Dollaro di Singapore", - "hu": "szingap\u00fari doll\u00e1r", - "es": "D\u00f3lar de Singapur" - }, - "UZS": { - "fr": "Sum", - "en": "Uzbekistani som", - "nl": "Oezbeekse sum", - "de": "So\u02bbm", - "it": "Som uzbeco", - "hu": "\u00dczb\u00e9g szom", - "es": "som" - }, - "STD": { - "fr": "Dobra", - "en": "S\u00e3o Tom\u00e9 and Pr\u00edncipe dobra", - "nl": "Santomese dobra", - "de": "S\u00e3o-tom\u00e9ischer Dobra", - "it": "Dobra di S\u00e3o Tom\u00e9 e Pr\u00edncipe", - "hu": "S\u00e3o Tom\u00e9 \u00e9s Pr\u00edncipe-i dobra", - "es": "Dobra santotomense" - }, - "XFO": { - "fr": "Franc-or", - "en": "Gold franc", - "de": "Goldfranken" - }, - "IRR": { - "fr": "Rial iranien", - "en": "Iranian rial", - "nl": "Iraanse rial", - "de": "Iranischer Rial", - "it": "Riyal iraniano", - "hu": "ir\u00e1ni ri\u00e1l", - "es": "Rial iran\u00ed" - }, - "CNY": { - "fr": "Yuan", - "en": "renminbi", - "nl": "Chinese renminbi", - "de": "Renminbi", - "it": "Renminbi cinese", - "hu": "Renminbi", - "es": "Yuan chino" - }, - "SLL": { - "fr": "leone", - "en": "Sierra Leonean leone", - "nl": "Sierra Leoonse leone", - "de": "Sierra-leonischer Leone", - "it": "Leone sierraleonese", - "hu": "Sierra Leone-i leone", - "es": "leone" - }, - "TND": { - "fr": "Dinar tunisien", - "en": "Tunisian dinar", - "nl": "Tunesische dinar", - "de": "Tunesischer Dinar", - "it": "Dinaro tunisino", - "hu": "Tun\u00e9ziai din\u00e1r", - "es": "dinar" - }, - "GYD": { - "fr": "Dollar guyanien", - "en": "Guyanese dollar", - "nl": "Guyaanse dollar", - "de": "Guyana-Dollar", - "it": "Dollaro della Guyana", - "hu": "Guyanai doll\u00e1r", - "es": "D\u00f3lar guyan\u00e9s" - }, - "MTL": { - "fr": "Lire maltaise", - "en": "Maltese lira", - "nl": "Maltese lire", - "de": "Maltesische Lira", - "it": "Lira maltese", - "hu": "M\u00e1ltai l\u00edra", - "es": "Lira maltesa" - }, - "NZD": { - "fr": "dollar n\u00e9o-z\u00e9landais", - "en": "New Zealand dollar", - "nl": "Nieuw-Zeelandse dollar", - "de": "Neuseeland-Dollar", - "it": "Dollaro neozelandese", - "hu": "\u00faj-z\u00e9landi doll\u00e1r", - "es": "D\u00f3lar neozeland\u00e9s" - }, - "FKP": { - "fr": "Livre des \u00celes Malouines", - "en": "Falkland Islands pound", - "nl": "Falklandeilands pond", - "de": "Falkland-Pfund", - "it": "Sterlina delle Falkland", - "hu": "Falkland-szigeteki font", - "es": "Libra malvinense" - }, - "LVL": { - "fr": "Lats", - "en": "lats", - "nl": "Letse lats", - "de": "Lats", - "it": "Lats lettone", - "hu": "lett lat", - "es": "Lats let\u00f3n" - }, - "ARP": { - "fr": "peso argentino", - "en": "peso argentino", - "nl": "peso argentino", - "it": "peso argentino", - "es": "peso argentino" - }, - "KGS": { - "fr": "Som", - "en": "Kyrgyzstani som", - "nl": "Kirgizische som", - "de": "Som", - "it": "som kirghizo", - "hu": "kirgiz szom", - "es": "Som kirgu\u00eds" - }, - "ARS": { - "fr": "peso argentin", - "en": "peso", - "nl": "Argentijnse peso", - "de": "Argentinischer Peso", - "it": "peso argentino", - "hu": "argentin peso", - "es": "peso" - }, - "BMD": { - "fr": "Dollar bermudien", - "en": "Bermudian dollar", - "nl": "Bermuda-dollar", - "de": "Bermuda-Dollar", - "it": "Dollaro della Bermuda", - "hu": "bermudai doll\u00e1r", - "es": "D\u00f3lar bermude\u00f1o" - }, - "RSD": { - "fr": "Dinar serbe", - "en": "Serbian dinar", - "nl": "Servische dinar", - "de": "Serbischer Dinar", - "it": "Dinaro serbo", - "hu": "szerb din\u00e1r", - "es": "Dinar serbio" - }, - "BHD": { - "fr": "Dinar bahre\u00efnien", - "en": "Bahraini dinar", - "nl": "Bahreinse dinar", - "de": "Bahrain-Dinar", - "it": "Dinaro del Bahrain", - "hu": "bahreini din\u00e1r", - "es": "Dinar barein\u00ed" - }, - "JPY": { - "fr": "Yen", - "en": "Japanese yen", - "nl": "Japanse yen", - "de": "Yen", - "it": "Yen giapponese", - "hu": "Jap\u00e1n jen", - "es": "yen" - }, - "ARA": { - "fr": "Austral (monnaie)", - "en": "Argentine austral", - "de": "Austral (W\u00e4hrung)", - "it": "Austral argentino", - "es": "Austral" - }, - "SDG": { - "fr": "Livre soudanaise", - "en": "Sudanese pound", - "nl": "Soedanees pond", - "de": "Sudanesisches Pfund", - "it": "Sterlina sudanese", - "hu": "Szud\u00e1ni font", - "es": "Libra sudanesa" - } - } -} \ No newline at end of file diff --git a/sources/searx/engines/__init__.py b/sources/searx/engines/__init__.py deleted file mode 100644 index 6d50667..0000000 --- a/sources/searx/engines/__init__.py +++ /dev/null @@ -1,202 +0,0 @@ - -''' -searx is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -searx 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 Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with searx. If not, see < http://www.gnu.org/licenses/ >. - -(C) 2013- by Adam Tauber, -''' - -from os.path import realpath, dirname, splitext, join -import sys -from imp import load_source -from flask.ext.babel import gettext -from operator import itemgetter -from searx import settings -from searx import logger - - -logger = logger.getChild('engines') - -engine_dir = dirname(realpath(__file__)) - -engines = {} - -categories = {'general': []} - -engine_shortcuts = {} -engine_default_args = {'paging': False, - 'categories': ['general'], - 'language_support': True, - 'safesearch': False, - 'timeout': settings['outgoing']['request_timeout'], - 'shortcut': '-', - 'disabled': False, - 'suspend_end_time': 0, - 'continuous_errors': 0} - - -def load_module(filename): - modname = splitext(filename)[0] - if modname in sys.modules: - del sys.modules[modname] - filepath = join(engine_dir, filename) - module = load_source(modname, filepath) - module.name = modname - return module - - -def load_engine(engine_data): - engine_name = engine_data['engine'] - engine = load_module(engine_name + '.py') - - for param_name in engine_data: - if param_name == 'engine': - continue - if param_name == 'categories': - if engine_data['categories'] == 'none': - engine.categories = [] - else: - engine.categories = map( - str.strip, engine_data['categories'].split(',')) - continue - setattr(engine, param_name, engine_data[param_name]) - - for arg_name, arg_value in engine_default_args.iteritems(): - if not hasattr(engine, arg_name): - setattr(engine, arg_name, arg_value) - - # checking required variables - for engine_attr in dir(engine): - if engine_attr.startswith('_'): - continue - if getattr(engine, engine_attr) is None: - logger.error('Missing engine config attribute: "{0}.{1}"' - .format(engine.name, engine_attr)) - sys.exit(1) - - engine.stats = { - 'result_count': 0, - 'search_count': 0, - 'page_load_time': 0, - 'score_count': 0, - 'errors': 0 - } - - for category_name in engine.categories: - categories.setdefault(category_name, []).append(engine) - - if engine.shortcut in engine_shortcuts: - logger.error('Engine config error: ambigious shortcut: {0}'.format(engine.shortcut)) - sys.exit(1) - - engine_shortcuts[engine.shortcut] = engine.name - - return engine - - -def get_engines_stats(): - # TODO refactor - pageloads = [] - results = [] - scores = [] - errors = [] - scores_per_result = [] - - max_pageload = max_results = max_score = max_errors = max_score_per_result = 0 # noqa - for engine in engines.values(): - if engine.stats['search_count'] == 0: - continue - results_num = \ - engine.stats['result_count'] / float(engine.stats['search_count']) - load_times = engine.stats['page_load_time'] / float(engine.stats['search_count']) # noqa - if results_num: - score = engine.stats['score_count'] / float(engine.stats['search_count']) # noqa - score_per_result = score / results_num - else: - score = score_per_result = 0.0 - max_results = max(results_num, max_results) - max_pageload = max(load_times, max_pageload) - max_score = max(score, max_score) - max_score_per_result = max(score_per_result, max_score_per_result) - max_errors = max(max_errors, engine.stats['errors']) - pageloads.append({'avg': load_times, 'name': engine.name}) - results.append({'avg': results_num, 'name': engine.name}) - scores.append({'avg': score, 'name': engine.name}) - errors.append({'avg': engine.stats['errors'], 'name': engine.name}) - scores_per_result.append({ - 'avg': score_per_result, - 'name': engine.name - }) - - for engine in pageloads: - if max_pageload: - engine['percentage'] = int(engine['avg'] / max_pageload * 100) - else: - engine['percentage'] = 0 - - for engine in results: - if max_results: - engine['percentage'] = int(engine['avg'] / max_results * 100) - else: - engine['percentage'] = 0 - - for engine in scores: - if max_score: - engine['percentage'] = int(engine['avg'] / max_score * 100) - else: - engine['percentage'] = 0 - - for engine in scores_per_result: - if max_score_per_result: - engine['percentage'] = int(engine['avg'] - / max_score_per_result * 100) - else: - engine['percentage'] = 0 - - for engine in errors: - if max_errors: - engine['percentage'] = int(float(engine['avg']) / max_errors * 100) - else: - engine['percentage'] = 0 - - return [ - ( - gettext('Page loads (sec)'), - sorted(pageloads, key=itemgetter('avg')) - ), - ( - gettext('Number of results'), - sorted(results, key=itemgetter('avg'), reverse=True) - ), - ( - gettext('Scores'), - sorted(scores, key=itemgetter('avg'), reverse=True) - ), - ( - gettext('Scores per result'), - sorted(scores_per_result, key=itemgetter('avg'), reverse=True) - ), - ( - gettext('Errors'), - sorted(errors, key=itemgetter('avg'), reverse=True) - ), - ] - - -if 'engines' not in settings or not settings['engines']: - logger.error('No engines found. Edit your settings.yml') - exit(2) - -for engine_data in settings['engines']: - engine = load_engine(engine_data) - engines[engine.name] = engine diff --git a/sources/searx/engines/archlinux.py b/sources/searx/engines/archlinux.py deleted file mode 100644 index 84e0d0f..0000000 --- a/sources/searx/engines/archlinux.py +++ /dev/null @@ -1,141 +0,0 @@ -# -*- coding: utf-8 -*- - -""" - Arch Linux Wiki - - @website https://wiki.archlinux.org - @provide-api no (Mediawiki provides API, but Arch Wiki blocks access to it - @using-api no - @results HTML - @stable no (HTML can change) - @parse url, title -""" - -from urlparse import urljoin -from cgi import escape -from urllib import urlencode -from lxml import html -from searx.engines.xpath import extract_text - -# engine dependent config -categories = ['it'] -language_support = True -paging = True -base_url = 'https://wiki.archlinux.org' - -# xpath queries -xpath_results = '//ul[@class="mw-search-results"]/li' -xpath_link = './/div[@class="mw-search-result-heading"]/a' - - -# cut 'en' from 'en_US', 'de' from 'de_CH', and so on -def locale_to_lang_code(locale): - if locale.find('_') >= 0: - locale = locale.split('_')[0] - return locale - -# wikis for some languages were moved off from the main site, we need to make -# requests to correct URLs to be able to get results in those languages -lang_urls = { - 'all': { - 'base': 'https://wiki.archlinux.org', - 'search': '/index.php?title=Special:Search&offset={offset}&{query}' - }, - 'de': { - 'base': 'https://wiki.archlinux.de', - 'search': '/index.php?title=Spezial:Suche&offset={offset}&{query}' - }, - 'fr': { - 'base': 'https://wiki.archlinux.fr', - 'search': '/index.php?title=Spécial:Recherche&offset={offset}&{query}' - }, - 'ja': { - 'base': 'https://wiki.archlinuxjp.org', - 'search': '/index.php?title=特別:検索&offset={offset}&{query}' - }, - 'ro': { - 'base': 'http://wiki.archlinux.ro', - 'search': '/index.php?title=Special:Căutare&offset={offset}&{query}' - }, - 'tr': { - 'base': 'http://archtr.org/wiki', - 'search': '/index.php?title=Özel:Ara&offset={offset}&{query}' - } -} - - -# get base & search URLs for selected language -def get_lang_urls(language): - if language in lang_urls: - return lang_urls[language] - return lang_urls['all'] - -# Language names to build search requests for -# those languages which are hosted on the main site. -main_langs = { - 'ar': 'العربية', - 'bg': 'Български', - 'cs': 'Česky', - 'da': 'Dansk', - 'el': 'Ελληνικά', - 'es': 'Español', - 'he': 'עברית', - 'hr': 'Hrvatski', - 'hu': 'Magyar', - 'it': 'Italiano', - 'ko': '한국어', - 'lt': 'Lietuviškai', - 'nl': 'Nederlands', - 'pl': 'Polski', - 'pt': 'Português', - 'ru': 'Русский', - 'sl': 'Slovenský', - 'th': 'ไทย', - 'uk': 'Українська', - 'zh': '简体中文' -} - - -# do search-request -def request(query, params): - # translate the locale (e.g. 'en_US') to language code ('en') - language = locale_to_lang_code(params['language']) - - # if our language is hosted on the main site, we need to add its name - # to the query in order to narrow the results to that language - if language in main_langs: - query += '(' + main_langs[language] + ')' - - # prepare the request parameters - query = urlencode({'search': query}) - offset = (params['pageno'] - 1) * 20 - - # get request URLs for our language of choice - urls = get_lang_urls(language) - search_url = urls['base'] + urls['search'] - - params['url'] = search_url.format(query=query, offset=offset) - - return params - - -# get response from search-request -def response(resp): - # get the base URL for the language in which request was made - language = locale_to_lang_code(resp.search_params['language']) - base_url = get_lang_urls(language)['base'] - - results = [] - - dom = html.fromstring(resp.text) - - # parse results - for result in dom.xpath(xpath_results): - link = result.xpath(xpath_link)[0] - href = urljoin(base_url, link.attrib.get('href')) - title = escape(extract_text(link)) - - results.append({'url': href, - 'title': title}) - - return results diff --git a/sources/searx/engines/base.py b/sources/searx/engines/base.py deleted file mode 100755 index 66491d3..0000000 --- a/sources/searx/engines/base.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python - -""" - BASE (Scholar publications) - - @website https://base-search.net - @provide-api yes with authorization (https://api.base-search.net/) - - @using-api yes - @results XML - @stable ? - @parse url, title, publishedDate, content - More info on api: http://base-search.net/about/download/base_interface.pdf -""" - -from lxml import etree -from urllib import urlencode -from searx.utils import searx_useragent -from cgi import escape -from datetime import datetime -import re - - -categories = ['science'] - -base_url = 'https://api.base-search.net/cgi-bin/BaseHttpSearchInterface.fcgi'\ - + '?func=PerformSearch&{query}&boost=oa&hits={hits}&offset={offset}' - -# engine dependent config -paging = True -number_of_results = 10 - -# shortcuts for advanced search -shorcut_dict = { - # user-friendly keywords - 'format:': 'dcformat:', - 'author:': 'dccreator:', - 'collection:': 'dccollection:', - 'hdate:': 'dchdate:', - 'contributor:': 'dccontributor:', - 'coverage:': 'dccoverage:', - 'date:': 'dcdate:', - 'abstract:': 'dcdescription:', - 'urls:': 'dcidentifier:', - 'language:': 'dclanguage:', - 'publisher:': 'dcpublisher:', - 'relation:': 'dcrelation:', - 'rights:': 'dcrights:', - 'source:': 'dcsource:', - 'subject:': 'dcsubject:', - 'title:': 'dctitle:', - 'type:': 'dcdctype:' -} - - -def request(query, params): - # replace shortcuts with API advanced search keywords - for key in shorcut_dict.keys(): - query = re.sub(str(key), str(shorcut_dict[key]), query) - - # basic search - offset = (params['pageno'] - 1) * number_of_results - - string_args = dict(query=urlencode({'query': query}), - offset=offset, - hits=number_of_results) - - params['url'] = base_url.format(**string_args) - - params['headers']['User-Agent'] = searx_useragent() - return params - - -def response(resp): - results = [] - - search_results = etree.XML(resp.content) - - for entry in search_results.xpath('./result/doc'): - content = "No description available" - - date = datetime.now() # needed in case no dcdate is available for an item - for item in entry: - if item.attrib["name"] == "dchdate": - harvestDate = item.text - - elif item.attrib["name"] == "dcdate": - date = item.text - - elif item.attrib["name"] == "dctitle": - title = item.text - - elif item.attrib["name"] == "dclink": - url = item.text - - elif item.attrib["name"] == "dcdescription": - content = escape(item.text[:300]) - if len(item.text) > 300: - content += "..." - -# dates returned by the BASE API are not several formats - publishedDate = None - for date_format in ['%Y-%m-%dT%H:%M:%SZ', '%Y-%m-%d', '%Y-%m', '%Y']: - try: - publishedDate = datetime.strptime(date, date_format) - break - except: - pass - - if publishedDate is not None: - res_dict = {'url': url, - 'title': title, - 'publishedDate': publishedDate, - 'content': content} - else: - res_dict = {'url': url, - 'title': title, - 'content': content} - - results.append(res_dict) - - return results diff --git a/sources/searx/engines/bing.py b/sources/searx/engines/bing.py deleted file mode 100644 index 6bdfd37..0000000 --- a/sources/searx/engines/bing.py +++ /dev/null @@ -1,88 +0,0 @@ -""" - Bing (Web) - - @website https://www.bing.com - @provide-api yes (http://datamarket.azure.com/dataset/bing/search), - max. 5000 query/month - - @using-api no (because of query limit) - @results HTML (using search portal) - @stable no (HTML can change) - @parse url, title, content - - @todo publishedDate -""" - -from urllib import urlencode -from cgi import escape -from lxml import html -from searx.engines.xpath import extract_text - -# engine dependent config -categories = ['general'] -paging = True -language_support = True - -# search-url -base_url = 'https://www.bing.com/' -search_string = 'search?{query}&first={offset}' - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 10 + 1 - - if params['language'] == 'all': - language = 'en-US' - else: - language = params['language'].replace('_', '-') - - search_path = search_string.format( - query=urlencode({'q': query, 'setmkt': language}), - offset=offset) - - params['cookies']['SRCHHPGUSR'] = \ - 'NEWWND=0&NRSLT=-1&SRCHLANG=' + language.split('-')[0] - - params['url'] = base_url + search_path - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - - try: - results.append({'number_of_results': int(dom.xpath('//span[@class="sb_count"]/text()')[0] - .split()[0].replace(',', ''))}) - except: - pass - - # parse results - for result in dom.xpath('//div[@class="sa_cc"]'): - link = result.xpath('.//h3/a')[0] - url = link.attrib.get('href') - title = extract_text(link) - content = escape(extract_text(result.xpath('.//p'))) - - # append result - results.append({'url': url, - 'title': title, - 'content': content}) - - # parse results again if nothing is found yet - for result in dom.xpath('//li[@class="b_algo"]'): - link = result.xpath('.//h2/a')[0] - url = link.attrib.get('href') - title = extract_text(link) - content = escape(extract_text(result.xpath('.//p'))) - - # append result - results.append({'url': url, - 'title': title, - 'content': content}) - - # return results - return results diff --git a/sources/searx/engines/bing_images.py b/sources/searx/engines/bing_images.py deleted file mode 100644 index 3845203..0000000 --- a/sources/searx/engines/bing_images.py +++ /dev/null @@ -1,98 +0,0 @@ -""" - Bing (Images) - - @website https://www.bing.com/images - @provide-api yes (http://datamarket.azure.com/dataset/bing/search), - max. 5000 query/month - - @using-api no (because of query limit) - @results HTML (using search portal) - @stable no (HTML can change) - @parse url, title, img_src - - @todo currently there are up to 35 images receive per page, - because bing does not parse count=10. - limited response to 10 images -""" - -from urllib import urlencode -from lxml import html -from json import loads -import re - -# engine dependent config -categories = ['images'] -paging = True -safesearch = True - -# search-url -base_url = 'https://www.bing.com/' -search_string = 'images/search?{query}&count=10&first={offset}' -thumb_url = "https://www.bing.com/th?id={ihk}" - -# safesearch definitions -safesearch_types = {2: 'STRICT', - 1: 'DEMOTE', - 0: 'OFF'} - - -_quote_keys_regex = re.compile('({|,)([a-z][a-z0-9]*):(")', re.I | re.U) - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 10 + 1 - - # required for cookie - if params['language'] == 'all': - language = 'en-US' - else: - language = params['language'].replace('_', '-') - - search_path = search_string.format( - query=urlencode({'q': query}), - offset=offset) - - params['cookies']['SRCHHPGUSR'] = \ - 'NEWWND=0&NRSLT=-1&SRCHLANG=' + language.split('-')[0] +\ - '&ADLT=' + safesearch_types.get(params['safesearch'], 'DEMOTE') - - params['url'] = base_url + search_path - - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - - # parse results - for result in dom.xpath('//div[@class="dg_u"]/div'): - link = result.xpath('./a')[0] - - # parse json-data (it is required to add a space, to make it parsable) - json_data = loads(_quote_keys_regex.sub(r'\1"\2": \3', link.attrib.get('m'))) - - title = link.attrib.get('t1') - ihk = link.attrib.get('ihk') - - # url = 'http://' + link.attrib.get('t3') - url = json_data.get('surl') - img_src = json_data.get('imgurl') - - # append result - results.append({'template': 'images.html', - 'url': url, - 'title': title, - 'content': '', - 'thumbnail_src': thumb_url.format(ihk=ihk), - 'img_src': img_src}) - - # TODO stop parsing if 10 images are found - if len(results) >= 10: - break - - # return results - return results diff --git a/sources/searx/engines/bing_news.py b/sources/searx/engines/bing_news.py deleted file mode 100644 index a2397c4..0000000 --- a/sources/searx/engines/bing_news.py +++ /dev/null @@ -1,111 +0,0 @@ -""" - Bing (News) - - @website https://www.bing.com/news - @provide-api yes (http://datamarket.azure.com/dataset/bing/search), - max. 5000 query/month - - @using-api no (because of query limit) - @results RSS (using search portal) - @stable yes (except perhaps for the images) - @parse url, title, content, publishedDate, thumbnail -""" - -from urllib import urlencode -from urlparse import urlparse, parse_qsl -from datetime import datetime -from dateutil import parser -from lxml import etree -from searx.utils import list_get - -# engine dependent config -categories = ['news'] -paging = True -language_support = True - -# search-url -base_url = 'https://www.bing.com/' -search_string = 'news/search?{query}&first={offset}&format=RSS' - - -# remove click -def url_cleanup(url_string): - parsed_url = urlparse(url_string) - if parsed_url.netloc == 'www.bing.com' and parsed_url.path == '/news/apiclick.aspx': - query = dict(parse_qsl(parsed_url.query)) - return query.get('url', None) - return url_string - - -# replace the http://*bing4.com/th?id=... by https://www.bing.com/th?id=... -def image_url_cleanup(url_string): - parsed_url = urlparse(url_string) - if parsed_url.netloc.endswith('bing4.com') and parsed_url.path == '/th': - query = dict(parse_qsl(parsed_url.query)) - return "https://www.bing.com/th?id=" + query.get('id') - return url_string - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 10 + 1 - - if params['language'] == 'all': - language = 'en-US' - else: - language = params['language'].replace('_', '-') - - search_path = search_string.format( - query=urlencode({'q': query, 'setmkt': language}), - offset=offset) - - params['url'] = base_url + search_path - - return params - - -# get response from search-request -def response(resp): - results = [] - - rss = etree.fromstring(resp.content) - - ns = rss.nsmap - - # parse results - for item in rss.xpath('./channel/item'): - # url / title / content - url = url_cleanup(item.xpath('./link/text()')[0]) - title = list_get(item.xpath('./title/text()'), 0, url) - content = list_get(item.xpath('./description/text()'), 0, '') - - # publishedDate - publishedDate = list_get(item.xpath('./pubDate/text()'), 0) - try: - publishedDate = parser.parse(publishedDate, dayfirst=False) - except TypeError: - publishedDate = datetime.now() - except ValueError: - publishedDate = datetime.now() - - # thumbnail - thumbnail = list_get(item.xpath('./News:Image/text()', namespaces=ns), 0) - if thumbnail is not None: - thumbnail = image_url_cleanup(thumbnail) - - # append result - if thumbnail is not None: - results.append({'template': 'videos.html', - 'url': url, - 'title': title, - 'publishedDate': publishedDate, - 'content': content, - 'thumbnail': thumbnail}) - else: - results.append({'url': url, - 'title': title, - 'publishedDate': publishedDate, - 'content': content}) - - # return results - return results diff --git a/sources/searx/engines/blekko_images.py b/sources/searx/engines/blekko_images.py deleted file mode 100644 index c0664f3..0000000 --- a/sources/searx/engines/blekko_images.py +++ /dev/null @@ -1,70 +0,0 @@ -""" - Blekko (Images) - - @website https://blekko.com - @provide-api yes (inofficial) - - @using-api yes - @results JSON - @stable yes - @parse url, title, img_src -""" - -from json import loads -from urllib import urlencode - -# engine dependent config -categories = ['images'] -paging = True -safesearch = True - -# search-url -base_url = 'https://blekko.com' -search_url = '/api/images?{query}&c={c}' - -# safesearch definitions -safesearch_types = {2: '1', - 1: '', - 0: '0'} - - -# do search-request -def request(query, params): - c = (params['pageno'] - 1) * 48 - - params['url'] = base_url +\ - search_url.format(query=urlencode({'q': query}), - c=c) - - if params['pageno'] != 1: - params['url'] += '&page={pageno}'.format(pageno=(params['pageno'] - 1)) - - # let Blekko know we wan't have profiling - params['cookies']['tag_lesslogging'] = '1' - - # parse safesearch argument - params['cookies']['safesearch'] = safesearch_types.get(params['safesearch'], '') - - return params - - -# get response from search-request -def response(resp): - results = [] - - search_results = loads(resp.text) - - # return empty array if there are no results - if not search_results: - return [] - - for result in search_results: - # append result - results.append({'url': result['page_url'], - 'title': result['title'], - 'content': '', - 'img_src': result['url'], - 'template': 'images.html'}) - - # return results - return results diff --git a/sources/searx/engines/btdigg.py b/sources/searx/engines/btdigg.py deleted file mode 100644 index c2b22f0..0000000 --- a/sources/searx/engines/btdigg.py +++ /dev/null @@ -1,106 +0,0 @@ -""" - BTDigg (Videos, Music, Files) - - @website https://btdigg.org - @provide-api yes (on demand) - - @using-api no - @results HTML (using search portal) - @stable no (HTML can change) - @parse url, title, content, seed, leech, magnetlink -""" - -from urlparse import urljoin -from cgi import escape -from urllib import quote -from lxml import html -from operator import itemgetter -from searx.engines.xpath import extract_text - -# engine dependent config -categories = ['videos', 'music', 'files'] -paging = True - -# search-url -url = 'https://btdigg.org' -search_url = url + '/search?q={search_term}&p={pageno}' - - -# do search-request -def request(query, params): - params['url'] = search_url.format(search_term=quote(query), - pageno=params['pageno'] - 1) - - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.content) - - search_res = dom.xpath('//div[@id="search_res"]/table/tr') - - # return empty array if nothing is found - if not search_res: - return [] - - # parse results - for result in search_res: - link = result.xpath('.//td[@class="torrent_name"]//a')[0] - href = urljoin(url, link.attrib.get('href')) - title = escape(extract_text(link)) - content = escape(extract_text(result.xpath('.//pre[@class="snippet"]')[0])) - content = "
".join(content.split("\n")) - - filesize = result.xpath('.//span[@class="attr_val"]/text()')[0].split()[0] - filesize_multiplier = result.xpath('.//span[@class="attr_val"]/text()')[0].split()[1] - files = result.xpath('.//span[@class="attr_val"]/text()')[1] - seed = result.xpath('.//span[@class="attr_val"]/text()')[2] - - # convert seed to int if possible - if seed.isdigit(): - seed = int(seed) - else: - seed = 0 - - leech = 0 - - # convert filesize to byte if possible - try: - filesize = float(filesize) - - # convert filesize to byte - if filesize_multiplier == 'TB': - filesize = int(filesize * 1024 * 1024 * 1024 * 1024) - elif filesize_multiplier == 'GB': - filesize = int(filesize * 1024 * 1024 * 1024) - elif filesize_multiplier == 'MB': - filesize = int(filesize * 1024 * 1024) - elif filesize_multiplier == 'KB': - filesize = int(filesize * 1024) - except: - filesize = None - - # convert files to int if possible - if files.isdigit(): - files = int(files) - else: - files = None - - magnetlink = result.xpath('.//td[@class="ttth"]//a')[0].attrib['href'] - - # append result - results.append({'url': href, - 'title': title, - 'content': content, - 'seed': seed, - 'leech': leech, - 'filesize': filesize, - 'files': files, - 'magnetlink': magnetlink, - 'template': 'torrent.html'}) - - # return results sorted by seeder - return sorted(results, key=itemgetter('seed'), reverse=True) diff --git a/sources/searx/engines/currency_convert.py b/sources/searx/engines/currency_convert.py deleted file mode 100644 index b0ffb49..0000000 --- a/sources/searx/engines/currency_convert.py +++ /dev/null @@ -1,101 +0,0 @@ -from datetime import datetime -import re -import os -import json -import unicodedata - - -categories = [] -url = 'https://download.finance.yahoo.com/d/quotes.csv?e=.csv&f=sl1d1t1&s={query}=X' -weight = 100 - -parser_re = re.compile(u'.*?(\d+(?:\.\d+)?) ([^.0-9]+) (?:in|to) ([^.0-9]+)', re.I) # noqa - -db = 1 - - -def normalize_name(name): - name = name.lower().replace('-', ' ').rstrip('s') - name = re.sub(' +', ' ', name) - return unicodedata.normalize('NFKD', name).lower() - - -def name_to_iso4217(name): - global db - - name = normalize_name(name) - currencies = db['names'].get(name, [name]) - return currencies[0] - - -def iso4217_to_name(iso4217, language): - global db - - return db['iso4217'].get(iso4217, {}).get(language, iso4217) - - -def request(query, params): - m = parser_re.match(unicode(query, 'utf8')) - if not m: - # wrong query - return params - - ammount, from_currency, to_currency = m.groups() - ammount = float(ammount) - from_currency = name_to_iso4217(from_currency.strip()) - to_currency = name_to_iso4217(to_currency.strip()) - - q = (from_currency + to_currency).upper() - - params['url'] = url.format(query=q) - params['ammount'] = ammount - params['from'] = from_currency - params['to'] = to_currency - params['from_name'] = iso4217_to_name(from_currency, 'en') - params['to_name'] = iso4217_to_name(to_currency, 'en') - - return params - - -def response(resp): - results = [] - try: - _, conversion_rate, _ = resp.text.split(',', 2) - conversion_rate = float(conversion_rate) - except: - return results - - answer = '{0} {1} = {2} {3}, 1 {1} ({5}) = {4} {3} ({6})'.format( - resp.search_params['ammount'], - resp.search_params['from'], - resp.search_params['ammount'] * conversion_rate, - resp.search_params['to'], - conversion_rate, - resp.search_params['from_name'], - resp.search_params['to_name'], - ) - - now_date = datetime.now().strftime('%Y%m%d') - url = 'https://finance.yahoo.com/currency/converter-results/{0}/{1}-{2}-to-{3}.html' # noqa - url = url.format( - now_date, - resp.search_params['ammount'], - resp.search_params['from'].lower(), - resp.search_params['to'].lower() - ) - - results.append({'answer': answer, 'url': url}) - - return results - - -def load(): - global db - - current_dir = os.path.dirname(os.path.realpath(__file__)) - json_data = open(current_dir + "/../data/currencies.json").read() - - db = json.loads(json_data) - - -load() diff --git a/sources/searx/engines/dailymotion.py b/sources/searx/engines/dailymotion.py deleted file mode 100644 index 4eb8947..0000000 --- a/sources/searx/engines/dailymotion.py +++ /dev/null @@ -1,77 +0,0 @@ -""" - Dailymotion (Videos) - - @website https://www.dailymotion.com - @provide-api yes (http://www.dailymotion.com/developer) - - @using-api yes - @results JSON - @stable yes - @parse url, title, thumbnail, publishedDate, embedded - - @todo set content-parameter with correct data -""" - -from urllib import urlencode -from json import loads -from cgi import escape -from datetime import datetime - -# engine dependent config -categories = ['videos'] -paging = True -language_support = True - -# search-url -# see http://www.dailymotion.com/doc/api/obj-video.html -search_url = 'https://api.dailymotion.com/videos?fields=created_time,title,description,duration,url,thumbnail_360_url,id&sort=relevance&limit=5&page={pageno}&{query}' # noqa -embedded_url = '' - - -# do search-request -def request(query, params): - if params['language'] == 'all': - locale = 'en-US' - else: - locale = params['language'] - - params['url'] = search_url.format( - query=urlencode({'search': query, 'localization': locale}), - pageno=params['pageno']) - - return params - - -# get response from search-request -def response(resp): - results = [] - - search_res = loads(resp.text) - - # return empty array if there are no results - if 'list' not in search_res: - return [] - - # parse results - for res in search_res['list']: - title = res['title'] - url = res['url'] - content = escape(res['description']) - thumbnail = res['thumbnail_360_url'] - publishedDate = datetime.fromtimestamp(res['created_time'], None) - embedded = embedded_url.format(videoid=res['id']) - - # http to https - thumbnail = thumbnail.replace("http://", "https://") - - results.append({'template': 'videos.html', - 'url': url, - 'title': title, - 'content': content, - 'publishedDate': publishedDate, - 'embedded': embedded, - 'thumbnail': thumbnail}) - - # return results - return results diff --git a/sources/searx/engines/deezer.py b/sources/searx/engines/deezer.py deleted file mode 100644 index 0530bc0..0000000 --- a/sources/searx/engines/deezer.py +++ /dev/null @@ -1,67 +0,0 @@ -""" - Deezer (Music) - - @website https://deezer.com - @provide-api yes (http://developers.deezer.com/api/) - - @using-api yes - @results JSON - @stable yes - @parse url, title, content, embedded -""" - -from json import loads -from urllib import urlencode - -# engine dependent config -categories = ['music'] -paging = True - -# search-url -url = 'https://api.deezer.com/' -search_url = url + 'search?{query}&index={offset}' - -embedded_url = '' - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 25 - - params['url'] = search_url.format(query=urlencode({'q': query}), - offset=offset) - - return params - - -# get response from search-request -def response(resp): - results = [] - - search_res = loads(resp.text) - - # parse results - for result in search_res.get('data', []): - if result['type'] == 'track': - title = result['title'] - url = result['link'] - - if url.startswith('http://'): - url = 'https' + url[4:] - - content = result['artist']['name'] +\ - " • " +\ - result['album']['title'] +\ - " • " + result['title'] - embedded = embedded_url.format(audioid=result['id']) - - # append result - results.append({'url': url, - 'title': title, - 'embedded': embedded, - 'content': content}) - - # return results - return results diff --git a/sources/searx/engines/deviantart.py b/sources/searx/engines/deviantart.py deleted file mode 100644 index 135aeb3..0000000 --- a/sources/searx/engines/deviantart.py +++ /dev/null @@ -1,75 +0,0 @@ -""" - Deviantart (Images) - - @website https://www.deviantart.com/ - @provide-api yes (https://www.deviantart.com/developers/) (RSS) - - @using-api no (TODO, rewrite to api) - @results HTML - @stable no (HTML can change) - @parse url, title, thumbnail_src, img_src - - @todo rewrite to api -""" - -from urllib import urlencode -from urlparse import urljoin -from lxml import html -import re -from searx.engines.xpath import extract_text - -# engine dependent config -categories = ['images'] -paging = True - -# search-url -base_url = 'https://www.deviantart.com/' -search_url = base_url + 'browse/all/?offset={offset}&{query}' - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 24 - - params['url'] = search_url.format(offset=offset, - query=urlencode({'q': query})) - - return params - - -# get response from search-request -def response(resp): - results = [] - - # return empty array if a redirection code is returned - if resp.status_code == 302: - return [] - - dom = html.fromstring(resp.text) - - regex = re.compile('\/200H\/') - - # parse results - for result in dom.xpath('//div[contains(@class, "tt-a tt-fh")]'): - link = result.xpath('.//a[contains(@class, "thumb")]')[0] - url = urljoin(base_url, link.attrib.get('href')) - title_links = result.xpath('.//span[@class="details"]//a[contains(@class, "t")]') - title = extract_text(title_links[0]) - thumbnail_src = link.xpath('.//img')[0].attrib.get('src') - img_src = regex.sub('/', thumbnail_src) - - # http to https, remove domain sharding - thumbnail_src = re.sub(r"https?://(th|fc)\d+.", "https://th01.", thumbnail_src) - thumbnail_src = re.sub(r"http://", "https://", thumbnail_src) - - url = re.sub(r"http://(.*)\.deviantart\.com/", "https://\\1.deviantart.com/", url) - - # append result - results.append({'url': url, - 'title': title, - 'img_src': img_src, - 'thumbnail_src': thumbnail_src, - 'template': 'images.html'}) - - # return results - return results diff --git a/sources/searx/engines/digg.py b/sources/searx/engines/digg.py deleted file mode 100644 index a10b38b..0000000 --- a/sources/searx/engines/digg.py +++ /dev/null @@ -1,75 +0,0 @@ -""" - Digg (News, Social media) - - @website https://digg.com/ - @provide-api no - - @using-api no - @results HTML (using search portal) - @stable no (HTML can change) - @parse url, title, content, publishedDate, thumbnail -""" - -from urllib import quote_plus -from json import loads -from lxml import html -from cgi import escape -from dateutil import parser - -# engine dependent config -categories = ['news', 'social media'] -paging = True - -# search-url -base_url = 'https://digg.com/' -search_url = base_url + 'api/search/{query}.json?position={position}&format=html' - -# specific xpath variables -results_xpath = '//article' -link_xpath = './/small[@class="time"]//a' -title_xpath = './/h2//a//text()' -content_xpath = './/p//text()' -pubdate_xpath = './/time' - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 10 - params['url'] = search_url.format(position=offset, - query=quote_plus(query)) - return params - - -# get response from search-request -def response(resp): - results = [] - - search_result = loads(resp.text) - - if 'html' not in search_result or search_result['html'] == '': - return results - - dom = html.fromstring(search_result['html']) - - # parse results - for result in dom.xpath(results_xpath): - url = result.attrib.get('data-contenturl') - thumbnail = result.xpath('.//img')[0].attrib.get('src') - title = ''.join(result.xpath(title_xpath)) - content = escape(''.join(result.xpath(content_xpath))) - pubdate = result.xpath(pubdate_xpath)[0].attrib.get('datetime') - publishedDate = parser.parse(pubdate) - - # http to https - thumbnail = thumbnail.replace("http://static.digg.com", "https://static.digg.com") - - # append result - results.append({'url': url, - 'title': title, - 'content': content, - 'template': 'videos.html', - 'publishedDate': publishedDate, - 'thumbnail': thumbnail}) - - # return results - return results diff --git a/sources/searx/engines/doku.py b/sources/searx/engines/doku.py deleted file mode 100644 index 93867fd..0000000 --- a/sources/searx/engines/doku.py +++ /dev/null @@ -1,84 +0,0 @@ -# Doku Wiki -# -# @website https://www.dokuwiki.org/ -# @provide-api yes -# (https://www.dokuwiki.org/devel:xmlrpc) -# -# @using-api no -# @results HTML -# @stable yes -# @parse (general) url, title, content - -from urllib import urlencode -from lxml.html import fromstring -from searx.engines.xpath import extract_text - -# engine dependent config -categories = ['general'] # TODO , 'images', 'music', 'videos', 'files' -paging = False -language_support = False -number_of_results = 5 - -# search-url -# Doku is OpenSearch compatible -base_url = 'http://localhost:8090' -search_url = '/?do=search'\ - '&{query}' -# TODO '&startRecord={offset}'\ -# TODO '&maximumRecords={limit}'\ - - -# do search-request -def request(query, params): - - params['url'] = base_url +\ - search_url.format(query=urlencode({'id': query})) - - return params - - -# get response from search-request -def response(resp): - results = [] - - doc = fromstring(resp.text) - - # parse results - # Quickhits - for r in doc.xpath('//div[@class="search_quickresult"]/ul/li'): - try: - res_url = r.xpath('.//a[@class="wikilink1"]/@href')[-1] - except: - continue - - if not res_url: - continue - - title = extract_text(r.xpath('.//a[@class="wikilink1"]/@title')) - - # append result - results.append({'title': title, - 'content': "", - 'url': base_url + res_url}) - - # Search results - for r in doc.xpath('//dl[@class="search_results"]/*'): - try: - if r.tag == "dt": - res_url = r.xpath('.//a[@class="wikilink1"]/@href')[-1] - title = extract_text(r.xpath('.//a[@class="wikilink1"]/@title')) - elif r.tag == "dd": - content = extract_text(r.xpath('.')) - - # append result - results.append({'title': title, - 'content': content, - 'url': base_url + res_url}) - except: - continue - - if not res_url: - continue - - # return results - return results diff --git a/sources/searx/engines/duckduckgo.py b/sources/searx/engines/duckduckgo.py deleted file mode 100644 index 373ce1b..0000000 --- a/sources/searx/engines/duckduckgo.py +++ /dev/null @@ -1,78 +0,0 @@ -""" - DuckDuckGo (Web) - - @website https://duckduckgo.com/ - @provide-api yes (https://duckduckgo.com/api), - but not all results from search-site - - @using-api no - @results HTML (using search portal) - @stable no (HTML can change) - @parse url, title, content - - @todo rewrite to api - @todo language support - (the current used site does not support language-change) -""" - -from urllib import urlencode -from lxml.html import fromstring -from searx.engines.xpath import extract_text - -# engine dependent config -categories = ['general'] -paging = True -language_support = True - -# search-url -url = 'https://duckduckgo.com/html?{query}&s={offset}' - -# specific xpath variables -result_xpath = '//div[@class="result results_links results_links_deep web-result "]' # noqa -url_xpath = './/a[@class="result__a"]/@href' -title_xpath = './/a[@class="result__a"]' -content_xpath = './/a[@class="result__snippet"]' - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 30 - - if params['language'] == 'all': - locale = 'en-us' - else: - locale = params['language'].replace('_', '-').lower() - - params['url'] = url.format( - query=urlencode({'q': query, 'kl': locale}), - offset=offset) - - return params - - -# get response from search-request -def response(resp): - results = [] - - doc = fromstring(resp.text) - - # parse results - for r in doc.xpath(result_xpath): - try: - res_url = r.xpath(url_xpath)[-1] - except: - continue - - if not res_url: - continue - - title = extract_text(r.xpath(title_xpath)) - content = extract_text(r.xpath(content_xpath)) - - # append result - results.append({'title': title, - 'content': content, - 'url': res_url}) - - # return results - return results diff --git a/sources/searx/engines/duckduckgo_definitions.py b/sources/searx/engines/duckduckgo_definitions.py deleted file mode 100644 index 208ccca..0000000 --- a/sources/searx/engines/duckduckgo_definitions.py +++ /dev/null @@ -1,156 +0,0 @@ -import json -from urllib import urlencode -from re import compile, sub -from lxml import html -from searx.utils import html_to_text -from searx.engines.xpath import extract_text - -url = 'https://api.duckduckgo.com/'\ - + '?{query}&format=json&pretty=0&no_redirect=1&d=1' - -http_regex = compile(r'^http:') - - -def result_to_text(url, text, htmlResult): - # TODO : remove result ending with "Meaning" or "Category" - dom = html.fromstring(htmlResult) - a = dom.xpath('//a') - if len(a) >= 1: - return extract_text(a[0]) - else: - return text - - -def request(query, params): - params['url'] = url.format(query=urlencode({'q': query})) - params['headers']['Accept-Language'] = params['language'] - return params - - -def response(resp): - results = [] - - search_res = json.loads(resp.text) - - content = '' - heading = search_res.get('Heading', '') - attributes = [] - urls = [] - infobox_id = None - relatedTopics = [] - - # add answer if there is one - answer = search_res.get('Answer', '') - if answer != '': - results.append({'answer': html_to_text(answer)}) - - # add infobox - if 'Definition' in search_res: - content = content + search_res.get('Definition', '') - - if 'Abstract' in search_res: - content = content + search_res.get('Abstract', '') - - # image - image = search_res.get('Image', '') - image = None if image == '' else image - - # attributes - if 'Infobox' in search_res: - infobox = search_res.get('Infobox', None) - if 'content' in infobox: - for info in infobox.get('content'): - attributes.append({'label': info.get('label'), - 'value': info.get('value')}) - - # urls - for ddg_result in search_res.get('Results', []): - if 'FirstURL' in ddg_result: - firstURL = ddg_result.get('FirstURL', '') - text = ddg_result.get('Text', '') - urls.append({'title': text, 'url': firstURL}) - results.append({'title': heading, 'url': firstURL}) - - # related topics - for ddg_result in search_res.get('RelatedTopics', []): - if 'FirstURL' in ddg_result: - suggestion = result_to_text(ddg_result.get('FirstURL', None), - ddg_result.get('Text', None), - ddg_result.get('Result', None)) - if suggestion != heading: - results.append({'suggestion': suggestion}) - elif 'Topics' in ddg_result: - suggestions = [] - relatedTopics.append({'name': ddg_result.get('Name', ''), - 'suggestions': suggestions}) - for topic_result in ddg_result.get('Topics', []): - suggestion = result_to_text(topic_result.get('FirstURL', None), - topic_result.get('Text', None), - topic_result.get('Result', None)) - if suggestion != heading: - suggestions.append(suggestion) - - # abstract - abstractURL = search_res.get('AbstractURL', '') - if abstractURL != '': - # add as result ? problem always in english - infobox_id = abstractURL - urls.append({'title': search_res.get('AbstractSource'), - 'url': abstractURL}) - - # definition - definitionURL = search_res.get('DefinitionURL', '') - if definitionURL != '': - # add as result ? as answer ? problem always in english - infobox_id = definitionURL - urls.append({'title': search_res.get('DefinitionSource'), - 'url': definitionURL}) - - # to merge with wikidata's infobox - if infobox_id: - infobox_id = http_regex.sub('https:', infobox_id) - - # entity - entity = search_res.get('Entity', None) - # TODO continent / country / department / location / waterfall / - # mountain range : - # link to map search, get weather, near by locations - # TODO musician : link to music search - # TODO concert tour : ?? - # TODO film / actor / television / media franchise : - # links to IMDB / rottentomatoes (or scrap result) - # TODO music : link tu musicbrainz / last.fm - # TODO book : ?? - # TODO artist / playwright : ?? - # TODO compagny : ?? - # TODO software / os : ?? - # TODO software engineer : ?? - # TODO prepared food : ?? - # TODO website : ?? - # TODO performing art : ?? - # TODO prepared food : ?? - # TODO programming language : ?? - # TODO file format : ?? - - if len(heading) > 0: - # TODO get infobox.meta.value where .label='article_title' - if image is None and len(attributes) == 0 and len(urls) == 1 and\ - len(relatedTopics) == 0 and len(content) == 0: - results.append({ - 'url': urls[0]['url'], - 'title': heading, - 'content': content - }) - else: - results.append({ - 'infobox': heading, - 'id': infobox_id, - 'entity': entity, - 'content': content, - 'img_src': image, - 'attributes': attributes, - 'urls': urls, - 'relatedTopics': relatedTopics - }) - - return results diff --git a/sources/searx/engines/dummy.py b/sources/searx/engines/dummy.py deleted file mode 100644 index 50b56ef..0000000 --- a/sources/searx/engines/dummy.py +++ /dev/null @@ -1,16 +0,0 @@ -""" - Dummy - - @results empty array - @stable yes -""" - - -# do search-request -def request(query, params): - return params - - -# get response from search-request -def response(resp): - return [] diff --git a/sources/searx/engines/faroo.py b/sources/searx/engines/faroo.py deleted file mode 100644 index 9fa244e..0000000 --- a/sources/searx/engines/faroo.py +++ /dev/null @@ -1,116 +0,0 @@ -""" - Faroo (Web, News) - - @website http://www.faroo.com - @provide-api yes (http://www.faroo.com/hp/api/api.html), require API-key - - @using-api yes - @results JSON - @stable yes - @parse url, title, content, publishedDate, img_src -""" - -from urllib import urlencode -from json import loads -import datetime -from searx.utils import searx_useragent - -# engine dependent config -categories = ['general', 'news'] -paging = True -language_support = True -number_of_results = 10 -api_key = None - -# search-url -url = 'http://www.faroo.com/' -search_url = url + 'api?{query}'\ - '&start={offset}'\ - '&length={number_of_results}'\ - '&l={language}'\ - '&src={categorie}'\ - '&i=false'\ - '&f=json'\ - '&key={api_key}' # noqa - -search_category = {'general': 'web', - 'news': 'news'} - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * number_of_results + 1 - categorie = search_category.get(params['category'], 'web') - - if params['language'] == 'all': - language = 'en' - else: - language = params['language'].split('_')[0] - - # if language is not supported, put it in english - if language != 'en' and\ - language != 'de' and\ - language != 'zh': - language = 'en' - - params['url'] = search_url.format(offset=offset, - number_of_results=number_of_results, - query=urlencode({'q': query}), - language=language, - categorie=categorie, - api_key=api_key) - - # using searx User-Agent - params['headers']['User-Agent'] = searx_useragent() - - return params - - -# get response from search-request -def response(resp): - # HTTP-Code 401: api-key is not valide - if resp.status_code == 401: - raise Exception("API key is not valide") - - # HTTP-Code 429: rate limit exceeded - if resp.status_code == 429: - raise Exception("rate limit has been exceeded!") - - results = [] - - search_res = loads(resp.text) - - # return empty array if there are no results - if not search_res.get('results', {}): - return [] - - # parse results - for result in search_res['results']: - if result['news']: - # timestamp (milliseconds since 1970) - publishedDate = datetime.datetime.fromtimestamp(result['date'] / 1000.0) # noqa - - # append news result - results.append({'url': result['url'], - 'title': result['title'], - 'publishedDate': publishedDate, - 'content': result['kwic']}) - - else: - # append general result - # TODO, publishedDate correct? - results.append({'url': result['url'], - 'title': result['title'], - 'content': result['kwic']}) - - # append image result if image url is set - # TODO, show results with an image like in faroo - if result['iurl']: - results.append({'template': 'images.html', - 'url': result['url'], - 'title': result['title'], - 'content': result['kwic'], - 'img_src': result['iurl']}) - - # return results - return results diff --git a/sources/searx/engines/fdroid.py b/sources/searx/engines/fdroid.py deleted file mode 100644 index 0b16773..0000000 --- a/sources/searx/engines/fdroid.py +++ /dev/null @@ -1,53 +0,0 @@ -""" - F-Droid (a repository of FOSS applications for Android) - - @website https://f-droid.org/ - @provide-api no - @using-api no - @results HTML - @stable no (HTML can change) - @parse url, title, content -""" - -from cgi import escape -from urllib import urlencode -from searx.engines.xpath import extract_text -from lxml import html - -# engine dependent config -categories = ['files'] -paging = True - -# search-url -base_url = 'https://f-droid.org/' -search_url = base_url + 'repository/browse/?{query}' - - -# do search-request -def request(query, params): - query = urlencode({'fdfilter': query, - 'fdpage': params['pageno']}) - params['url'] = search_url.format(query=query) - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - - for app in dom.xpath('//div[@id="appheader"]'): - url = app.xpath('./ancestor::a/@href')[0] - title = app.xpath('./p/span/text()')[0] - img_src = app.xpath('.//img/@src')[0] - - content = extract_text(app.xpath('./p')[0]) - content = escape(content.replace(title, '', 1).strip()) - - results.append({'url': url, - 'title': title, - 'content': content, - 'img_src': img_src}) - - return results diff --git a/sources/searx/engines/filecrop.py b/sources/searx/engines/filecrop.py deleted file mode 100644 index 89dc776..0000000 --- a/sources/searx/engines/filecrop.py +++ /dev/null @@ -1,84 +0,0 @@ -from urllib import urlencode -from HTMLParser import HTMLParser - -url = 'http://www.filecrop.com/' -search_url = url + '/search.php?{query}&size_i=0&size_f=100000000&engine_r=1&engine_d=1&engine_e=1&engine_4=1&engine_m=1&pos={index}' # noqa - -paging = True - - -class FilecropResultParser(HTMLParser): - def __init__(self): - HTMLParser.__init__(self) - self.__start_processing = False - - self.results = [] - self.result = {} - - self.tr_counter = 0 - self.data_counter = 0 - - def handle_starttag(self, tag, attrs): - - if tag == 'tr': - if ('bgcolor', '#edeff5') in attrs or\ - ('bgcolor', '#ffffff') in attrs: - self.__start_processing = True - - if not self.__start_processing: - return - - if tag == 'label': - self.result['title'] = [attr[1] for attr in attrs - if attr[0] == 'title'][0] - elif tag == 'a' and ('rel', 'nofollow') in attrs\ - and ('class', 'sourcelink') in attrs: - if 'content' in self.result: - self.result['content'] += [attr[1] for attr in attrs - if attr[0] == 'title'][0] - else: - self.result['content'] = [attr[1] for attr in attrs - if attr[0] == 'title'][0] - self.result['content'] += ' ' - elif tag == 'a': - self.result['url'] = url + [attr[1] for attr in attrs - if attr[0] == 'href'][0] - - def handle_endtag(self, tag): - if self.__start_processing is False: - return - - if tag == 'tr': - self.tr_counter += 1 - - if self.tr_counter == 2: - self.__start_processing = False - self.tr_counter = 0 - self.data_counter = 0 - self.results.append(self.result) - self.result = {} - - def handle_data(self, data): - if not self.__start_processing: - return - - if 'content' in self.result: - self.result['content'] += data + ' ' - else: - self.result['content'] = data + ' ' - - self.data_counter += 1 - - -def request(query, params): - index = 1 + (params['pageno'] - 1) * 30 - params['url'] = search_url.format(query=urlencode({'w': query}), - index=index) - return params - - -def response(resp): - parser = FilecropResultParser() - parser.feed(resp.text) - - return parser.results diff --git a/sources/searx/engines/flickr.py b/sources/searx/engines/flickr.py deleted file mode 100644 index 68d45bc..0000000 --- a/sources/searx/engines/flickr.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python - -""" - Flickr (Images) - - @website https://www.flickr.com - @provide-api yes (https://secure.flickr.com/services/api/flickr.photos.search.html) - - @using-api yes - @results JSON - @stable yes - @parse url, title, thumbnail, img_src - More info on api-key : https://www.flickr.com/services/apps/create/ -""" - -from urllib import urlencode -from json import loads - -categories = ['images'] - -nb_per_page = 15 -paging = True -api_key = None - - -url = 'https://api.flickr.com/services/rest/?method=flickr.photos.search' +\ - '&api_key={api_key}&{text}&sort=relevance' +\ - '&extras=description%2C+owner_name%2C+url_o%2C+url_n%2C+url_z' +\ - '&per_page={nb_per_page}&format=json&nojsoncallback=1&page={page}' -photo_url = 'https://www.flickr.com/photos/{userid}/{photoid}' - -paging = True - - -def build_flickr_url(user_id, photo_id): - return photo_url.format(userid=user_id, photoid=photo_id) - - -def request(query, params): - params['url'] = url.format(text=urlencode({'text': query}), - api_key=api_key, - nb_per_page=nb_per_page, - page=params['pageno']) - return params - - -def response(resp): - results = [] - - search_results = loads(resp.text) - - # return empty array if there are no results - if 'photos' not in search_results: - return [] - - if 'photo' not in search_results['photos']: - return [] - - photos = search_results['photos']['photo'] - - # parse results - for photo in photos: - if 'url_o' in photo: - img_src = photo['url_o'] - elif 'url_z' in photo: - img_src = photo['url_z'] - else: - continue - -# For a bigger thumbnail, keep only the url_z, not the url_n - if 'url_n' in photo: - thumbnail_src = photo['url_n'] - elif 'url_z' in photo: - thumbnail_src = photo['url_z'] - else: - thumbnail_src = img_src - - url = build_flickr_url(photo['owner'], photo['id']) - - title = photo['title'] - - content = '' +\ - photo['ownername'] +\ - '
' +\ - '' +\ - photo['description']['_content'] +\ - '' - - # append result - results.append({'url': url, - 'title': title, - 'img_src': img_src, - 'thumbnail_src': thumbnail_src, - 'content': content, - 'template': 'images.html'}) - - # return results - return results diff --git a/sources/searx/engines/flickr_noapi.py b/sources/searx/engines/flickr_noapi.py deleted file mode 100644 index 87b912e..0000000 --- a/sources/searx/engines/flickr_noapi.py +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env python - -""" - Flickr (Images) - - @website https://www.flickr.com - @provide-api yes (https://secure.flickr.com/services/api/flickr.photos.search.html) - - @using-api no - @results HTML - @stable no - @parse url, title, thumbnail, img_src -""" - -from urllib import urlencode -from json import loads -import re -from searx.engines import logger - - -logger = logger.getChild('flickr-noapi') - -categories = ['images'] - -url = 'https://www.flickr.com/' -search_url = url + 'search?{query}&page={page}' -photo_url = 'https://www.flickr.com/photos/{userid}/{photoid}' -regex = re.compile(r"\"search-photos-lite-models\",\"photos\":(.*}),\"totalItems\":", re.DOTALL) -image_sizes = ('o', 'k', 'h', 'b', 'c', 'z', 'n', 'm', 't', 'q', 's') - -paging = True - - -def build_flickr_url(user_id, photo_id): - return photo_url.format(userid=user_id, photoid=photo_id) - - -def request(query, params): - params['url'] = search_url.format(query=urlencode({'text': query}), - page=params['pageno']) - - return params - - -def response(resp): - results = [] - - matches = regex.search(resp.text) - - if matches is None: - return results - - match = matches.group(1) - search_results = loads(match) - - if '_data' not in search_results: - return [] - - photos = search_results['_data'] - - for photo in photos: - - # In paged configuration, the first pages' photos - # are represented by a None object - if photo is None: - continue - - img_src = None - # From the biggest to the lowest format - for image_size in image_sizes: - if image_size in photo['sizes']: - img_src = photo['sizes'][image_size]['url'] - break - - if not img_src: - logger.debug('cannot find valid image size: {0}'.format(repr(photo))) - continue - - if 'ownerNsid' not in photo: - continue - - # For a bigger thumbnail, keep only the url_z, not the url_n - if 'n' in photo['sizes']: - thumbnail_src = photo['sizes']['n']['url'] - elif 'z' in photo['sizes']: - thumbnail_src = photo['sizes']['z']['url'] - else: - thumbnail_src = img_src - - url = build_flickr_url(photo['ownerNsid'], photo['id']) - - title = photo.get('title', '') - - content = '' +\ - photo['username'] +\ - '
' - - # append result - results.append({'url': url, - 'title': title, - 'img_src': img_src, - 'thumbnail_src': thumbnail_src, - 'content': content, - 'template': 'images.html'}) - - return results diff --git a/sources/searx/engines/frinkiac.py b/sources/searx/engines/frinkiac.py deleted file mode 100644 index a9383f8..0000000 --- a/sources/searx/engines/frinkiac.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Frinkiac (Images) - -@website https://www.frinkiac.com -@provide-api no -@using-api no -@results JSON -@stable no -@parse url, title, img_src -""" - -from json import loads -from urllib import urlencode - -categories = ['images'] - -BASE = 'https://frinkiac.com/' -SEARCH_URL = '{base}api/search?{query}' -RESULT_URL = '{base}?{query}' -THUMB_URL = '{base}img/{episode}/{timestamp}/medium.jpg' -IMAGE_URL = '{base}img/{episode}/{timestamp}.jpg' - - -def request(query, params): - params['url'] = SEARCH_URL.format(base=BASE, query=urlencode({'q': query})) - return params - - -def response(resp): - results = [] - response_data = loads(resp.text) - for result in response_data: - episode = result['Episode'] - timestamp = result['Timestamp'] - - results.append({'template': 'images.html', - 'url': RESULT_URL.format(base=BASE, - query=urlencode({'p': 'caption', 'e': episode, 't': timestamp})), - 'title': episode, - 'content': '', - 'thumbnail_src': THUMB_URL.format(base=BASE, episode=episode, timestamp=timestamp), - 'img_src': IMAGE_URL.format(base=BASE, episode=episode, timestamp=timestamp)}) - - return results diff --git a/sources/searx/engines/generalfile.py b/sources/searx/engines/generalfile.py deleted file mode 100644 index 3bb2744..0000000 --- a/sources/searx/engines/generalfile.py +++ /dev/null @@ -1,62 +0,0 @@ -""" - General Files (Files) - - @website http://www.general-files.org - @provide-api no (nothing found) - - @using-api no (because nothing found) - @results HTML (using search portal) - @stable no (HTML can change) - @parse url, title, content - - @todo detect torrents? -""" - -from lxml import html - -# engine dependent config -categories = ['files'] -paging = True - -# search-url -base_url = 'http://www.general-file.com' -search_url = base_url + '/files-{letter}/{query}/{pageno}' - -# specific xpath variables -result_xpath = '//table[@class="block-file"]' -title_xpath = './/h2/a//text()' -url_xpath = './/h2/a/@href' -content_xpath = './/p//text()' - - -# do search-request -def request(query, params): - - params['url'] = search_url.format(query=query, - letter=query[0], - pageno=params['pageno']) - - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - - # parse results - for result in dom.xpath(result_xpath): - url = result.xpath(url_xpath)[0] - - # skip fast download links - if not url.startswith('/'): - continue - - # append result - results.append({'url': base_url + url, - 'title': ''.join(result.xpath(title_xpath)), - 'content': ''.join(result.xpath(content_xpath))}) - - # return results - return results diff --git a/sources/searx/engines/gigablast.py b/sources/searx/engines/gigablast.py deleted file mode 100644 index 6e4e24b..0000000 --- a/sources/searx/engines/gigablast.py +++ /dev/null @@ -1,85 +0,0 @@ -""" - Gigablast (Web) - - @website https://gigablast.com - @provide-api yes (https://gigablast.com/api.html) - - @using-api yes - @results XML - @stable yes - @parse url, title, content -""" - -from cgi import escape -from json import loads -from random import randint -from time import time -from urllib import urlencode - -# engine dependent config -categories = ['general'] -paging = True -number_of_results = 10 -language_support = True -safesearch = True - -# search-url -base_url = 'https://gigablast.com/' -search_string = 'search?{query}'\ - '&n={number_of_results}'\ - '&c=main'\ - '&s={offset}'\ - '&format=json'\ - '&qh=0'\ - '&qlang={lang}'\ - '&ff={safesearch}'\ - '&rxikd={rxikd}' # random number - 9 digits - -# specific xpath variables -results_xpath = '//response//result' -url_xpath = './/url' -title_xpath = './/title' -content_xpath = './/sum' - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * number_of_results - - if params['language'] == 'all': - language = 'xx' - else: - language = params['language'][0:2] - - if params['safesearch'] >= 1: - safesearch = 1 - else: - safesearch = 0 - - search_path = search_string.format(query=urlencode({'q': query}), - offset=offset, - number_of_results=number_of_results, - rxikd=str(time())[:9], - lang=language, - safesearch=safesearch) - - params['url'] = base_url + search_path - - return params - - -# get response from search-request -def response(resp): - results = [] - - # parse results - response_json = loads(resp.text) - - for result in response_json['results']: - # append result - results.append({'url': result['url'], - 'title': escape(result['title']), - 'content': escape(result['sum'])}) - - # return results - return results diff --git a/sources/searx/engines/github.py b/sources/searx/engines/github.py deleted file mode 100644 index cc1fc47..0000000 --- a/sources/searx/engines/github.py +++ /dev/null @@ -1,61 +0,0 @@ -""" - Github (It) - - @website https://github.com/ - @provide-api yes (https://developer.github.com/v3/) - - @using-api yes - @results JSON - @stable yes (using api) - @parse url, title, content -""" - -from urllib import urlencode -from json import loads -from cgi import escape - -# engine dependent config -categories = ['it'] - -# search-url -search_url = 'https://api.github.com/search/repositories?sort=stars&order=desc&{query}' # noqa - -accept_header = 'application/vnd.github.preview.text-match+json' - - -# do search-request -def request(query, params): - params['url'] = search_url.format(query=urlencode({'q': query})) - - params['headers']['Accept'] = accept_header - - return params - - -# get response from search-request -def response(resp): - results = [] - - search_res = loads(resp.text) - - # check if items are recieved - if 'items' not in search_res: - return [] - - # parse results - for res in search_res['items']: - title = res['name'] - url = res['html_url'] - - if res['description']: - content = escape(res['description'][:500]) - else: - content = '' - - # append result - results.append({'url': url, - 'title': title, - 'content': content}) - - # return results - return results diff --git a/sources/searx/engines/google.py b/sources/searx/engines/google.py deleted file mode 100644 index 6018ad1..0000000 --- a/sources/searx/engines/google.py +++ /dev/null @@ -1,349 +0,0 @@ -# Google (Web) -# -# @website https://www.google.com -# @provide-api yes (https://developers.google.com/custom-search/) -# -# @using-api no -# @results HTML -# @stable no (HTML can change) -# @parse url, title, content, suggestion - -import re -from cgi import escape -from urllib import urlencode -from urlparse import urlparse, parse_qsl -from lxml import html, etree -from searx.engines.xpath import extract_text, extract_url -from searx.search import logger - -logger = logger.getChild('google engine') - - -# engine dependent config -categories = ['general'] -paging = True -language_support = True -use_locale_domain = True - -# based on https://en.wikipedia.org/wiki/List_of_Google_domains and tests -default_hostname = 'www.google.com' - -country_to_hostname = { - 'BG': 'www.google.bg', # Bulgaria - 'CZ': 'www.google.cz', # Czech Republic - 'DE': 'www.google.de', # Germany - 'DK': 'www.google.dk', # Denmark - 'AT': 'www.google.at', # Austria - 'CH': 'www.google.ch', # Switzerland - 'GR': 'www.google.gr', # Greece - 'AU': 'www.google.com.au', # Australia - 'CA': 'www.google.ca', # Canada - 'GB': 'www.google.co.uk', # United Kingdom - 'ID': 'www.google.co.id', # Indonesia - 'IE': 'www.google.ie', # Ireland - 'IN': 'www.google.co.in', # India - 'MY': 'www.google.com.my', # Malaysia - 'NZ': 'www.google.co.nz', # New Zealand - 'PH': 'www.google.com.ph', # Philippines - 'SG': 'www.google.com.sg', # Singapore - # 'US': 'www.google.us', # United States, redirect to .com - 'ZA': 'www.google.co.za', # South Africa - 'AR': 'www.google.com.ar', # Argentina - 'CL': 'www.google.cl', # Chile - 'ES': 'www.google.es', # Spain - 'MX': 'www.google.com.mx', # Mexico - 'EE': 'www.google.ee', # Estonia - 'FI': 'www.google.fi', # Finland - 'BE': 'www.google.be', # Belgium - 'FR': 'www.google.fr', # France - 'IL': 'www.google.co.il', # Israel - 'HR': 'www.google.hr', # Croatia - 'HU': 'www.google.hu', # Hungary - 'IT': 'www.google.it', # Italy - 'JP': 'www.google.co.jp', # Japan - 'KR': 'www.google.co.kr', # South Korea - 'LT': 'www.google.lt', # Lithuania - 'LV': 'www.google.lv', # Latvia - 'NO': 'www.google.no', # Norway - 'NL': 'www.google.nl', # Netherlands - 'PL': 'www.google.pl', # Poland - 'BR': 'www.google.com.br', # Brazil - 'PT': 'www.google.pt', # Portugal - 'RO': 'www.google.ro', # Romania - 'RU': 'www.google.ru', # Russia - 'SK': 'www.google.sk', # Slovakia - 'SL': 'www.google.si', # Slovenia (SL -> si) - 'SE': 'www.google.se', # Sweden - 'TH': 'www.google.co.th', # Thailand - 'TR': 'www.google.com.tr', # Turkey - 'UA': 'www.google.com.ua', # Ukraine - # 'CN': 'www.google.cn', # China, only from China ? - 'HK': 'www.google.com.hk', # Hong Kong - 'TW': 'www.google.com.tw' # Taiwan -} - -# osm -url_map = 'https://www.openstreetmap.org/'\ - + '?lat={latitude}&lon={longitude}&zoom={zoom}&layers=M' - -# search-url -search_path = '/search' -search_url = ('https://{hostname}' + - search_path + - '?{query}&start={offset}&gws_rd=cr&gbv=1&lr={lang}&ei=x') - -# other URLs -map_hostname_start = 'maps.google.' -maps_path = '/maps' -redirect_path = '/url' -images_path = '/images' - -# specific xpath variables -results_xpath = '//div[@class="g"]' -url_xpath = './/h3/a/@href' -title_xpath = './/h3' -content_xpath = './/span[@class="st"]' -content_misc_xpath = './/div[@class="f slp"]' -suggestion_xpath = '//p[@class="_Bmc"]' - -# map : detail location -map_address_xpath = './/div[@class="s"]//table//td[2]/span/text()' -map_phone_xpath = './/div[@class="s"]//table//td[2]/span/span' -map_website_url_xpath = 'h3[2]/a/@href' -map_website_title_xpath = 'h3[2]' - -# map : near the location -map_near = 'table[@class="ts"]//tr' -map_near_title = './/h4' -map_near_url = './/h4/a/@href' -map_near_phone = './/span[@class="nobr"]' - -# images -images_xpath = './/div/a' -image_url_xpath = './@href' -image_img_src_xpath = './img/@src' - -# property names -# FIXME : no translation -property_address = "Address" -property_phone = "Phone number" - - -# remove google-specific tracking-url -def parse_url(url_string, google_hostname): - # sanity check - if url_string is None: - return url_string - - # normal case - parsed_url = urlparse(url_string) - if (parsed_url.netloc in [google_hostname, ''] - and parsed_url.path == redirect_path): - query = dict(parse_qsl(parsed_url.query)) - return query['q'] - else: - return url_string - - -# returns extract_text on the first result selected by the xpath or None -def extract_text_from_dom(result, xpath): - r = result.xpath(xpath) - if len(r) > 0: - return escape(extract_text(r[0])) - return None - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 10 - - if params['language'] == 'all': - language = 'en' - country = 'US' - url_lang = '' - else: - language_array = params['language'].lower().split('_') - if len(language_array) == 2: - country = language_array[1] - else: - country = 'US' - language = language_array[0] + ',' + language_array[0] + '-' + country - url_lang = 'lang_' + language_array[0] - - if use_locale_domain: - google_hostname = country_to_hostname.get(country.upper(), default_hostname) - else: - google_hostname = default_hostname - - params['url'] = search_url.format(offset=offset, - query=urlencode({'q': query}), - hostname=google_hostname, - lang=url_lang) - - params['headers']['Accept-Language'] = language - params['headers']['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' - - params['google_hostname'] = google_hostname - - return params - - -# get response from search-request -def response(resp): - results = [] - - # detect google sorry - resp_url = urlparse(resp.url) - if resp_url.netloc == 'sorry.google.com' or resp_url.path == '/sorry/IndexRedirect': - raise RuntimeWarning('sorry.google.com') - - # which hostname ? - google_hostname = resp.search_params.get('google_hostname') - google_url = "https://" + google_hostname - - # convert the text to dom - dom = html.fromstring(resp.text) - - # parse results - for result in dom.xpath(results_xpath): - try: - title = extract_text(result.xpath(title_xpath)[0]) - url = parse_url(extract_url(result.xpath(url_xpath), google_url), google_hostname) - parsed_url = urlparse(url, google_hostname) - - # map result - if parsed_url.netloc == google_hostname: - # TODO fix inside links - continue - # if parsed_url.path.startswith(maps_path) or parsed_url.netloc.startswith(map_hostname_start): - # print "yooooo"*30 - # x = result.xpath(map_near) - # if len(x) > 0: - # # map : near the location - # results = results + parse_map_near(parsed_url, x, google_hostname) - # else: - # # map : detail about a location - # results = results + parse_map_detail(parsed_url, result, google_hostname) - # # google news - # elif parsed_url.path == search_path: - # # skipping news results - # pass - - # # images result - # elif parsed_url.path == images_path: - # # only thumbnail image provided, - # # so skipping image results - # # results = results + parse_images(result, google_hostname) - # pass - - else: - # normal result - content = extract_text_from_dom(result, content_xpath) - if content is None: - continue - content_misc = extract_text_from_dom(result, content_misc_xpath) - if content_misc is not None: - content = content_misc + "
" + content - # append result - results.append({'url': url, - 'title': title, - 'content': content - }) - except: - logger.debug('result parse error in:\n%s', etree.tostring(result, pretty_print=True)) - continue - - # parse suggestion - for suggestion in dom.xpath(suggestion_xpath): - # append suggestion - results.append({'suggestion': escape(extract_text(suggestion))}) - - # return results - return results - - -def parse_images(result, google_hostname): - results = [] - for image in result.xpath(images_xpath): - url = parse_url(extract_text(image.xpath(image_url_xpath)[0]), google_hostname) - img_src = extract_text(image.xpath(image_img_src_xpath)[0]) - - # append result - results.append({'url': url, - 'title': '', - 'content': '', - 'img_src': img_src, - 'template': 'images.html' - }) - - return results - - -def parse_map_near(parsed_url, x, google_hostname): - results = [] - - for result in x: - title = extract_text_from_dom(result, map_near_title) - url = parse_url(extract_text_from_dom(result, map_near_url), google_hostname) - attributes = [] - phone = extract_text_from_dom(result, map_near_phone) - add_attributes(attributes, property_phone, phone, 'tel:' + phone) - results.append({'title': title, - 'url': url, - 'content': attributes_to_html(attributes) - }) - - return results - - -def parse_map_detail(parsed_url, result, google_hostname): - results = [] - - # try to parse the geoloc - m = re.search('@([0-9\.]+),([0-9\.]+),([0-9]+)', parsed_url.path) - if m is None: - m = re.search('ll\=([0-9\.]+),([0-9\.]+)\&z\=([0-9]+)', parsed_url.query) - - if m is not None: - # geoloc found (ignored) - lon = float(m.group(2)) # noqa - lat = float(m.group(1)) # noqa - zoom = int(m.group(3)) # noqa - - # attributes - attributes = [] - address = extract_text_from_dom(result, map_address_xpath) - phone = extract_text_from_dom(result, map_phone_xpath) - add_attributes(attributes, property_address, address, 'geo:' + str(lat) + ',' + str(lon)) - add_attributes(attributes, property_phone, phone, 'tel:' + phone) - - # title / content / url - website_title = extract_text_from_dom(result, map_website_title_xpath) - content = extract_text_from_dom(result, content_xpath) - website_url = parse_url(extract_text_from_dom(result, map_website_url_xpath), google_hostname) - - # add a result if there is a website - if website_url is not None: - results.append({'title': website_title, - 'content': (content + '
' if content is not None else '') - + attributes_to_html(attributes), - 'url': website_url - }) - - return results - - -def add_attributes(attributes, name, value, url): - if value is not None and len(value) > 0: - attributes.append({'label': name, 'value': value, 'url': url}) - - -def attributes_to_html(attributes): - retval = '' - for a in attributes: - value = a.get('value') - if 'url' in a: - value = '' + value + '' - retval = retval + '' - retval = retval + '
' + a.get('label') + '' + value + '
' - return retval diff --git a/sources/searx/engines/google_images.py b/sources/searx/engines/google_images.py deleted file mode 100644 index efe4681..0000000 --- a/sources/searx/engines/google_images.py +++ /dev/null @@ -1,69 +0,0 @@ -""" - Google (Images) - - @website https://www.google.com - @provide-api yes (https://developers.google.com/custom-search/) - - @using-api no - @results HTML chunks with JSON inside - @stable no - @parse url, title, img_src -""" - -from urllib import urlencode -from urlparse import parse_qs -from json import loads -from lxml import html - -# engine dependent config -categories = ['images'] -paging = True -safesearch = True - -search_url = 'https://www.google.com/search'\ - '?{query}'\ - '&tbm=isch'\ - '&ijn=1'\ - '&start={offset}' - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 100 - - params['url'] = search_url.format(query=urlencode({'q': query}), - offset=offset, - safesearch=safesearch) - - if safesearch and params['safesearch']: - params['url'] += '&' + urlencode({'safe': 'active'}) - - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - - # parse results - for result in dom.xpath('//div[@data-ved]'): - - metadata = loads(result.xpath('./div[@class="rg_meta"]/text()')[0]) - - thumbnail_src = metadata['tu'] - - # http to https - thumbnail_src = thumbnail_src.replace("http://", "https://") - - # append result - results.append({'url': metadata['ru'], - 'title': metadata['pt'], - 'content': metadata['s'], - 'thumbnail_src': thumbnail_src, - 'img_src': metadata['ou'], - 'template': 'images.html'}) - - # return results - return results diff --git a/sources/searx/engines/google_news.py b/sources/searx/engines/google_news.py deleted file mode 100644 index 95d15cf..0000000 --- a/sources/searx/engines/google_news.py +++ /dev/null @@ -1,67 +0,0 @@ -""" - Google (News) - - @website https://www.google.com - @provide-api yes (https://developers.google.com/web-search/docs/), - deprecated! - - @using-api yes - @results JSON - @stable yes (but deprecated) - @parse url, title, content, publishedDate -""" - -from urllib import urlencode -from json import loads -from dateutil import parser - -# search-url -categories = ['news'] -paging = True -language_support = True - -# engine dependent config -url = 'https://ajax.googleapis.com/' -search_url = url + 'ajax/services/search/news?v=2.0&start={offset}&rsz=large&safe=off&filter=off&{query}&hl={lang}' - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 8 - - language = 'en-US' - if params['language'] != 'all': - language = params['language'].replace('_', '-') - - params['url'] = search_url.format(offset=offset, - query=urlencode({'q': query}), - lang=language) - - return params - - -# get response from search-request -def response(resp): - results = [] - - search_res = loads(resp.text) - - # return empty array if there are no results - if not search_res.get('responseData', {}).get('results'): - return [] - - # parse results - for result in search_res['responseData']['results']: - # parse publishedDate - publishedDate = parser.parse(result['publishedDate']) - if 'url' not in result: - continue - - # append result - results.append({'url': result['unescapedUrl'], - 'title': result['titleNoFormatting'], - 'publishedDate': publishedDate, - 'content': result['content']}) - - # return results - return results diff --git a/sources/searx/engines/json_engine.py b/sources/searx/engines/json_engine.py deleted file mode 100644 index 5525b7f..0000000 --- a/sources/searx/engines/json_engine.py +++ /dev/null @@ -1,87 +0,0 @@ -from urllib import urlencode -from json import loads -from collections import Iterable - -search_url = None -url_query = None -content_query = None -title_query = None -# suggestion_xpath = '' - - -def iterate(iterable): - if type(iterable) == dict: - it = iterable.iteritems() - - else: - it = enumerate(iterable) - for index, value in it: - yield str(index), value - - -def is_iterable(obj): - if type(obj) == str: - return False - if type(obj) == unicode: - return False - return isinstance(obj, Iterable) - - -def parse(query): - q = [] - for part in query.split('/'): - if part == '': - continue - else: - q.append(part) - return q - - -def do_query(data, q): - ret = [] - if not q: - return ret - - qkey = q[0] - - for key, value in iterate(data): - - if len(q) == 1: - if key == qkey: - ret.append(value) - elif is_iterable(value): - ret.extend(do_query(value, q)) - else: - if not is_iterable(value): - continue - if key == qkey: - ret.extend(do_query(value, q[1:])) - else: - ret.extend(do_query(value, q)) - return ret - - -def query(data, query_string): - q = parse(query_string) - - return do_query(data, q) - - -def request(query, params): - query = urlencode({'q': query})[2:] - params['url'] = search_url.format(query=query) - params['query'] = query - return params - - -def response(resp): - results = [] - - json = loads(resp.text) - - urls = query(json, url_query) - contents = query(json, content_query) - titles = query(json, title_query) - for url, title, content in zip(urls, titles, contents): - results.append({'url': url, 'title': title, 'content': content}) - return results diff --git a/sources/searx/engines/kickass.py b/sources/searx/engines/kickass.py deleted file mode 100644 index 4c5d240..0000000 --- a/sources/searx/engines/kickass.py +++ /dev/null @@ -1,118 +0,0 @@ -""" - Kickass Torrent (Videos, Music, Files) - - @website https://kickass.so - @provide-api no (nothing found) - - @using-api no - @results HTML (using search portal) - @stable yes (HTML can change) - @parse url, title, content, seed, leech, magnetlink -""" - -from urlparse import urljoin -from cgi import escape -from urllib import quote -from lxml import html -from operator import itemgetter -from searx.engines.xpath import extract_text - -# engine dependent config -categories = ['videos', 'music', 'files'] -paging = True - -# search-url -url = 'https://kickass.to/' -search_url = url + 'search/{search_term}/{pageno}/' - -# specific xpath variables -magnet_xpath = './/a[@title="Torrent magnet link"]' -torrent_xpath = './/a[@title="Download torrent file"]' -content_xpath = './/span[@class="font11px lightgrey block"]' - - -# do search-request -def request(query, params): - params['url'] = search_url.format(search_term=quote(query), - pageno=params['pageno']) - - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - - search_res = dom.xpath('//table[@class="data"]//tr') - - # return empty array if nothing is found - if not search_res: - return [] - - # parse results - for result in search_res[1:]: - link = result.xpath('.//a[@class="cellMainLink"]')[0] - href = urljoin(url, link.attrib['href']) - title = extract_text(link) - content = escape(extract_text(result.xpath(content_xpath))) - seed = result.xpath('.//td[contains(@class, "green")]/text()')[0] - leech = result.xpath('.//td[contains(@class, "red")]/text()')[0] - filesize = result.xpath('.//td[contains(@class, "nobr")]/text()')[0] - filesize_multiplier = result.xpath('.//td[contains(@class, "nobr")]//span/text()')[0] - files = result.xpath('.//td[contains(@class, "center")][2]/text()')[0] - - # convert seed to int if possible - if seed.isdigit(): - seed = int(seed) - else: - seed = 0 - - # convert leech to int if possible - if leech.isdigit(): - leech = int(leech) - else: - leech = 0 - - # convert filesize to byte if possible - try: - filesize = float(filesize) - - # convert filesize to byte - if filesize_multiplier == 'TB': - filesize = int(filesize * 1024 * 1024 * 1024 * 1024) - elif filesize_multiplier == 'GB': - filesize = int(filesize * 1024 * 1024 * 1024) - elif filesize_multiplier == 'MB': - filesize = int(filesize * 1024 * 1024) - elif filesize_multiplier == 'KB': - filesize = int(filesize * 1024) - except: - filesize = None - - # convert files to int if possible - if files.isdigit(): - files = int(files) - else: - files = None - - magnetlink = result.xpath(magnet_xpath)[0].attrib['href'] - - torrentfile = result.xpath(torrent_xpath)[0].attrib['href'] - torrentfileurl = quote(torrentfile, safe="%/:=&?~#+!$,;'@()*") - - # append result - results.append({'url': href, - 'title': title, - 'content': content, - 'seed': seed, - 'leech': leech, - 'filesize': filesize, - 'files': files, - 'magnetlink': magnetlink, - 'torrentfile': torrentfileurl, - 'template': 'torrent.html'}) - - # return results sorted by seeder - return sorted(results, key=itemgetter('seed'), reverse=True) diff --git a/sources/searx/engines/mediawiki.py b/sources/searx/engines/mediawiki.py deleted file mode 100644 index 26d3720..0000000 --- a/sources/searx/engines/mediawiki.py +++ /dev/null @@ -1,88 +0,0 @@ -""" - general mediawiki-engine (Web) - - @website websites built on mediawiki (https://www.mediawiki.org) - @provide-api yes (http://www.mediawiki.org/wiki/API:Search) - - @using-api yes - @results JSON - @stable yes - @parse url, title - - @todo content -""" - -from json import loads -from string import Formatter -from urllib import urlencode, quote - -# engine dependent config -categories = ['general'] -language_support = True -paging = True -number_of_results = 1 - -# search-url -base_url = 'https://{language}.wikipedia.org/' -search_postfix = 'w/api.php?action=query'\ - '&list=search'\ - '&{query}'\ - '&format=json'\ - '&sroffset={offset}'\ - '&srlimit={limit}'\ - '&srwhat=nearmatch' # search for a near match in the title - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * number_of_results - - string_args = dict(query=urlencode({'srsearch': query}), - offset=offset, - limit=number_of_results) - - format_strings = list(Formatter().parse(base_url)) - - if params['language'] == 'all': - language = 'en' - else: - language = params['language'].split('_')[0] - - # format_string [('https://', 'language', '', None), ('.wikipedia.org/', None, None, None)] - if any(x[1] == 'language' for x in format_strings): - string_args['language'] = language - - # write search-language back to params, required in response - params['language'] = language - - search_url = base_url + search_postfix - - params['url'] = search_url.format(**string_args) - - return params - - -# get response from search-request -def response(resp): - results = [] - - search_results = loads(resp.text) - - # return empty array if there are no results - if not search_results.get('query', {}).get('search'): - return [] - - # parse results - for result in search_results['query']['search']: - if result.get('snippet', '').startswith('#REDIRECT'): - continue - url = base_url.format(language=resp.search_params['language']) +\ - 'wiki/' + quote(result['title'].replace(' ', '_').encode('utf-8')) - - # append result - results.append({'url': url, - 'title': result['title'], - 'content': ''}) - - # return results - return results diff --git a/sources/searx/engines/mixcloud.py b/sources/searx/engines/mixcloud.py deleted file mode 100644 index 312d297..0000000 --- a/sources/searx/engines/mixcloud.py +++ /dev/null @@ -1,61 +0,0 @@ -""" - Mixcloud (Music) - - @website https://http://www.mixcloud.com/ - @provide-api yes (http://www.mixcloud.com/developers/ - - @using-api yes - @results JSON - @stable yes - @parse url, title, content, embedded, publishedDate -""" - -from json import loads -from urllib import urlencode -from dateutil import parser - -# engine dependent config -categories = ['music'] -paging = True - -# search-url -url = 'https://api.mixcloud.com/' -search_url = url + 'search/?{query}&type=cloudcast&limit=10&offset={offset}' - -embedded_url = '' - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 10 - - params['url'] = search_url.format(query=urlencode({'q': query}), - offset=offset) - - return params - - -# get response from search-request -def response(resp): - results = [] - - search_res = loads(resp.text) - - # parse results - for result in search_res.get('data', []): - title = result['name'] - url = result['url'] - content = result['user']['name'] - embedded = embedded_url.format(url=url) - publishedDate = parser.parse(result['created_time']) - - # append result - results.append({'url': url, - 'title': title, - 'embedded': embedded, - 'publishedDate': publishedDate, - 'content': content}) - - # return results - return results diff --git a/sources/searx/engines/nyaa.py b/sources/searx/engines/nyaa.py deleted file mode 100644 index cda8231..0000000 --- a/sources/searx/engines/nyaa.py +++ /dev/null @@ -1,119 +0,0 @@ -""" - Nyaa.se (Anime Bittorrent tracker) - - @website http://www.nyaa.se/ - @provide-api no - @using-api no - @results HTML - @stable no (HTML can change) - @parse url, title, content, seed, leech, torrentfile -""" - -from cgi import escape -from urllib import urlencode -from lxml import html -from searx.engines.xpath import extract_text - -# engine dependent config -categories = ['files', 'images', 'videos', 'music'] -paging = True - -# search-url -base_url = 'http://www.nyaa.se/' -search_url = base_url + '?page=search&{query}&offset={offset}' - -# xpath queries -xpath_results = '//table[@class="tlist"]//tr[contains(@class, "tlistrow")]' -xpath_category = './/td[@class="tlisticon"]/a' -xpath_title = './/td[@class="tlistname"]/a' -xpath_torrent_file = './/td[@class="tlistdownload"]/a' -xpath_filesize = './/td[@class="tlistsize"]/text()' -xpath_seeds = './/td[@class="tlistsn"]/text()' -xpath_leeches = './/td[@class="tlistln"]/text()' -xpath_downloads = './/td[@class="tlistdn"]/text()' - - -# convert a variable to integer or return 0 if it's not a number -def int_or_zero(num): - if isinstance(num, list): - if len(num) < 1: - return 0 - num = num[0] - if num.isdigit(): - return int(num) - return 0 - - -# get multiplier to convert torrent size to bytes -def get_filesize_mul(suffix): - return { - 'KB': 1024, - 'MB': 1024 ** 2, - 'GB': 1024 ** 3, - 'TB': 1024 ** 4, - - 'KIB': 1024, - 'MIB': 1024 ** 2, - 'GIB': 1024 ** 3, - 'TIB': 1024 ** 4 - }[str(suffix).upper()] - - -# do search-request -def request(query, params): - query = urlencode({'term': query}) - params['url'] = search_url.format(query=query, offset=params['pageno']) - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - - for result in dom.xpath(xpath_results): - # category in which our torrent belongs - category = result.xpath(xpath_category)[0].attrib.get('title') - - # torrent title - page_a = result.xpath(xpath_title)[0] - title = escape(extract_text(page_a)) - - # link to the page - href = page_a.attrib.get('href') - - # link to the torrent file - torrent_link = result.xpath(xpath_torrent_file)[0].attrib.get('href') - - # torrent size - try: - file_size, suffix = result.xpath(xpath_filesize)[0].split(' ') - file_size = int(float(file_size) * get_filesize_mul(suffix)) - except Exception as e: - file_size = None - - # seed count - seed = int_or_zero(result.xpath(xpath_seeds)) - - # leech count - leech = int_or_zero(result.xpath(xpath_leeches)) - - # torrent downloads count - downloads = int_or_zero(result.xpath(xpath_downloads)) - - # content string contains all information not included into template - content = 'Category: "{category}". Downloaded {downloads} times.' - content = content.format(category=category, downloads=downloads) - content = escape(content) - - results.append({'url': href, - 'title': title, - 'content': content, - 'seed': seed, - 'leech': leech, - 'filesize': file_size, - 'torrentfile': torrent_link, - 'template': 'torrent.html'}) - - return results diff --git a/sources/searx/engines/openstreetmap.py b/sources/searx/engines/openstreetmap.py deleted file mode 100644 index 38baaad..0000000 --- a/sources/searx/engines/openstreetmap.py +++ /dev/null @@ -1,99 +0,0 @@ -""" - OpenStreetMap (Map) - - @website https://openstreetmap.org/ - @provide-api yes (http://wiki.openstreetmap.org/wiki/Nominatim) - - @using-api yes - @results JSON - @stable yes - @parse url, title -""" - -from json import loads -from searx.utils import searx_useragent - -# engine dependent config -categories = ['map'] -paging = False - -# search-url -base_url = 'https://nominatim.openstreetmap.org/' -search_string = 'search/{query}?format=json&polygon_geojson=1&addressdetails=1' -result_base_url = 'https://openstreetmap.org/{osm_type}/{osm_id}' - - -# do search-request -def request(query, params): - params['url'] = base_url + search_string.format(query=query) - - # using searx User-Agent - params['headers']['User-Agent'] = searx_useragent() - - return params - - -# get response from search-request -def response(resp): - results = [] - json = loads(resp.text) - - # parse results - for r in json: - if 'display_name' not in r: - continue - - title = r['display_name'] - osm_type = r.get('osm_type', r.get('type')) - url = result_base_url.format(osm_type=osm_type, - osm_id=r['osm_id']) - - osm = {'type': osm_type, - 'id': r['osm_id']} - - geojson = r.get('geojson') - - # if no geojson is found and osm_type is a node, add geojson Point - if not geojson and osm_type == 'node': - geojson = {u'type': u'Point', u'coordinates': [r['lon'], r['lat']]} - - address_raw = r.get('address') - address = {} - - # get name - if r['class'] == 'amenity' or\ - r['class'] == 'shop' or\ - r['class'] == 'tourism' or\ - r['class'] == 'leisure': - if address_raw.get('address29'): - address = {'name': address_raw.get('address29')} - else: - address = {'name': address_raw.get(r['type'])} - - # add rest of adressdata, if something is already found - if address.get('name'): - address.update({'house_number': address_raw.get('house_number'), - 'road': address_raw.get('road'), - 'locality': address_raw.get('city', - address_raw.get('town', # noqa - address_raw.get('village'))), # noqa - 'postcode': address_raw.get('postcode'), - 'country': address_raw.get('country'), - 'country_code': address_raw.get('country_code')}) - else: - address = None - - # append result - results.append({'template': 'map.html', - 'title': title, - 'content': '', - 'longitude': r['lon'], - 'latitude': r['lat'], - 'boundingbox': r['boundingbox'], - 'geojson': geojson, - 'address': address, - 'osm': osm, - 'url': url}) - - # return results - return results diff --git a/sources/searx/engines/photon.py b/sources/searx/engines/photon.py deleted file mode 100644 index 2197005..0000000 --- a/sources/searx/engines/photon.py +++ /dev/null @@ -1,131 +0,0 @@ -""" - Photon (Map) - - @website https://photon.komoot.de - @provide-api yes (https://photon.komoot.de/) - - @using-api yes - @results JSON - @stable yes - @parse url, title -""" - -from urllib import urlencode -from json import loads -from searx.utils import searx_useragent - -# engine dependent config -categories = ['map'] -paging = False -language_support = True -number_of_results = 10 - -# search-url -base_url = 'https://photon.komoot.de/' -search_string = 'api/?{query}&limit={limit}' -result_base_url = 'https://openstreetmap.org/{osm_type}/{osm_id}' - -# list of supported languages -allowed_languages = ['de', 'en', 'fr', 'it'] - - -# do search-request -def request(query, params): - params['url'] = base_url +\ - search_string.format(query=urlencode({'q': query}), - limit=number_of_results) - - if params['language'] != 'all': - language = params['language'].split('_')[0] - if language in allowed_languages: - params['url'] = params['url'] + "&lang=" + language - - # using searx User-Agent - params['headers']['User-Agent'] = searx_useragent() - - return params - - -# get response from search-request -def response(resp): - results = [] - json = loads(resp.text) - - # parse results - for r in json.get('features', {}): - - properties = r.get('properties') - - if not properties: - continue - - # get title - title = properties.get('name') - - # get osm-type - if properties.get('osm_type') == 'N': - osm_type = 'node' - elif properties.get('osm_type') == 'W': - osm_type = 'way' - elif properties.get('osm_type') == 'R': - osm_type = 'relation' - else: - # continue if invalide osm-type - continue - - url = result_base_url.format(osm_type=osm_type, - osm_id=properties.get('osm_id')) - - osm = {'type': osm_type, - 'id': properties.get('osm_id')} - - geojson = r.get('geometry') - - if properties.get('extent'): - boundingbox = [properties.get('extent')[3], - properties.get('extent')[1], - properties.get('extent')[0], - properties.get('extent')[2]] - else: - # TODO: better boundingbox calculation - boundingbox = [geojson['coordinates'][1], - geojson['coordinates'][1], - geojson['coordinates'][0], - geojson['coordinates'][0]] - - # address calculation - address = {} - - # get name - if properties.get('osm_key') == 'amenity' or\ - properties.get('osm_key') == 'shop' or\ - properties.get('osm_key') == 'tourism' or\ - properties.get('osm_key') == 'leisure': - address = {'name': properties.get('name')} - - # add rest of adressdata, if something is already found - if address.get('name'): - address.update({'house_number': properties.get('housenumber'), - 'road': properties.get('street'), - 'locality': properties.get('city', - properties.get('town', # noqa - properties.get('village'))), # noqa - 'postcode': properties.get('postcode'), - 'country': properties.get('country')}) - else: - address = None - - # append result - results.append({'template': 'map.html', - 'title': title, - 'content': '', - 'longitude': geojson['coordinates'][0], - 'latitude': geojson['coordinates'][1], - 'boundingbox': boundingbox, - 'geojson': geojson, - 'address': address, - 'osm': osm, - 'url': url}) - - # return results - return results diff --git a/sources/searx/engines/piratebay.py b/sources/searx/engines/piratebay.py deleted file mode 100644 index 55446b4..0000000 --- a/sources/searx/engines/piratebay.py +++ /dev/null @@ -1,98 +0,0 @@ -# Piratebay (Videos, Music, Files) -# -# @website https://thepiratebay.se -# @provide-api no (nothing found) -# -# @using-api no -# @results HTML (using search portal) -# @stable yes (HTML can change) -# @parse url, title, content, seed, leech, magnetlink - -from urlparse import urljoin -from cgi import escape -from urllib import quote -from lxml import html -from operator import itemgetter -from searx.engines.xpath import extract_text - -# engine dependent config -categories = ['videos', 'music', 'files'] -paging = True - -# search-url -url = 'https://thepiratebay.se/' -search_url = url + 'search/{search_term}/{pageno}/99/{search_type}' - -# piratebay specific type-definitions -search_types = {'files': '0', - 'music': '100', - 'videos': '200'} - -# specific xpath variables -magnet_xpath = './/a[@title="Download this torrent using magnet"]' -torrent_xpath = './/a[@title="Download this torrent"]' -content_xpath = './/font[@class="detDesc"]' - - -# do search-request -def request(query, params): - search_type = search_types.get(params['category'], '0') - - params['url'] = search_url.format(search_term=quote(query), - search_type=search_type, - pageno=params['pageno'] - 1) - - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - - search_res = dom.xpath('//table[@id="searchResult"]//tr') - - # return empty array if nothing is found - if not search_res: - return [] - - # parse results - for result in search_res[1:]: - link = result.xpath('.//div[@class="detName"]//a')[0] - href = urljoin(url, link.attrib.get('href')) - title = extract_text(link) - content = escape(extract_text(result.xpath(content_xpath))) - seed, leech = result.xpath('.//td[@align="right"]/text()')[:2] - - # convert seed to int if possible - if seed.isdigit(): - seed = int(seed) - else: - seed = 0 - - # convert leech to int if possible - if leech.isdigit(): - leech = int(leech) - else: - leech = 0 - - magnetlink = result.xpath(magnet_xpath)[0] - torrentfile_links = result.xpath(torrent_xpath) - if torrentfile_links: - torrentfile_link = torrentfile_links[0].attrib.get('href') - else: - torrentfile_link = None - - # append result - results.append({'url': href, - 'title': title, - 'content': content, - 'seed': seed, - 'leech': leech, - 'magnetlink': magnetlink.attrib.get('href'), - 'torrentfile': torrentfile_link, - 'template': 'torrent.html'}) - - # return results sorted by seeder - return sorted(results, key=itemgetter('seed'), reverse=True) diff --git a/sources/searx/engines/qwant.py b/sources/searx/engines/qwant.py deleted file mode 100644 index 872bd4e..0000000 --- a/sources/searx/engines/qwant.py +++ /dev/null @@ -1,98 +0,0 @@ -""" - Qwant (Web, Images, News, Social) - - @website https://qwant.com/ - @provide-api not officially (https://api.qwant.com/api/search/) - - @using-api yes - @results JSON - @stable yes - @parse url, title, content -""" - -from urllib import urlencode -from json import loads -from datetime import datetime - -# engine dependent config -categories = None -paging = True -language_support = True - -category_to_keyword = {'general': 'web', - 'images': 'images', - 'news': 'news', - 'social media': 'social'} - -# search-url -url = 'https://api.qwant.com/api/search/{keyword}?count=10&offset={offset}&f=&{query}' - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 10 - - if categories[0] and categories[0] in category_to_keyword: - - params['url'] = url.format(keyword=category_to_keyword[categories[0]], - query=urlencode({'q': query}), - offset=offset) - else: - params['url'] = url.format(keyword='web', - query=urlencode({'q': query}), - offset=offset) - - # add language tag if specified - if params['language'] != 'all': - params['url'] += '&locale=' + params['language'].lower() - - return params - - -# get response from search-request -def response(resp): - results = [] - - search_results = loads(resp.text) - - # return empty array if there are no results - if 'data' not in search_results: - return [] - - data = search_results.get('data', {}) - - res = data.get('result', {}) - - # parse results - for result in res.get('items', {}): - - title = result['title'] - res_url = result['url'] - content = result['desc'] - - if category_to_keyword.get(categories[0], '') == 'web': - results.append({'title': title, - 'content': content, - 'url': res_url}) - - elif category_to_keyword.get(categories[0], '') == 'images': - thumbnail_src = result['thumbnail'] - img_src = result['media'] - results.append({'template': 'images.html', - 'url': res_url, - 'title': title, - 'content': '', - 'thumbnail_src': thumbnail_src, - 'img_src': img_src}) - - elif (category_to_keyword.get(categories[0], '') == 'news' or - category_to_keyword.get(categories[0], '') == 'social'): - published_date = datetime.fromtimestamp(result['date'], None) - - results.append({'url': res_url, - 'title': title, - 'publishedDate': published_date, - 'content': content}) - - # return results - return results diff --git a/sources/searx/engines/reddit.py b/sources/searx/engines/reddit.py deleted file mode 100644 index 3ca7e44..0000000 --- a/sources/searx/engines/reddit.py +++ /dev/null @@ -1,79 +0,0 @@ -""" - Reddit - - @website https://www.reddit.com/ - @provide-api yes (https://www.reddit.com/dev/api) - - @using-api yes - @results JSON - @stable yes - @parse url, title, content, thumbnail, publishedDate -""" - -import json -from cgi import escape -from urllib import urlencode -from urlparse import urlparse, urljoin -from datetime import datetime - -# engine dependent config -categories = ['general', 'images', 'news', 'social media'] -page_size = 25 - -# search-url -base_url = 'https://www.reddit.com/' -search_url = base_url + 'search.json?{query}' - - -# do search-request -def request(query, params): - query = urlencode({'q': query, - 'limit': page_size}) - params['url'] = search_url.format(query=query) - - return params - - -# get response from search-request -def response(resp): - img_results = [] - text_results = [] - - search_results = json.loads(resp.text) - - # return empty array if there are no results - if 'data' not in search_results: - return [] - - posts = search_results.get('data', {}).get('children', []) - - # process results - for post in posts: - data = post['data'] - - # extract post information - params = { - 'url': urljoin(base_url, data['permalink']), - 'title': data['title'] - } - - # if thumbnail field contains a valid URL, we need to change template - thumbnail = data['thumbnail'] - url_info = urlparse(thumbnail) - # netloc & path - if url_info[1] != '' and url_info[2] != '': - params['img_src'] = data['url'] - params['thumbnail_src'] = thumbnail - params['template'] = 'images.html' - img_results.append(params) - else: - created = datetime.fromtimestamp(data['created_utc']) - content = escape(data['selftext']) - if len(content) > 500: - content = content[:500] + '...' - params['content'] = content - params['publishedDate'] = created - text_results.append(params) - - # show images first and text results second - return img_results + text_results diff --git a/sources/searx/engines/searchcode_code.py b/sources/searx/engines/searchcode_code.py deleted file mode 100644 index de8cd43..0000000 --- a/sources/searx/engines/searchcode_code.py +++ /dev/null @@ -1,75 +0,0 @@ -""" - Searchcode (It) - - @website https://searchcode.com/ - @provide-api yes (https://searchcode.com/api/) - - @using-api yes - @results JSON - @stable yes - @parse url, title, content -""" - -from urllib import urlencode -from json import loads - - -# engine dependent config -categories = ['it'] -paging = True - -# search-url -url = 'https://searchcode.com/' -search_url = url + 'api/codesearch_I/?{query}&p={pageno}' - -# special code-endings which are not recognised by the file ending -code_endings = {'cs': 'c#', - 'h': 'c', - 'hpp': 'cpp', - 'cxx': 'cpp'} - - -# do search-request -def request(query, params): - params['url'] = search_url.format(query=urlencode({'q': query}), - pageno=params['pageno'] - 1) - - # Disable SSL verification - # error: (60) SSL certificate problem: unable to get local issuer - # certificate - params['verify'] = False - - return params - - -# get response from search-request -def response(resp): - results = [] - - search_results = loads(resp.text) - - # parse results - for result in search_results.get('results', []): - href = result['url'] - title = "" + result['name'] + " - " + result['filename'] - repo = result['repo'] - - lines = dict() - for line, code in result['lines'].items(): - lines[int(line)] = code - - code_language = code_endings.get( - result['filename'].split('.')[-1].lower(), - result['filename'].split('.')[-1].lower()) - - # append result - results.append({'url': href, - 'title': title, - 'content': '', - 'repository': repo, - 'codelines': sorted(lines.items()), - 'code_language': code_language, - 'template': 'code.html'}) - - # return results - return results diff --git a/sources/searx/engines/searchcode_doc.py b/sources/searx/engines/searchcode_doc.py deleted file mode 100644 index f24fe6f..0000000 --- a/sources/searx/engines/searchcode_doc.py +++ /dev/null @@ -1,63 +0,0 @@ -""" - Searchcode (It) - - @website https://searchcode.com/ - @provide-api yes (https://searchcode.com/api/) - - @using-api yes - @results JSON - @stable yes - @parse url, title, content -""" - -from urllib import urlencode -from json import loads - -# engine dependent config -categories = ['it'] -paging = True - -# search-url -url = 'https://searchcode.com/' -search_url = url + 'api/search_IV/?{query}&p={pageno}' - - -# do search-request -def request(query, params): - params['url'] = search_url.format(query=urlencode({'q': query}), - pageno=params['pageno'] - 1) - - # Disable SSL verification - # error: (60) SSL certificate problem: unable to get local issuer - # certificate - params['verify'] = False - - return params - - -# get response from search-request -def response(resp): - results = [] - - search_results = loads(resp.text) - - # parse results - for result in search_results.get('results', []): - href = result['url'] - title = "[" + result['type'] + "] " +\ - result['namespace'] +\ - " " + result['name'] - content = '[' +\ - result['type'] + "] " +\ - result['name'] + " " +\ - result['synopsis'] +\ - "
" +\ - result['description'] - - # append result - results.append({'url': href, - 'title': title, - 'content': content}) - - # return results - return results diff --git a/sources/searx/engines/soundcloud.py b/sources/searx/engines/soundcloud.py deleted file mode 100644 index ac23c1e..0000000 --- a/sources/searx/engines/soundcloud.py +++ /dev/null @@ -1,98 +0,0 @@ -""" - Soundcloud (Music) - - @website https://soundcloud.com - @provide-api yes (https://developers.soundcloud.com/) - - @using-api yes - @results JSON - @stable yes - @parse url, title, content, publishedDate, embedded -""" - -import re -from StringIO import StringIO -from json import loads -from lxml import etree -from urllib import urlencode, quote_plus -from dateutil import parser -from searx import logger -from searx.poolrequests import get as http_get - -# engine dependent config -categories = ['music'] -paging = True - -# search-url -url = 'https://api.soundcloud.com/' -search_url = url + 'search?{query}'\ - '&facet=model'\ - '&limit=20'\ - '&offset={offset}'\ - '&linked_partitioning=1'\ - '&client_id={client_id}' # noqa - -embedded_url = '' - - -def get_client_id(): - response = http_get("https://soundcloud.com") - rx_namespace = {"re": "http://exslt.org/regular-expressions"} - - if response.ok: - tree = etree.parse(StringIO(response.content), etree.HTMLParser()) - script_tags = tree.xpath("//script[re:match(@src, '(.*app.*js)')]", namespaces=rx_namespace) - app_js_urls = [script_tag.get('src') for script_tag in script_tags if script_tag is not None] - - # extracts valid app_js urls from soundcloud.com content - for app_js_url in app_js_urls: - # gets app_js and searches for the clientid - response = http_get(app_js_url) - if response.ok: - cids = re.search(r'client_id:"([^"]*)"', response.content, re.M | re.I) - if cids is not None and len(cids.groups()): - return cids.groups()[0] - logger.warning("Unable to fetch guest client_id from SoundCloud, check parser!") - return "" - -# api-key -guest_client_id = get_client_id() - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 20 - - params['url'] = search_url.format(query=urlencode({'q': query}), - offset=offset, - client_id=guest_client_id) - - return params - - -# get response from search-request -def response(resp): - results = [] - - search_res = loads(resp.text) - - # parse results - for result in search_res.get('collection', []): - if result['kind'] in ('track', 'playlist'): - title = result['title'] - content = result['description'] - publishedDate = parser.parse(result['last_modified']) - uri = quote_plus(result['uri']) - embedded = embedded_url.format(uri=uri) - - # append result - results.append({'url': result['permalink_url'], - 'title': title, - 'publishedDate': publishedDate, - 'embedded': embedded, - 'content': content}) - - # return results - return results diff --git a/sources/searx/engines/spotify.py b/sources/searx/engines/spotify.py deleted file mode 100644 index f75796e..0000000 --- a/sources/searx/engines/spotify.py +++ /dev/null @@ -1,62 +0,0 @@ -""" - Spotify (Music) - - @website https://spotify.com - @provide-api yes (https://developer.spotify.com/web-api/search-item/) - - @using-api yes - @results JSON - @stable yes - @parse url, title, content, embedded -""" - -from json import loads -from urllib import urlencode - -# engine dependent config -categories = ['music'] -paging = True - -# search-url -url = 'https://api.spotify.com/' -search_url = url + 'v1/search?{query}&type=track&offset={offset}' - -embedded_url = '' - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 20 - - params['url'] = search_url.format(query=urlencode({'q': query}), - offset=offset) - - return params - - -# get response from search-request -def response(resp): - results = [] - - search_res = loads(resp.text) - - # parse results - for result in search_res.get('tracks', {}).get('items', {}): - if result['type'] == 'track': - title = result['name'] - url = result['external_urls']['spotify'] - content = result['artists'][0]['name'] +\ - " • " +\ - result['album']['name'] +\ - " • " + result['name'] - embedded = embedded_url.format(audioid=result['id']) - - # append result - results.append({'url': url, - 'title': title, - 'embedded': embedded, - 'content': content}) - - # return results - return results diff --git a/sources/searx/engines/stackoverflow.py b/sources/searx/engines/stackoverflow.py deleted file mode 100644 index fdd3711..0000000 --- a/sources/searx/engines/stackoverflow.py +++ /dev/null @@ -1,60 +0,0 @@ -""" - Stackoverflow (It) - - @website https://stackoverflow.com/ - @provide-api not clear (https://api.stackexchange.com/docs/advanced-search) - - @using-api no - @results HTML - @stable no (HTML can change) - @parse url, title, content -""" - -from urlparse import urljoin -from cgi import escape -from urllib import urlencode -from lxml import html -from searx.engines.xpath import extract_text - -# engine dependent config -categories = ['it'] -paging = True - -# search-url -url = 'https://stackoverflow.com/' -search_url = url + 'search?{query}&page={pageno}' - -# specific xpath variables -results_xpath = '//div[contains(@class,"question-summary")]' -link_xpath = './/div[@class="result-link"]//a|.//div[@class="summary"]//h3//a' -content_xpath = './/div[@class="excerpt"]' - - -# do search-request -def request(query, params): - params['url'] = search_url.format(query=urlencode({'q': query}), - pageno=params['pageno']) - - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - - # parse results - for result in dom.xpath(results_xpath): - link = result.xpath(link_xpath)[0] - href = urljoin(url, link.attrib.get('href')) - title = escape(extract_text(link)) - content = escape(extract_text(result.xpath(content_xpath))) - - # append result - results.append({'url': href, - 'title': title, - 'content': content}) - - # return results - return results diff --git a/sources/searx/engines/startpage.py b/sources/searx/engines/startpage.py deleted file mode 100644 index 52dd0b9..0000000 --- a/sources/searx/engines/startpage.py +++ /dev/null @@ -1,124 +0,0 @@ -# Startpage (Web) -# -# @website https://startpage.com -# @provide-api no (nothing found) -# -# @using-api no -# @results HTML -# @stable no (HTML can change) -# @parse url, title, content -# -# @todo paging - -from lxml import html -from cgi import escape -from dateutil import parser -from datetime import datetime, timedelta -import re -from searx.engines.xpath import extract_text - -# engine dependent config -categories = ['general'] -# there is a mechanism to block "bot" search -# (probably the parameter qid), require -# storing of qid's between mulitble search-calls - -# paging = False -language_support = True - -# search-url -base_url = 'https://startpage.com/' -search_url = base_url + 'do/search' - -# specific xpath variables -# ads xpath //div[@id="results"]/div[@id="sponsored"]//div[@class="result"] -# not ads: div[@class="result"] are the direct childs of div[@id="results"] -results_xpath = '//div[@class="result"]' -link_xpath = './/h3/a' - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 10 - - params['url'] = search_url - params['method'] = 'POST' - params['data'] = {'query': query, - 'startat': offset} - - # set language if specified - if params['language'] != 'all': - params['data']['with_language'] = ('lang_' + params['language'].split('_')[0]) - - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.content) - - # parse results - for result in dom.xpath(results_xpath): - links = result.xpath(link_xpath) - if not links: - continue - link = links[0] - url = link.attrib.get('href') - - # block google-ad url's - if re.match("^http(s|)://(www\.)?google\.[a-z]+/aclk.*$", url): - continue - - # block startpage search url's - if re.match("^http(s|)://(www\.)?startpage\.com/do/search\?.*$", url): - continue - - # block ixquick search url's - if re.match("^http(s|)://(www\.)?ixquick\.com/do/search\?.*$", url): - continue - - title = escape(extract_text(link)) - - if result.xpath('./p[@class="desc clk"]'): - content = escape(extract_text(result.xpath('./p[@class="desc clk"]'))) - else: - content = '' - - published_date = None - - # check if search result starts with something like: "2 Sep 2014 ... " - if re.match("^([1-9]|[1-2][0-9]|3[0-1]) [A-Z][a-z]{2} [0-9]{4} \.\.\. ", content): - date_pos = content.find('...') + 4 - date_string = content[0:date_pos - 5] - published_date = parser.parse(date_string, dayfirst=True) - - # fix content string - content = content[date_pos:] - - # check if search result starts with something like: "5 days ago ... " - elif re.match("^[0-9]+ days? ago \.\.\. ", content): - date_pos = content.find('...') + 4 - date_string = content[0:date_pos - 5] - - # calculate datetime - published_date = datetime.now() - timedelta(days=int(re.match(r'\d+', date_string).group())) - - # fix content string - content = content[date_pos:] - - if published_date: - # append result - results.append({'url': url, - 'title': title, - 'content': content, - 'publishedDate': published_date}) - else: - # append result - results.append({'url': url, - 'title': title, - 'content': content}) - - # return results - return results diff --git a/sources/searx/engines/subtitleseeker.py b/sources/searx/engines/subtitleseeker.py deleted file mode 100644 index 47d27d0..0000000 --- a/sources/searx/engines/subtitleseeker.py +++ /dev/null @@ -1,81 +0,0 @@ -""" - Subtitleseeker (Video) - - @website http://www.subtitleseeker.com - @provide-api no - - @using-api no - @results HTML - @stable no (HTML can change) - @parse url, title, content -""" - -from cgi import escape -from urllib import quote_plus -from lxml import html -from searx.languages import language_codes -from searx.engines.xpath import extract_text - -# engine dependent config -categories = ['videos'] -paging = True -language = "" - -# search-url -url = 'http://www.subtitleseeker.com/' -search_url = url + 'search/TITLES/{query}&p={pageno}' - -# specific xpath variables -results_xpath = '//div[@class="boxRows"]' - - -# do search-request -def request(query, params): - params['url'] = search_url.format(query=quote_plus(query), - pageno=params['pageno']) - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - - search_lang = "" - - if resp.search_params['language'] != 'all': - search_lang = [lc[1] - for lc in language_codes - if lc[0][:2] == resp.search_params['language'].split('_')[0]][0] - - # parse results - for result in dom.xpath(results_xpath): - link = result.xpath(".//a")[0] - href = link.attrib.get('href') - - if language is not "": - href = href + language + '/' - elif search_lang: - href = href + search_lang + '/' - - title = escape(extract_text(link)) - - content = extract_text(result.xpath('.//div[contains(@class,"red")]')) - content = content + " - " - text = extract_text(result.xpath('.//div[contains(@class,"grey-web")]')[0]) - content = content + text - - if result.xpath(".//span") != []: - content = content +\ - " - (" +\ - extract_text(result.xpath(".//span")) +\ - ")" - - # append result - results.append({'url': href, - 'title': title, - 'content': escape(content)}) - - # return results - return results diff --git a/sources/searx/engines/swisscows.py b/sources/searx/engines/swisscows.py deleted file mode 100644 index 864436a..0000000 --- a/sources/searx/engines/swisscows.py +++ /dev/null @@ -1,109 +0,0 @@ -""" - Swisscows (Web, Images) - - @website https://swisscows.ch - @provide-api no - - @using-api no - @results HTML (using search portal) - @stable no (HTML can change) - @parse url, title, content -""" - -from cgi import escape -from json import loads -from urllib import urlencode, unquote -import re - -# engine dependent config -categories = ['general', 'images'] -paging = True -language_support = True - -# search-url -base_url = 'https://swisscows.ch/' -search_string = '?{query}&page={page}' - -# regex -regex_json = re.compile('initialData: {"Request":(.|\n)*},\s*environment') -regex_json_remove_start = re.compile('^initialData:\s*') -regex_json_remove_end = re.compile(',\s*environment$') -regex_img_url_remove_start = re.compile('^https?://i\.swisscows\.ch/\?link=') - - -# do search-request -def request(query, params): - if params['language'] == 'all': - ui_language = 'browser' - region = 'browser' - else: - region = params['language'].replace('_', '-') - ui_language = params['language'].split('_')[0] - - search_path = search_string.format( - query=urlencode({'query': query, - 'uiLanguage': ui_language, - 'region': region}), - page=params['pageno']) - - # image search query is something like 'image?{query}&page={page}' - if params['category'] == 'images': - search_path = 'image' + search_path - - params['url'] = base_url + search_path - - return params - - -# get response from search-request -def response(resp): - results = [] - - json_regex = regex_json.search(resp.content) - - # check if results are returned - if not json_regex: - return [] - - json_raw = regex_json_remove_end.sub('', regex_json_remove_start.sub('', json_regex.group())) - json = loads(json_raw) - - # parse results - for result in json['Results'].get('items', []): - result_title = result['Title'].replace(u'\uE000', '').replace(u'\uE001', '') - - # parse image results - if result.get('ContentType', '').startswith('image'): - img_url = unquote(regex_img_url_remove_start.sub('', result['Url'])) - - # append result - results.append({'url': result['SourceUrl'], - 'title': escape(result['Title']), - 'content': '', - 'img_src': img_url, - 'template': 'images.html'}) - - # parse general results - else: - result_url = result['Url'].replace(u'\uE000', '').replace(u'\uE001', '') - result_content = result['Description'].replace(u'\uE000', '').replace(u'\uE001', '') - - # append result - results.append({'url': result_url, - 'title': escape(result_title), - 'content': escape(result_content)}) - - # parse images - for result in json.get('Images', []): - # decode image url - img_url = unquote(regex_img_url_remove_start.sub('', result['Url'])) - - # append result - results.append({'url': result['SourceUrl'], - 'title': escape(result['Title']), - 'content': '', - 'img_src': img_url, - 'template': 'images.html'}) - - # return results - return results diff --git a/sources/searx/engines/tokyotoshokan.py b/sources/searx/engines/tokyotoshokan.py deleted file mode 100644 index 17e8e21..0000000 --- a/sources/searx/engines/tokyotoshokan.py +++ /dev/null @@ -1,102 +0,0 @@ -""" - Tokyo Toshokan (A BitTorrent Library for Japanese Media) - - @website https://www.tokyotosho.info/ - @provide-api no - @using-api no - @results HTML - @stable no (HTML can change) - @parse url, title, publishedDate, seed, leech, - filesize, magnetlink, content -""" - -import re -from cgi import escape -from urllib import urlencode -from lxml import html -from searx.engines.xpath import extract_text -from datetime import datetime -from searx.engines.nyaa import int_or_zero, get_filesize_mul - -# engine dependent config -categories = ['files', 'videos', 'music'] -paging = True - -# search-url -base_url = 'https://www.tokyotosho.info/' -search_url = base_url + 'search.php?{query}' - - -# do search-request -def request(query, params): - query = urlencode({'page': params['pageno'], - 'terms': query}) - params['url'] = search_url.format(query=query) - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - rows = dom.xpath('//table[@class="listing"]//tr[contains(@class, "category_0")]') - - # check if there are no results or page layout was changed so we cannot parse it - # currently there are two rows for each result, so total count must be even - if len(rows) == 0 or len(rows) % 2 != 0: - return [] - - # regular expression for parsing torrent size strings - size_re = re.compile('Size:\s*([\d.]+)(TB|GB|MB|B)', re.IGNORECASE) - - # processing the results, two rows at a time - for i in xrange(0, len(rows), 2): - # parse the first row - name_row = rows[i] - - links = name_row.xpath('./td[@class="desc-top"]/a') - params = { - 'template': 'torrent.html', - 'url': links[-1].attrib.get('href'), - 'title': extract_text(links[-1]) - } - # I have not yet seen any torrents without magnet links, but - # it's better to be prepared to stumble upon one some day - if len(links) == 2: - magnet = links[0].attrib.get('href') - if magnet.startswith('magnet'): - # okay, we have a valid magnet link, let's add it to the result - params['magnetlink'] = magnet - - # no more info in the first row, start parsing the second one - info_row = rows[i + 1] - desc = extract_text(info_row.xpath('./td[@class="desc-bot"]')[0]) - for item in desc.split('|'): - item = item.strip() - if item.startswith('Size:'): - try: - # ('1.228', 'GB') - groups = size_re.match(item).groups() - multiplier = get_filesize_mul(groups[1]) - params['filesize'] = int(multiplier * float(groups[0])) - except Exception as e: - pass - elif item.startswith('Date:'): - try: - # Date: 2016-02-21 21:44 UTC - date = datetime.strptime(item, 'Date: %Y-%m-%d %H:%M UTC') - params['publishedDate'] = date - except Exception as e: - pass - elif item.startswith('Comment:'): - params['content'] = item - stats = info_row.xpath('./td[@class="stats"]/span') - # has the layout not changed yet? - if len(stats) == 3: - params['seed'] = int_or_zero(extract_text(stats[0])) - params['leech'] = int_or_zero(extract_text(stats[1])) - - results.append(params) - - return results diff --git a/sources/searx/engines/torrentz.py b/sources/searx/engines/torrentz.py deleted file mode 100644 index 92fbe70..0000000 --- a/sources/searx/engines/torrentz.py +++ /dev/null @@ -1,93 +0,0 @@ -""" - Torrentz.eu (BitTorrent meta-search engine) - - @website https://torrentz.eu/ - @provide-api no - - @using-api no - @results HTML - @stable no (HTML can change, although unlikely, - see https://torrentz.eu/torrentz.btsearch) - @parse url, title, publishedDate, seed, leech, filesize, magnetlink -""" - -import re -from cgi import escape -from urllib import urlencode -from lxml import html -from searx.engines.xpath import extract_text -from datetime import datetime -from searx.engines.nyaa import int_or_zero, get_filesize_mul - -# engine dependent config -categories = ['files', 'videos', 'music'] -paging = True - -# search-url -# https://torrentz.eu/search?f=EXAMPLE&p=6 -base_url = 'https://torrentz.eu/' -search_url = base_url + 'search?{query}' - - -# do search-request -def request(query, params): - page = params['pageno'] - 1 - query = urlencode({'q': query, 'p': page}) - params['url'] = search_url.format(query=query) - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - - for result in dom.xpath('//div[@class="results"]/dl'): - name_cell = result.xpath('./dt')[0] - title = extract_text(name_cell) - - # skip rows that do not contain a link to a torrent - links = name_cell.xpath('./a') - if len(links) != 1: - continue - - # extract url and remove a slash in the beginning - link = links[0].attrib.get('href').lstrip('/') - - seed = result.xpath('./dd/span[@class="u"]/text()')[0].replace(',', '') - leech = result.xpath('./dd/span[@class="d"]/text()')[0].replace(',', '') - - params = { - 'url': base_url + link, - 'title': title, - 'seed': int_or_zero(seed), - 'leech': int_or_zero(leech), - 'template': 'torrent.html' - } - - # let's try to calculate the torrent size - try: - size_str = result.xpath('./dd/span[@class="s"]/text()')[0] - size, suffix = size_str.split() - params['filesize'] = int(size) * get_filesize_mul(suffix) - except Exception as e: - pass - - # does our link contain a valid SHA1 sum? - if re.compile('[0-9a-fA-F]{40}').match(link): - # add a magnet link to the result - params['magnetlink'] = 'magnet:?xt=urn:btih:' + link - - # extract and convert creation date - try: - date_str = result.xpath('./dd/span[@class="a"]/span')[0].attrib.get('title') - # Fri, 25 Mar 2016 16:29:01 - date = datetime.strptime(date_str, '%a, %d %b %Y %H:%M:%S') - params['publishedDate'] = date - except Exception as e: - pass - - results.append(params) - - return results diff --git a/sources/searx/engines/twitter.py b/sources/searx/engines/twitter.py deleted file mode 100644 index 36efac1..0000000 --- a/sources/searx/engines/twitter.py +++ /dev/null @@ -1,83 +0,0 @@ -""" - Twitter (Social media) - - @website https://twitter.com/ - @provide-api yes (https://dev.twitter.com/docs/using-search) - - @using-api no - @results HTML (using search portal) - @stable no (HTML can change) - @parse url, title, content - - @todo publishedDate -""" - -from urlparse import urljoin -from urllib import urlencode -from lxml import html -from datetime import datetime -from searx.engines.xpath import extract_text - -# engine dependent config -categories = ['social media'] -language_support = True - -# search-url -base_url = 'https://twitter.com/' -search_url = base_url + 'search?' - -# specific xpath variables -results_xpath = '//li[@data-item-type="tweet"]' -link_xpath = './/small[@class="time"]//a' -title_xpath = './/span[contains(@class, "username")]' -content_xpath = './/p[contains(@class, "tweet-text")]' -timestamp_xpath = './/span[contains(@class,"_timestamp")]' - - -# do search-request -def request(query, params): - params['url'] = search_url + urlencode({'q': query}) - - # set language if specified - if params['language'] != 'all': - params['cookies']['lang'] = params['language'].split('_')[0] - else: - params['cookies']['lang'] = 'en' - - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - - # parse results - for tweet in dom.xpath(results_xpath): - try: - link = tweet.xpath(link_xpath)[0] - content = extract_text(tweet.xpath(content_xpath)[0]) - except Exception: - continue - - url = urljoin(base_url, link.attrib.get('href')) - title = extract_text(tweet.xpath(title_xpath)) - - pubdate = tweet.xpath(timestamp_xpath) - if len(pubdate) > 0: - timestamp = float(pubdate[0].attrib.get('data-time')) - publishedDate = datetime.fromtimestamp(timestamp, None) - # append result - results.append({'url': url, - 'title': title, - 'content': content, - 'publishedDate': publishedDate}) - else: - # append result - results.append({'url': url, - 'title': title, - 'content': content}) - - # return results - return results diff --git a/sources/searx/engines/vimeo.py b/sources/searx/engines/vimeo.py deleted file mode 100644 index 517ac1c..0000000 --- a/sources/searx/engines/vimeo.py +++ /dev/null @@ -1,75 +0,0 @@ -# Vimeo (Videos) -# -# @website https://vimeo.com/ -# @provide-api yes (http://developer.vimeo.com/api), -# they have a maximum count of queries/hour -# -# @using-api no (TODO, rewrite to api) -# @results HTML (using search portal) -# @stable no (HTML can change) -# @parse url, title, publishedDate, thumbnail, embedded -# -# @todo rewrite to api -# @todo set content-parameter with correct data - -from urllib import urlencode -from lxml import html -from HTMLParser import HTMLParser -from searx.engines.xpath import extract_text -from dateutil import parser - -# engine dependent config -categories = ['videos'] -paging = True - -# search-url -base_url = 'https://vimeo.com' -search_url = base_url + '/search/page:{pageno}?{query}' - -# specific xpath variables -results_xpath = '//div[contains(@class,"results_grid")]/ul/li' -url_xpath = './/a/@href' -title_xpath = './/span[@class="title"]' -thumbnail_xpath = './/img[@class="js-clip_thumbnail_image"]/@src' -publishedDate_xpath = './/time/attribute::datetime' - -embedded_url = '' - - -# do search-request -def request(query, params): - params['url'] = search_url.format(pageno=params['pageno'], - query=urlencode({'q': query})) - - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - p = HTMLParser() - - # parse results - for result in dom.xpath(results_xpath): - videoid = result.xpath(url_xpath)[0] - url = base_url + videoid - title = p.unescape(extract_text(result.xpath(title_xpath))) - thumbnail = extract_text(result.xpath(thumbnail_xpath)[0]) - publishedDate = parser.parse(extract_text(result.xpath(publishedDate_xpath)[0])) - embedded = embedded_url.format(videoid=videoid) - - # append result - results.append({'url': url, - 'title': title, - 'content': '', - 'template': 'videos.html', - 'publishedDate': publishedDate, - 'embedded': embedded, - 'thumbnail': thumbnail}) - - # return results - return results diff --git a/sources/searx/engines/wikidata.py b/sources/searx/engines/wikidata.py deleted file mode 100644 index 8aa2fcd..0000000 --- a/sources/searx/engines/wikidata.py +++ /dev/null @@ -1,323 +0,0 @@ -import json - -from searx import logger -from searx.poolrequests import get -from searx.utils import format_date_by_locale - -from datetime import datetime -from dateutil.parser import parse as dateutil_parse -from urllib import urlencode - - -logger = logger.getChild('wikidata') -result_count = 1 -wikidata_host = 'https://www.wikidata.org' -wikidata_api = wikidata_host + '/w/api.php' -url_search = wikidata_api \ - + '?action=query&list=search&format=json'\ - + '&srnamespace=0&srprop=sectiontitle&{query}' -url_detail = wikidata_api\ - + '?action=wbgetentities&format=json'\ - + '&props=labels%7Cinfo%7Csitelinks'\ - + '%7Csitelinks%2Furls%7Cdescriptions%7Cclaims'\ - + '&{query}' -url_map = 'https://www.openstreetmap.org/'\ - + '?lat={latitude}&lon={longitude}&zoom={zoom}&layers=M' - - -def request(query, params): - params['url'] = url_search.format( - query=urlencode({'srsearch': query, - 'srlimit': result_count})) - return params - - -def response(resp): - results = [] - search_res = json.loads(resp.text) - - wikidata_ids = set() - for r in search_res.get('query', {}).get('search', {}): - wikidata_ids.add(r.get('title', '')) - - language = resp.search_params['language'].split('_')[0] - if language == 'all': - language = 'en' - - url = url_detail.format(query=urlencode({'ids': '|'.join(wikidata_ids), - 'languages': language + '|en'})) - - htmlresponse = get(url) - jsonresponse = json.loads(htmlresponse.content) - for wikidata_id in wikidata_ids: - results = results + getDetail(jsonresponse, wikidata_id, language, resp.search_params['language']) - - return results - - -def getDetail(jsonresponse, wikidata_id, language, locale): - results = [] - urls = [] - attributes = [] - - result = jsonresponse.get('entities', {}).get(wikidata_id, {}) - - title = result.get('labels', {}).get(language, {}).get('value', None) - if title is None: - title = result.get('labels', {}).get('en', {}).get('value', None) - if title is None: - return results - - description = result\ - .get('descriptions', {})\ - .get(language, {})\ - .get('value', None) - - if description is None: - description = result\ - .get('descriptions', {})\ - .get('en', {})\ - .get('value', '') - - claims = result.get('claims', {}) - official_website = get_string(claims, 'P856', None) - if official_website is not None: - urls.append({'title': 'Official site', 'url': official_website}) - results.append({'title': title, 'url': official_website}) - - wikipedia_link_count = 0 - wikipedia_link = get_wikilink(result, language + 'wiki') - wikipedia_link_count += add_url(urls, - 'Wikipedia (' + language + ')', - wikipedia_link) - if language != 'en': - wikipedia_en_link = get_wikilink(result, 'enwiki') - wikipedia_link_count += add_url(urls, - 'Wikipedia (en)', - wikipedia_en_link) - if wikipedia_link_count == 0: - misc_language = get_wiki_firstlanguage(result, 'wiki') - if misc_language is not None: - add_url(urls, - 'Wikipedia (' + misc_language + ')', - get_wikilink(result, misc_language + 'wiki')) - - if language != 'en': - add_url(urls, - 'Wiki voyage (' + language + ')', - get_wikilink(result, language + 'wikivoyage')) - - add_url(urls, - 'Wiki voyage (en)', - get_wikilink(result, 'enwikivoyage')) - - if language != 'en': - add_url(urls, - 'Wikiquote (' + language + ')', - get_wikilink(result, language + 'wikiquote')) - - add_url(urls, - 'Wikiquote (en)', - get_wikilink(result, 'enwikiquote')) - - add_url(urls, - 'Commons wiki', - get_wikilink(result, 'commonswiki')) - - add_url(urls, - 'Location', - get_geolink(claims, 'P625', None)) - - add_url(urls, - 'Wikidata', - 'https://www.wikidata.org/wiki/' - + wikidata_id + '?uselang=' + language) - - musicbrainz_work_id = get_string(claims, 'P435') - if musicbrainz_work_id is not None: - add_url(urls, - 'MusicBrainz', - 'http://musicbrainz.org/work/' - + musicbrainz_work_id) - - musicbrainz_artist_id = get_string(claims, 'P434') - if musicbrainz_artist_id is not None: - add_url(urls, - 'MusicBrainz', - 'http://musicbrainz.org/artist/' - + musicbrainz_artist_id) - - musicbrainz_release_group_id = get_string(claims, 'P436') - if musicbrainz_release_group_id is not None: - add_url(urls, - 'MusicBrainz', - 'http://musicbrainz.org/release-group/' - + musicbrainz_release_group_id) - - musicbrainz_label_id = get_string(claims, 'P966') - if musicbrainz_label_id is not None: - add_url(urls, - 'MusicBrainz', - 'http://musicbrainz.org/label/' - + musicbrainz_label_id) - - # musicbrainz_area_id = get_string(claims, 'P982') - # P1407 MusicBrainz series ID - # P1004 MusicBrainz place ID - # P1330 MusicBrainz instrument ID - # P1407 MusicBrainz series ID - - postal_code = get_string(claims, 'P281', None) - if postal_code is not None: - attributes.append({'label': 'Postal code(s)', 'value': postal_code}) - - date_of_birth = get_time(claims, 'P569', locale, None) - if date_of_birth is not None: - attributes.append({'label': 'Date of birth', 'value': date_of_birth}) - - date_of_death = get_time(claims, 'P570', locale, None) - if date_of_death is not None: - attributes.append({'label': 'Date of death', 'value': date_of_death}) - - if len(attributes) == 0 and len(urls) == 2 and len(description) == 0: - results.append({ - 'url': urls[0]['url'], - 'title': title, - 'content': description - }) - else: - results.append({ - 'infobox': title, - 'id': wikipedia_link, - 'content': description, - 'attributes': attributes, - 'urls': urls - }) - - return results - - -def add_url(urls, title, url): - if url is not None: - urls.append({'title': title, 'url': url}) - return 1 - else: - return 0 - - -def get_mainsnak(claims, propertyName): - propValue = claims.get(propertyName, {}) - if len(propValue) == 0: - return None - - propValue = propValue[0].get('mainsnak', None) - return propValue - - -def get_string(claims, propertyName, defaultValue=None): - propValue = claims.get(propertyName, {}) - if len(propValue) == 0: - return defaultValue - - result = [] - for e in propValue: - mainsnak = e.get('mainsnak', {}) - - datavalue = mainsnak.get('datavalue', {}) - if datavalue is not None: - result.append(datavalue.get('value', '')) - - if len(result) == 0: - return defaultValue - else: - # TODO handle multiple urls - return result[0] - - -def get_time(claims, propertyName, locale, defaultValue=None): - propValue = claims.get(propertyName, {}) - if len(propValue) == 0: - return defaultValue - - result = [] - for e in propValue: - mainsnak = e.get('mainsnak', {}) - - datavalue = mainsnak.get('datavalue', {}) - if datavalue is not None: - value = datavalue.get('value', '') - result.append(value.get('time', '')) - - if len(result) == 0: - date_string = defaultValue - else: - date_string = ', '.join(result) - - try: - parsed_date = datetime.strptime(date_string, "+%Y-%m-%dT%H:%M:%SZ") - except: - if date_string.startswith('-'): - return date_string.split('T')[0] - try: - parsed_date = dateutil_parse(date_string, fuzzy=False, default=False) - except: - logger.debug('could not parse date %s', date_string) - return date_string.split('T')[0] - - return format_date_by_locale(parsed_date, locale) - - -def get_geolink(claims, propertyName, defaultValue=''): - mainsnak = get_mainsnak(claims, propertyName) - - if mainsnak is None: - return defaultValue - - datatype = mainsnak.get('datatype', '') - datavalue = mainsnak.get('datavalue', {}) - - if datatype != 'globe-coordinate': - return defaultValue - - value = datavalue.get('value', {}) - - precision = value.get('precision', 0.0002) - - # there is no zoom information, deduce from precision (error prone) - # samples : - # 13 --> 5 - # 1 --> 6 - # 0.016666666666667 --> 9 - # 0.00027777777777778 --> 19 - # wolframalpha : - # quadratic fit { {13, 5}, {1, 6}, {0.0166666, 9}, {0.0002777777,19}} - # 14.1186-8.8322 x+0.625447 x^2 - if precision < 0.0003: - zoom = 19 - else: - zoom = int(15 - precision * 8.8322 + precision * precision * 0.625447) - - url = url_map\ - .replace('{latitude}', str(value.get('latitude', 0)))\ - .replace('{longitude}', str(value.get('longitude', 0)))\ - .replace('{zoom}', str(zoom)) - - return url - - -def get_wikilink(result, wikiid): - url = result.get('sitelinks', {}).get(wikiid, {}).get('url', None) - if url is None: - return url - elif url.startswith('http://'): - url = url.replace('http://', 'https://') - elif url.startswith('//'): - url = 'https:' + url - return url - - -def get_wiki_firstlanguage(result, wikipatternid): - for k in result.get('sitelinks', {}).keys(): - if k.endswith(wikipatternid) and len(k) == (2 + len(wikipatternid)): - return k[0:2] - return None diff --git a/sources/searx/engines/wikipedia.py b/sources/searx/engines/wikipedia.py deleted file mode 100644 index fed7b26..0000000 --- a/sources/searx/engines/wikipedia.py +++ /dev/null @@ -1,114 +0,0 @@ -""" - Wikipedia (Web) - - @website https://{language}.wikipedia.org - @provide-api yes - - @using-api yes - @results JSON - @stable yes - @parse url, infobox -""" - -from json import loads -from urllib import urlencode, quote - -# search-url -base_url = 'https://{language}.wikipedia.org/' -search_postfix = 'w/api.php?'\ - 'action=query'\ - '&format=json'\ - '&{query}'\ - '&prop=extracts|pageimages'\ - '&exintro'\ - '&explaintext'\ - '&pithumbsize=300'\ - '&redirects' - - -# set language in base_url -def url_lang(lang): - if lang == 'all': - language = 'en' - else: - language = lang.split('_')[0] - - return base_url.format(language=language) - - -# do search-request -def request(query, params): - if query.islower(): - query += '|' + query.title() - - params['url'] = url_lang(params['language']) \ - + search_postfix.format(query=urlencode({'titles': query})) - - return params - - -# get first meaningful paragraph -# this should filter out disambiguation pages and notes above first paragraph -# "magic numbers" were obtained by fine tuning -def extract_first_paragraph(content, title, image): - first_paragraph = None - - failed_attempts = 0 - for paragraph in content.split('\n'): - - starts_with_title = paragraph.lower().find(title.lower(), 0, len(title) + 35) - length = len(paragraph) - - if length >= 200 or (starts_with_title >= 0 and (image or length >= 150)): - first_paragraph = paragraph - break - - failed_attempts += 1 - if failed_attempts > 3: - return None - - return first_paragraph - - -# get response from search-request -def response(resp): - results = [] - - search_result = loads(resp.content) - - # wikipedia article's unique id - # first valid id is assumed to be the requested article - for article_id in search_result['query']['pages']: - page = search_result['query']['pages'][article_id] - if int(article_id) > 0: - break - - if int(article_id) < 0: - return [] - - title = page.get('title') - - image = page.get('thumbnail') - if image: - image = image.get('source') - - extract = page.get('extract') - - summary = extract_first_paragraph(extract, title, image) - if not summary: - return [] - - # link to wikipedia article - # parenthesis are not quoted to make infobox mergeable with wikidata's - wikipedia_link = url_lang(resp.search_params['language']) \ - + 'wiki/' + quote(title.replace(' ', '_').encode('utf8')).replace('%28', '(').replace('%29', ')') - - results.append({'url': wikipedia_link, 'title': title}) - - results.append({'infobox': title, - 'id': wikipedia_link, - 'content': summary, - 'img_src': image, - 'urls': [{'title': 'Wikipedia', 'url': wikipedia_link}]}) - - return results diff --git a/sources/searx/engines/wolframalpha_api.py b/sources/searx/engines/wolframalpha_api.py deleted file mode 100644 index 4526c82..0000000 --- a/sources/searx/engines/wolframalpha_api.py +++ /dev/null @@ -1,122 +0,0 @@ -# Wolfram Alpha (Science) -# -# @website https://www.wolframalpha.com -# @provide-api yes (https://api.wolframalpha.com/v2/) -# -# @using-api yes -# @results XML -# @stable yes -# @parse url, infobox - -from urllib import urlencode -from lxml import etree - -# search-url -search_url = 'https://api.wolframalpha.com/v2/query?appid={api_key}&{query}' -site_url = 'https://www.wolframalpha.com/input/?{query}' -api_key = '' # defined in settings.yml - -# xpath variables -failure_xpath = '/queryresult[attribute::success="false"]' -answer_xpath = '//pod[attribute::primary="true"]/subpod/plaintext' -input_xpath = '//pod[starts-with(attribute::id, "Input")]/subpod/plaintext' -pods_xpath = '//pod' -subpods_xpath = './subpod' -pod_id_xpath = './@id' -pod_title_xpath = './@title' -plaintext_xpath = './plaintext' -image_xpath = './img' -img_src_xpath = './@src' -img_alt_xpath = './@alt' - -# pods to display as image in infobox -# this pods do return a plaintext, but they look better and are more useful as images -image_pods = {'VisualRepresentation', - 'Illustration'} - - -# do search-request -def request(query, params): - params['url'] = search_url.format(query=urlencode({'input': query}), - api_key=api_key) - params['headers']['Referer'] = site_url.format(query=urlencode({'i': query})) - - return params - - -# replace private user area characters to make text legible -def replace_pua_chars(text): - pua_chars = {u'\uf522': u'\u2192', # rigth arrow - u'\uf7b1': u'\u2115', # set of natural numbers - u'\uf7b4': u'\u211a', # set of rational numbers - u'\uf7b5': u'\u211d', # set of real numbers - u'\uf7bd': u'\u2124', # set of integer numbers - u'\uf74c': 'd', # differential - u'\uf74d': u'\u212f', # euler's number - u'\uf74e': 'i', # imaginary number - u'\uf7d9': '='} # equals sign - - for k, v in pua_chars.iteritems(): - text = text.replace(k, v) - - return text - - -# get response from search-request -def response(resp): - results = [] - - search_results = etree.XML(resp.content) - - # return empty array if there are no results - if search_results.xpath(failure_xpath): - return [] - - try: - infobox_title = search_results.xpath(input_xpath)[0].text - except: - infobox_title = None - - pods = search_results.xpath(pods_xpath) - result_chunks = [] - for pod in pods: - pod_id = pod.xpath(pod_id_xpath)[0] - pod_title = pod.xpath(pod_title_xpath)[0] - - subpods = pod.xpath(subpods_xpath) - if not subpods: - continue - - # Appends either a text or an image, depending on which one is more suitable - for subpod in subpods: - content = subpod.xpath(plaintext_xpath)[0].text - image = subpod.xpath(image_xpath) - - if content and pod_id not in image_pods: - - # if no input pod was found, title is first plaintext pod - if not infobox_title: - infobox_title = content - - content = replace_pua_chars(content) - result_chunks.append({'label': pod_title, 'value': content}) - - elif image: - result_chunks.append({'label': pod_title, - 'image': {'src': image[0].xpath(img_src_xpath)[0], - 'alt': image[0].xpath(img_alt_xpath)[0]}}) - - if not result_chunks: - return [] - - # append infobox - results.append({'infobox': infobox_title, - 'attributes': result_chunks, - 'urls': [{'title': 'Wolfram|Alpha', 'url': resp.request.headers['Referer'].decode('utf8')}]}) - - # append link to site - results.append({'url': resp.request.headers['Referer'].decode('utf8'), - 'title': 'Wolfram|Alpha', - 'content': infobox_title}) - - return results diff --git a/sources/searx/engines/wolframalpha_noapi.py b/sources/searx/engines/wolframalpha_noapi.py deleted file mode 100644 index 59629b8..0000000 --- a/sources/searx/engines/wolframalpha_noapi.py +++ /dev/null @@ -1,116 +0,0 @@ -# Wolfram|Alpha (Science) -# -# @website https://www.wolframalpha.com/ -# @provide-api yes (https://api.wolframalpha.com/v2/) -# -# @using-api no -# @results JSON -# @stable no -# @parse url, infobox - -from cgi import escape -from json import loads -from time import time -from urllib import urlencode -from lxml.etree import XML - -from searx.poolrequests import get as http_get - -# search-url -url = 'https://www.wolframalpha.com/' - -search_url = url + 'input/json.jsp'\ - '?async=false'\ - '&banners=raw'\ - '&debuggingdata=false'\ - '&format=image,plaintext,imagemap,minput,moutput'\ - '&formattimeout=2'\ - '&{query}'\ - '&output=JSON'\ - '&parsetimeout=2'\ - '&proxycode={token}'\ - '&scantimeout=0.5'\ - '&sponsorcategories=true'\ - '&statemethod=deploybutton' - -referer_url = url + 'input/?{query}' - -token = {'value': '', - 'last_updated': None} - -# pods to display as image in infobox -# this pods do return a plaintext, but they look better and are more useful as images -image_pods = {'VisualRepresentation', - 'Illustration', - 'Symbol'} - - -# seems, wolframalpha resets its token in every hour -def obtain_token(): - update_time = time() - (time() % 3600) - try: - token_response = http_get('https://www.wolframalpha.com/input/api/v1/code?ts=9999999999999999999', timeout=2.0) - token['value'] = loads(token_response.text)['code'] - token['last_updated'] = update_time - except: - pass - return token - - -obtain_token() - - -# do search-request -def request(query, params): - # obtain token if last update was more than an hour - if time() - token['last_updated'] > 3600: - obtain_token() - params['url'] = search_url.format(query=urlencode({'input': query}), token=token['value']) - params['headers']['Referer'] = referer_url.format(query=urlencode({'i': query})) - - return params - - -# get response from search-request -def response(resp): - results = [] - - resp_json = loads(resp.text) - - if not resp_json['queryresult']['success']: - return [] - - # TODO handle resp_json['queryresult']['assumptions'] - result_chunks = [] - infobox_title = None - for pod in resp_json['queryresult']['pods']: - pod_id = pod.get('id', '') - pod_title = pod.get('title', '') - - if 'subpods' not in pod: - continue - - if pod_id == 'Input' or not infobox_title: - infobox_title = pod['subpods'][0]['plaintext'] - - for subpod in pod['subpods']: - if subpod['plaintext'] != '' and pod_id not in image_pods: - # append unless it's not an actual answer - if subpod['plaintext'] != '(requires interactivity)': - result_chunks.append({'label': pod_title, 'value': subpod['plaintext']}) - - elif 'img' in subpod: - result_chunks.append({'label': pod_title, 'image': subpod['img']}) - - if not result_chunks: - return [] - - results.append({'infobox': infobox_title, - 'attributes': result_chunks, - 'urls': [{'title': 'Wolfram|Alpha', 'url': resp.request.headers['Referer'].decode('utf8')}]}) - - results.append({'url': resp.request.headers['Referer'].decode('utf8'), - 'title': 'Wolfram|Alpha', - 'content': infobox_title}) - - return results diff --git a/sources/searx/engines/www1x.py b/sources/searx/engines/www1x.py deleted file mode 100644 index 1269a54..0000000 --- a/sources/searx/engines/www1x.py +++ /dev/null @@ -1,83 +0,0 @@ -""" - 1x (Images) - - @website http://1x.com/ - @provide-api no - - @using-api no - @results HTML - @stable no (HTML can change) - @parse url, title, thumbnail, img_src, content -""" - -from urllib import urlencode -from urlparse import urljoin -from lxml import html -import string -import re - -# engine dependent config -categories = ['images'] -paging = False - -# search-url -base_url = 'https://1x.com' -search_url = base_url + '/backend/search.php?{query}' - - -# do search-request -def request(query, params): - params['url'] = search_url.format(query=urlencode({'q': query})) - - return params - - -# get response from search-request -def response(resp): - results = [] - - # get links from result-text - regex = re.compile('(|', '"/>') - - dom = html.fromstring(cur_element) - link = dom.xpath('//a')[0] - - url = urljoin(base_url, link.attrib.get('href')) - title = link.attrib.get('title', '') - - thumbnail_src = urljoin(base_url, link.xpath('.//img')[0].attrib['src']) - # TODO: get image with higher resolution - img_src = thumbnail_src - - # check if url is showing to a photo - if '/photo/' not in url: - continue - - # append result - results.append({'url': url, - 'title': title, - 'img_src': img_src, - 'content': '', - 'thumbnail_src': thumbnail_src, - 'template': 'images.html'}) - - # return results - return results diff --git a/sources/searx/engines/www500px.py b/sources/searx/engines/www500px.py deleted file mode 100644 index c98e194..0000000 --- a/sources/searx/engines/www500px.py +++ /dev/null @@ -1,66 +0,0 @@ -""" - 500px (Images) - - @website https://500px.com - @provide-api yes (https://developers.500px.com/) - - @using-api no - @results HTML - @stable no (HTML can change) - @parse url, title, thumbnail, img_src, content - - @todo rewrite to api -""" - - -from urllib import urlencode -from urlparse import urljoin -from lxml import html -import re -from searx.engines.xpath import extract_text - -# engine dependent config -categories = ['images'] -paging = True - -# search-url -base_url = 'https://500px.com' -search_url = base_url + '/search?search?page={pageno}&type=photos&{query}' - - -# do search-request -def request(query, params): - params['url'] = search_url.format(pageno=params['pageno'], - query=urlencode({'q': query})) - - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - regex = re.compile('3\.jpg.*$') - - # parse results - for result in dom.xpath('//div[@class="photo"]'): - link = result.xpath('.//a')[0] - url = urljoin(base_url, link.attrib.get('href')) - title = extract_text(result.xpath('.//div[@class="title"]')) - thumbnail_src = link.xpath('.//img')[0].attrib.get('src') - # To have a bigger thumbnail, uncomment the next line - # thumbnail_src = regex.sub('4.jpg', thumbnail_src) - content = extract_text(result.xpath('.//div[@class="info"]')) - img_src = regex.sub('2048.jpg', thumbnail_src) - - # append result - results.append({'url': url, - 'title': title, - 'img_src': img_src, - 'content': content, - 'thumbnail_src': thumbnail_src, - 'template': 'images.html'}) - - # return results - return results diff --git a/sources/searx/engines/xpath.py b/sources/searx/engines/xpath.py deleted file mode 100644 index e701c02..0000000 --- a/sources/searx/engines/xpath.py +++ /dev/null @@ -1,120 +0,0 @@ -from lxml import html -from urllib import urlencode, unquote -from urlparse import urlparse, urljoin -from lxml.etree import _ElementStringResult, _ElementUnicodeResult -from searx.utils import html_to_text - -search_url = None -url_xpath = None -content_xpath = None -title_xpath = None -suggestion_xpath = '' -results_xpath = '' - -# parameters for engines with paging support -# -# number of results on each page -# (only needed if the site requires not a page number, but an offset) -page_size = 1 -# number of the first page (usually 0 or 1) -first_page_num = 1 - - -''' -if xpath_results is list, extract the text from each result and concat the list -if xpath_results is a xml element, extract all the text node from it - ( text_content() method from lxml ) -if xpath_results is a string element, then it's already done -''' - - -def extract_text(xpath_results): - if type(xpath_results) == list: - # it's list of result : concat everything using recursive call - if not xpath_results: - raise Exception('Empty url resultset') - result = '' - for e in xpath_results: - result = result + extract_text(e) - return result.strip() - elif type(xpath_results) in [_ElementStringResult, _ElementUnicodeResult]: - # it's a string - return ''.join(xpath_results) - else: - # it's a element - return html_to_text(xpath_results.text_content()).strip() - - -def extract_url(xpath_results, search_url): - url = extract_text(xpath_results) - - if url.startswith('//'): - # add http or https to this kind of url //example.com/ - parsed_search_url = urlparse(search_url) - url = parsed_search_url.scheme + url - elif url.startswith('/'): - # fix relative url to the search engine - url = urljoin(search_url, url) - - # normalize url - url = normalize_url(url) - - return url - - -def normalize_url(url): - parsed_url = urlparse(url) - - # add a / at this end of the url if there is no path - if not parsed_url.netloc: - raise Exception('Cannot parse url') - if not parsed_url.path: - url += '/' - - # FIXME : hack for yahoo - if parsed_url.hostname == 'search.yahoo.com'\ - and parsed_url.path.startswith('/r'): - p = parsed_url.path - mark = p.find('/**') - if mark != -1: - return unquote(p[mark + 3:]).decode('utf-8') - - return url - - -def request(query, params): - query = urlencode({'q': query})[2:] - - fp = {'query': query} - if paging and search_url.find('{pageno}') >= 0: - fp['pageno'] = (params['pageno'] + first_page_num - 1) * page_size - - params['url'] = search_url.format(**fp) - params['query'] = query - - return params - - -def response(resp): - results = [] - dom = html.fromstring(resp.text) - if results_xpath: - for result in dom.xpath(results_xpath): - url = extract_url(result.xpath(url_xpath), search_url) - title = extract_text(result.xpath(title_xpath)[0]) - content = extract_text(result.xpath(content_xpath)[0]) - results.append({'url': url, 'title': title, 'content': content}) - else: - for url, title, content in zip( - (extract_url(x, search_url) for - x in dom.xpath(url_xpath)), - map(extract_text, dom.xpath(title_xpath)), - map(extract_text, dom.xpath(content_xpath)) - ): - results.append({'url': url, 'title': title, 'content': content}) - - if not suggestion_xpath: - return results - for suggestion in dom.xpath(suggestion_xpath): - results.append({'suggestion': extract_text(suggestion)}) - return results diff --git a/sources/searx/engines/yacy.py b/sources/searx/engines/yacy.py deleted file mode 100644 index c2f1bc7..0000000 --- a/sources/searx/engines/yacy.py +++ /dev/null @@ -1,97 +0,0 @@ -# Yacy (Web, Images, Videos, Music, Files) -# -# @website http://yacy.net -# @provide-api yes -# (http://www.yacy-websuche.de/wiki/index.php/Dev:APIyacysearch) -# -# @using-api yes -# @results JSON -# @stable yes -# @parse (general) url, title, content, publishedDate -# @parse (images) url, title, img_src -# -# @todo parse video, audio and file results - -from json import loads -from urllib import urlencode -from dateutil import parser - -# engine dependent config -categories = ['general', 'images'] # TODO , 'music', 'videos', 'files' -paging = True -language_support = True -number_of_results = 5 - -# search-url -base_url = 'http://localhost:8090' -search_url = '/yacysearch.json?{query}'\ - '&startRecord={offset}'\ - '&maximumRecords={limit}'\ - '&contentdom={search_type}'\ - '&resource=global' - -# yacy specific type-definitions -search_types = {'general': 'text', - 'images': 'image', - 'files': 'app', - 'music': 'audio', - 'videos': 'video'} - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * number_of_results - search_type = search_types.get(params.get('category'), '0') - - params['url'] = base_url +\ - search_url.format(query=urlencode({'query': query}), - offset=offset, - limit=number_of_results, - search_type=search_type) - - # add language tag if specified - if params['language'] != 'all': - params['url'] += '&lr=lang_' + params['language'].split('_')[0] - - return params - - -# get response from search-request -def response(resp): - results = [] - - raw_search_results = loads(resp.text) - - # return empty array if there are no results - if not raw_search_results: - return [] - - search_results = raw_search_results.get('channels', []) - - if len(search_results) == 0: - return [] - - for result in search_results[0].get('items', []): - # parse image results - if result.get('image'): - # append result - results.append({'url': result['url'], - 'title': result['title'], - 'content': '', - 'img_src': result['image'], - 'template': 'images.html'}) - - # parse general results - else: - publishedDate = parser.parse(result['pubDate']) - - # append result - results.append({'url': result['link'], - 'title': result['title'], - 'content': result['description'], - 'publishedDate': publishedDate}) - - # TODO parse video, audio and file results - - # return results - return results diff --git a/sources/searx/engines/yahoo.py b/sources/searx/engines/yahoo.py deleted file mode 100644 index b8b40e4..0000000 --- a/sources/searx/engines/yahoo.py +++ /dev/null @@ -1,113 +0,0 @@ -""" - Yahoo (Web) - - @website https://search.yahoo.com/web - @provide-api yes (https://developer.yahoo.com/boss/search/), - $0.80/1000 queries - - @using-api no (because pricing) - @results HTML (using search portal) - @stable no (HTML can change) - @parse url, title, content, suggestion -""" - -from urllib import urlencode -from urlparse import unquote -from lxml import html -from searx.engines.xpath import extract_text, extract_url - -# engine dependent config -categories = ['general'] -paging = True -language_support = True - -# search-url -base_url = 'https://search.yahoo.com/' -search_url = 'search?{query}&b={offset}&fl=1&vl=lang_{lang}' - -# specific xpath variables -results_xpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' Sr ')]" -url_xpath = './/h3/a/@href' -title_xpath = './/h3/a' -content_xpath = './/div[@class="compText aAbs"]' -suggestion_xpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' AlsoTry ')]//a" - - -# remove yahoo-specific tracking-url -def parse_url(url_string): - endings = ['/RS', '/RK'] - endpositions = [] - start = url_string.find('http', url_string.find('/RU=') + 1) - - for ending in endings: - endpos = url_string.rfind(ending) - if endpos > -1: - endpositions.append(endpos) - - if start == 0 or len(endpositions) == 0: - return url_string - else: - end = min(endpositions) - return unquote(url_string[start:end]) - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 10 + 1 - - if params['language'] == 'all': - language = 'en' - else: - language = params['language'].split('_')[0] - - params['url'] = base_url + search_url.format(offset=offset, - query=urlencode({'p': query}), - lang=language) - - # TODO required? - params['cookies']['sB'] = 'fl=1&vl=lang_{lang}&sh=1&rw=new&v=1'\ - .format(lang=language) - - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - - try: - results_num = int(dom.xpath('//div[@class="compPagination"]/span[last()]/text()')[0] - .split()[0].replace(',', '')) - results.append({'number_of_results': results_num}) - except: - pass - - # parse results - for result in dom.xpath(results_xpath): - try: - url = parse_url(extract_url(result.xpath(url_xpath), search_url)) - title = extract_text(result.xpath(title_xpath)[0]) - except: - continue - - content = extract_text(result.xpath(content_xpath)[0]) - - # append result - results.append({'url': url, - 'title': title, - 'content': content}) - - # if no suggestion found, return results - suggestions = dom.xpath(suggestion_xpath) - if not suggestions: - return results - - # parse suggestion - for suggestion in suggestions: - # append suggestion - results.append({'suggestion': extract_text(suggestion)}) - - # return results - return results diff --git a/sources/searx/engines/yahoo_news.py b/sources/searx/engines/yahoo_news.py deleted file mode 100644 index d4cfbed..0000000 --- a/sources/searx/engines/yahoo_news.py +++ /dev/null @@ -1,104 +0,0 @@ -# Yahoo (News) -# -# @website https://news.yahoo.com -# @provide-api yes (https://developer.yahoo.com/boss/search/) -# $0.80/1000 queries -# -# @using-api no (because pricing) -# @results HTML (using search portal) -# @stable no (HTML can change) -# @parse url, title, content, publishedDate - -from urllib import urlencode -from lxml import html -from searx.engines.xpath import extract_text, extract_url -from searx.engines.yahoo import parse_url -from datetime import datetime, timedelta -import re -from dateutil import parser - -# engine dependent config -categories = ['news'] -paging = True -language_support = True - -# search-url -search_url = 'https://news.search.yahoo.com/search?{query}&b={offset}&{lang}=uh3_news_web_gs_1&pz=10&xargs=0&vl=lang_{lang}' # noqa - -# specific xpath variables -results_xpath = '//ol[contains(@class,"searchCenterMiddle")]//li' -url_xpath = './/h3/a/@href' -title_xpath = './/h3/a' -content_xpath = './/div[@class="compText"]' -publishedDate_xpath = './/span[contains(@class,"tri")]' -suggestion_xpath = '//div[contains(@class,"VerALSOTRY")]//a' - - -# do search-request -def request(query, params): - offset = (params['pageno'] - 1) * 10 + 1 - - if params['language'] == 'all': - language = 'en' - else: - language = params['language'].split('_')[0] - - params['url'] = search_url.format(offset=offset, - query=urlencode({'p': query}), - lang=language) - - # TODO required? - params['cookies']['sB'] = '"v=1&vm=p&fl=1&vl=lang_{lang}&sh=1&pn=10&rw=new'\ - .format(lang=language) - return params - - -def sanitize_url(url): - if ".yahoo.com/" in url: - return re.sub(u"\;\_ylt\=.+$", "", url) - else: - return url - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - - # parse results - for result in dom.xpath(results_xpath): - urls = result.xpath(url_xpath) - if len(urls) != 1: - continue - url = sanitize_url(parse_url(extract_url(urls, search_url))) - title = extract_text(result.xpath(title_xpath)[0]) - content = extract_text(result.xpath(content_xpath)[0]) - - # parse publishedDate - publishedDate = extract_text(result.xpath(publishedDate_xpath)[0]) - - # still useful ? - if re.match("^[0-9]+ minute(s|) ago$", publishedDate): - publishedDate = datetime.now() - timedelta(minutes=int(re.match(r'\d+', publishedDate).group())) # noqa - else: - if re.match("^[0-9]+ hour(s|), [0-9]+ minute(s|) ago$", - publishedDate): - timeNumbers = re.findall(r'\d+', publishedDate) - publishedDate = datetime.now()\ - - timedelta(hours=int(timeNumbers[0]))\ - - timedelta(minutes=int(timeNumbers[1])) - else: - publishedDate = parser.parse(publishedDate) - - if publishedDate.year == 1900: - publishedDate = publishedDate.replace(year=datetime.now().year) - - # append result - results.append({'url': url, - 'title': title, - 'content': content, - 'publishedDate': publishedDate}) - - # return results - return results diff --git a/sources/searx/engines/yandex.py b/sources/searx/engines/yandex.py deleted file mode 100644 index be3ec36..0000000 --- a/sources/searx/engines/yandex.py +++ /dev/null @@ -1,63 +0,0 @@ -""" - Yahoo (Web) - - @website https://yandex.ru/ - @provide-api ? - @using-api no - @results HTML (using search portal) - @stable no (HTML can change) - @parse url, title, content -""" - -from cgi import escape -from urllib import urlencode -from lxml import html -from searx.search import logger - -logger = logger.getChild('yandex engine') - -# engine dependent config -categories = ['general'] -paging = True -language_support = True # TODO - -default_tld = 'com' -language_map = {'ru': 'ru', - 'ua': 'uk', - 'tr': 'com.tr'} - -# search-url -base_url = 'https://yandex.{tld}/' -search_url = 'search/?{query}&p={page}' - -results_xpath = '//div[@class="serp-item serp-item_plain_yes clearfix i-bem"]' -url_xpath = './/h2/a/@href' -title_xpath = './/h2/a//text()' -content_xpath = './/div[@class="serp-item__text"]//text()' - - -def request(query, params): - lang = params['language'].split('_')[0] - host = base_url.format(tld=language_map.get(lang) or default_tld) - params['url'] = host + search_url.format(page=params['pageno'] - 1, - query=urlencode({'text': query})) - return params - - -# get response from search-request -def response(resp): - dom = html.fromstring(resp.text) - results = [] - - for result in dom.xpath(results_xpath): - try: - res = {'url': result.xpath(url_xpath)[0], - 'title': escape(''.join(result.xpath(title_xpath))), - 'content': escape(''.join(result.xpath(content_xpath)))} - except: - logger.exception('yandex parse crash') - continue - - results.append(res) - - return results diff --git a/sources/searx/engines/youtube_api.py b/sources/searx/engines/youtube_api.py deleted file mode 100644 index 8fd939a..0000000 --- a/sources/searx/engines/youtube_api.py +++ /dev/null @@ -1,83 +0,0 @@ -# Youtube (Videos) -# -# @website https://www.youtube.com/ -# @provide-api yes (https://developers.google.com/apis-explorer/#p/youtube/v3/youtube.search.list) -# -# @using-api yes -# @results JSON -# @stable yes -# @parse url, title, content, publishedDate, thumbnail, embedded - -from json import loads -from urllib import urlencode -from dateutil import parser - -# engine dependent config -categories = ['videos', 'music'] -paging = False -language_support = True -api_key = None - -# search-url -base_url = 'https://www.googleapis.com/youtube/v3/search' -search_url = base_url + '?part=snippet&{query}&maxResults=20&key={api_key}' - -embedded_url = '' - -base_youtube_url = 'https://www.youtube.com/watch?v=' - - -# do search-request -def request(query, params): - params['url'] = search_url.format(query=urlencode({'q': query}), - api_key=api_key) - - # add language tag if specified - if params['language'] != 'all': - params['url'] += '&relevanceLanguage=' + params['language'].split('_')[0] - - return params - - -# get response from search-request -def response(resp): - results = [] - - search_results = loads(resp.text) - - # return empty array if there are no results - if 'items' not in search_results: - return [] - - # parse results - for result in search_results['items']: - videoid = result['id']['videoId'] - - title = result['snippet']['title'] - content = '' - thumbnail = '' - - pubdate = result['snippet']['publishedAt'] - publishedDate = parser.parse(pubdate) - - thumbnail = result['snippet']['thumbnails']['high']['url'] - - content = result['snippet']['description'] - - url = base_youtube_url + videoid - - embedded = embedded_url.format(videoid=videoid) - - # append result - results.append({'url': url, - 'title': title, - 'content': content, - 'template': 'videos.html', - 'publishedDate': publishedDate, - 'embedded': embedded, - 'thumbnail': thumbnail}) - - # return results - return results diff --git a/sources/searx/engines/youtube_noapi.py b/sources/searx/engines/youtube_noapi.py deleted file mode 100644 index 401fca4..0000000 --- a/sources/searx/engines/youtube_noapi.py +++ /dev/null @@ -1,81 +0,0 @@ -# Youtube (Videos) -# -# @website https://www.youtube.com/ -# @provide-api yes (https://developers.google.com/apis-explorer/#p/youtube/v3/youtube.search.list) -# -# @using-api no -# @results HTML -# @stable no -# @parse url, title, content, publishedDate, thumbnail, embedded - -from urllib import quote_plus -from lxml import html -from searx.engines.xpath import extract_text -from searx.utils import list_get - -# engine dependent config -categories = ['videos', 'music'] -paging = True -language_support = False - -# search-url -base_url = 'https://www.youtube.com/results' -search_url = base_url + '?search_query={query}&page={page}' - -embedded_url = '' - -base_youtube_url = 'https://www.youtube.com/watch?v=' - -# specific xpath variables -results_xpath = "//ol/li/div[contains(@class, 'yt-lockup yt-lockup-tile yt-lockup-video vve-check')]" -url_xpath = './/h3/a/@href' -title_xpath = './/div[@class="yt-lockup-content"]/h3/a' -content_xpath = './/div[@class="yt-lockup-content"]/div[@class="yt-lockup-description yt-ui-ellipsis yt-ui-ellipsis-2"]' - - -# returns extract_text on the first result selected by the xpath or None -def extract_text_from_dom(result, xpath): - r = result.xpath(xpath) - if len(r) > 0: - return extract_text(r[0]) - return None - - -# do search-request -def request(query, params): - params['url'] = search_url.format(query=quote_plus(query), - page=params['pageno']) - - return params - - -# get response from search-request -def response(resp): - results = [] - - dom = html.fromstring(resp.text) - - # parse results - for result in dom.xpath(results_xpath): - videoid = list_get(result.xpath('@data-context-item-id'), 0) - if videoid is not None: - url = base_youtube_url + videoid - thumbnail = 'https://i.ytimg.com/vi/' + videoid + '/hqdefault.jpg' - - title = extract_text_from_dom(result, title_xpath) or videoid - content = extract_text_from_dom(result, content_xpath) - - embedded = embedded_url.format(videoid=videoid) - - # append result - results.append({'url': url, - 'title': title, - 'content': content, - 'template': 'videos.html', - 'embedded': embedded, - 'thumbnail': thumbnail}) - - # return results - return results diff --git a/sources/searx/languages.py b/sources/searx/languages.py deleted file mode 100644 index 70459a5..0000000 --- a/sources/searx/languages.py +++ /dev/null @@ -1,78 +0,0 @@ -''' -searx is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -searx 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 Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with searx. If not, see < http://www.gnu.org/licenses/ >. - -(C) 2013- by Adam Tauber, -''' - -# list of language codes -language_codes = ( - ("ar_XA", "Arabic", "Arabia"), - ("bg_BG", "Bulgarian", "Bulgaria"), - ("cs_CZ", "Czech", "Czech Republic"), - ("da_DK", "Danish", "Denmark"), - ("de_AT", "German", "Austria"), - ("de_CH", "German", "Switzerland"), - ("de_DE", "German", "Germany"), - ("el_GR", "Greek", "Greece"), - ("en_AU", "English", "Australia"), - ("en_CA", "English", "Canada"), - ("en_GB", "English", "United Kingdom"), - ("en_ID", "English", "Indonesia"), - ("en_IE", "English", "Ireland"), - ("en_IN", "English", "India"), - ("en_MY", "English", "Malaysia"), - ("en_NZ", "English", "New Zealand"), - ("en_PH", "English", "Philippines"), - ("en_SG", "English", "Singapore"), - ("en_US", "English", "United States"), - ("en_XA", "English", "Arabia"), - ("en_ZA", "English", "South Africa"), - ("es_AR", "Spanish", "Argentina"), - ("es_CL", "Spanish", "Chile"), - ("es_ES", "Spanish", "Spain"), - ("es_MX", "Spanish", "Mexico"), - ("es_US", "Spanish", "United States"), - ("es_XL", "Spanish", "Latin America"), - ("et_EE", "Estonian", "Estonia"), - ("fi_FI", "Finnish", "Finland"), - ("fr_BE", "French", "Belgium"), - ("fr_CA", "French", "Canada"), - ("fr_CH", "French", "Switzerland"), - ("fr_FR", "French", "France"), - ("he_IL", "Hebrew", "Israel"), - ("hr_HR", "Croatian", "Croatia"), - ("hu_HU", "Hungarian", "Hungary"), - ("it_IT", "Italian", "Italy"), - ("ja_JP", "Japanese", "Japan"), - ("ko_KR", "Korean", "Korea"), - ("lt_LT", "Lithuanian", "Lithuania"), - ("lv_LV", "Latvian", "Latvia"), - ("nb_NO", "Norwegian", "Norway"), - ("nl_BE", "Dutch", "Belgium"), - ("nl_NL", "Dutch", "Netherlands"), - ("oc_OC", "Occitan", "Occitan"), - ("pl_PL", "Polish", "Poland"), - ("pt_BR", "Portuguese", "Brazil"), - ("pt_PT", "Portuguese", "Portugal"), - ("ro_RO", "Romanian", "Romania"), - ("ru_RU", "Russian", "Russia"), - ("sk_SK", "Slovak", "Slovak Republic"), - ("sl_SL", "Slovenian", "Slovenia"), - ("sv_SE", "Swedish", "Sweden"), - ("th_TH", "Thai", "Thailand"), - ("tr_TR", "Turkish", "Turkey"), - ("uk_UA", "Ukrainian", "Ukraine"), - ("zh_CN", "Chinese", "China"), - ("zh_HK", "Chinese", "Hong Kong SAR"), - ("zh_TW", "Chinese", "Taiwan")) diff --git a/sources/searx/plugins/__init__.py b/sources/searx/plugins/__init__.py deleted file mode 100644 index efb9b06..0000000 --- a/sources/searx/plugins/__init__.py +++ /dev/null @@ -1,81 +0,0 @@ -''' -searx is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -searx 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 Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with searx. If not, see < http://www.gnu.org/licenses/ >. - -(C) 2015 by Adam Tauber, -''' -from sys import exit -from searx import logger - -logger = logger.getChild('plugins') - -from searx.plugins import (https_rewrite, - open_results_on_new_tab, - self_info, - search_on_category_select, - tracker_url_remover, - vim_hotkeys) - -required_attrs = (('name', str), - ('description', str), - ('default_on', bool)) - -optional_attrs = (('js_dependencies', tuple), - ('css_dependencies', tuple)) - - -class Plugin(): - default_on = False - name = 'Default plugin' - description = 'Default plugin description' - - -class PluginStore(): - - def __init__(self): - self.plugins = [] - - def __iter__(self): - for plugin in self.plugins: - yield plugin - - def register(self, *plugins): - for plugin in plugins: - for plugin_attr, plugin_attr_type in required_attrs: - if not hasattr(plugin, plugin_attr) or not isinstance(getattr(plugin, plugin_attr), plugin_attr_type): - logger.critical('missing attribute "{0}", cannot load plugin: {1}'.format(plugin_attr, plugin)) - exit(3) - for plugin_attr, plugin_attr_type in optional_attrs: - if not hasattr(plugin, plugin_attr) or not isinstance(getattr(plugin, plugin_attr), plugin_attr_type): - setattr(plugin, plugin_attr, plugin_attr_type()) - plugin.id = plugin.name.replace(' ', '_') - self.plugins.append(plugin) - - def call(self, plugin_type, request, *args, **kwargs): - ret = True - for plugin in request.user_plugins: - if hasattr(plugin, plugin_type): - ret = getattr(plugin, plugin_type)(request, *args, **kwargs) - if not ret: - break - - return ret - - -plugins = PluginStore() -plugins.register(https_rewrite) -plugins.register(open_results_on_new_tab) -plugins.register(self_info) -plugins.register(search_on_category_select) -plugins.register(tracker_url_remover) -plugins.register(vim_hotkeys) diff --git a/sources/searx/plugins/https_rewrite.py b/sources/searx/plugins/https_rewrite.py deleted file mode 100644 index 0a58cc8..0000000 --- a/sources/searx/plugins/https_rewrite.py +++ /dev/null @@ -1,230 +0,0 @@ -''' -searx is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -searx 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 Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with searx. If not, see < http://www.gnu.org/licenses/ >. - -(C) 2013- by Adam Tauber, -''' - -import re -from urlparse import urlparse -from lxml import etree -from os import listdir, environ -from os.path import isfile, isdir, join -from searx.plugins import logger -from flask.ext.babel import gettext -from searx import searx_dir - - -name = "HTTPS rewrite" -description = gettext('Rewrite HTTP links to HTTPS if possible') -default_on = True - -if 'SEARX_HTTPS_REWRITE_PATH' in environ: - rules_path = environ['SEARX_rules_path'] -else: - rules_path = join(searx_dir, 'plugins/https_rules') - -logger = logger.getChild("https_rewrite") - -# https://gitweb.torproject.org/\ -# pde/https-everywhere.git/tree/4.0:/src/chrome/content/rules - -# HTTPS rewrite rules -https_rules = [] - - -# load single ruleset from a xml file -def load_single_https_ruleset(rules_path): - ruleset = () - - # init parser - parser = etree.XMLParser() - - # load and parse xml-file - try: - tree = etree.parse(rules_path, parser) - except: - # TODO, error message - return () - - # get root node - root = tree.getroot() - - # check if root is a node with the name ruleset - # TODO improve parsing - if root.tag != 'ruleset': - return () - - # check if rule is deactivated by default - if root.attrib.get('default_off'): - return () - - # check if rule does only work for specific platforms - if root.attrib.get('platform'): - return () - - hosts = [] - rules = [] - exclusions = [] - - # parse childs from ruleset - for ruleset in root: - # this child define a target - if ruleset.tag == 'target': - # check if required tags available - if not ruleset.attrib.get('host'): - continue - - # convert host-rule to valid regex - host = ruleset.attrib.get('host')\ - .replace('.', '\.').replace('*', '.*') - - # append to host list - hosts.append(host) - - # this child define a rule - elif ruleset.tag == 'rule': - # check if required tags available - if not ruleset.attrib.get('from')\ - or not ruleset.attrib.get('to'): - continue - - # TODO hack, which convert a javascript regex group - # into a valid python regex group - rule_from = ruleset.attrib['from'].replace('$', '\\') - if rule_from.endswith('\\'): - rule_from = rule_from[:-1] + '$' - rule_to = ruleset.attrib['to'].replace('$', '\\') - if rule_to.endswith('\\'): - rule_to = rule_to[:-1] + '$' - - # TODO, not working yet because of the hack above, - # currently doing that in webapp.py - # rule_from_rgx = re.compile(rule_from, re.I) - - # append rule - try: - rules.append((re.compile(rule_from, re.I | re.U), rule_to)) - except: - # TODO log regex error - continue - - # this child define an exclusion - elif ruleset.tag == 'exclusion': - # check if required tags available - if not ruleset.attrib.get('pattern'): - continue - - exclusion_rgx = re.compile(ruleset.attrib.get('pattern')) - - # append exclusion - exclusions.append(exclusion_rgx) - - # convert list of possible hosts to a simple regex - # TODO compress regex to improve performance - try: - target_hosts = re.compile('^(' + '|'.join(hosts) + ')', re.I | re.U) - except: - return () - - # return ruleset - return (target_hosts, rules, exclusions) - - -# load all https rewrite rules -def load_https_rules(rules_path): - # check if directory exists - if not isdir(rules_path): - logger.error("directory not found: '" + rules_path + "'") - return - - # search all xml files which are stored in the https rule directory - xml_files = [join(rules_path, f) - for f in listdir(rules_path) - if isfile(join(rules_path, f)) and f[-4:] == '.xml'] - - # load xml-files - for ruleset_file in xml_files: - # calculate rewrite-rules - ruleset = load_single_https_ruleset(ruleset_file) - - # skip if no ruleset returned - if not ruleset: - continue - - # append ruleset - https_rules.append(ruleset) - - logger.info('{n} rules loaded'.format(n=len(https_rules))) - - -def https_url_rewrite(result): - skip_https_rewrite = False - # check if HTTPS rewrite is possible - for target, rules, exclusions in https_rules: - - # check if target regex match with url - if target.match(result['parsed_url'].netloc): - # process exclusions - for exclusion in exclusions: - # check if exclusion match with url - if exclusion.match(result['url']): - skip_https_rewrite = True - break - - # skip https rewrite if required - if skip_https_rewrite: - break - - # process rules - for rule in rules: - try: - new_result_url = rule[0].sub(rule[1], result['url']) - except: - break - - # parse new url - new_parsed_url = urlparse(new_result_url) - - # continiue if nothing was rewritten - if result['url'] == new_result_url: - continue - - # get domainname from result - # TODO, does only work correct with TLD's like - # asdf.com, not for asdf.com.de - # TODO, using publicsuffix instead of this rewrite rule - old_result_domainname = '.'.join( - result['parsed_url'].hostname.split('.')[-2:]) - new_result_domainname = '.'.join( - new_parsed_url.hostname.split('.')[-2:]) - - # check if rewritten hostname is the same, - # to protect against wrong or malicious rewrite rules - if old_result_domainname == new_result_domainname: - # set new url - result['url'] = new_result_url - - # target has matched, do not search over the other rules - break - return result - - -def on_result(request, ctx): - result = ctx['result'] - if result['parsed_url'].scheme == 'http': - https_url_rewrite(result) - return True - - -load_https_rules(rules_path) diff --git a/sources/searx/plugins/https_rules/00README b/sources/searx/plugins/https_rules/00README deleted file mode 100644 index fcd8a77..0000000 --- a/sources/searx/plugins/https_rules/00README +++ /dev/null @@ -1,17 +0,0 @@ - diff --git a/sources/searx/plugins/https_rules/Bing.xml b/sources/searx/plugins/https_rules/Bing.xml deleted file mode 100644 index 8b403f1..0000000 --- a/sources/searx/plugins/https_rules/Bing.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/Dailymotion.xml b/sources/searx/plugins/https_rules/Dailymotion.xml deleted file mode 100644 index 743100c..0000000 --- a/sources/searx/plugins/https_rules/Dailymotion.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/Deviantart.xml b/sources/searx/plugins/https_rules/Deviantart.xml deleted file mode 100644 index 7830fc2..0000000 --- a/sources/searx/plugins/https_rules/Deviantart.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/DuckDuckGo.xml b/sources/searx/plugins/https_rules/DuckDuckGo.xml deleted file mode 100644 index 173a9ad..0000000 --- a/sources/searx/plugins/https_rules/DuckDuckGo.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/Flickr.xml b/sources/searx/plugins/https_rules/Flickr.xml deleted file mode 100644 index 85c6e80..0000000 --- a/sources/searx/plugins/https_rules/Flickr.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/Github-Pages.xml b/sources/searx/plugins/https_rules/Github-Pages.xml deleted file mode 100644 index d3be58a..0000000 --- a/sources/searx/plugins/https_rules/Github-Pages.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - diff --git a/sources/searx/plugins/https_rules/Github.xml b/sources/searx/plugins/https_rules/Github.xml deleted file mode 100644 index a9a3a1e..0000000 --- a/sources/searx/plugins/https_rules/Github.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/Google-mismatches.xml b/sources/searx/plugins/https_rules/Google-mismatches.xml deleted file mode 100644 index de9d3eb..0000000 --- a/sources/searx/plugins/https_rules/Google-mismatches.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/Google.org.xml b/sources/searx/plugins/https_rules/Google.org.xml deleted file mode 100644 index d6cc478..0000000 --- a/sources/searx/plugins/https_rules/Google.org.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/sources/searx/plugins/https_rules/GoogleAPIs.xml b/sources/searx/plugins/https_rules/GoogleAPIs.xml deleted file mode 100644 index 85a5a80..0000000 --- a/sources/searx/plugins/https_rules/GoogleAPIs.xml +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/GoogleCanada.xml b/sources/searx/plugins/https_rules/GoogleCanada.xml deleted file mode 100644 index d5eefe8..0000000 --- a/sources/searx/plugins/https_rules/GoogleCanada.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/sources/searx/plugins/https_rules/GoogleImages.xml b/sources/searx/plugins/https_rules/GoogleImages.xml deleted file mode 100644 index 0112001..0000000 --- a/sources/searx/plugins/https_rules/GoogleImages.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/GoogleMainSearch.xml b/sources/searx/plugins/https_rules/GoogleMainSearch.xml deleted file mode 100644 index df504d9..0000000 --- a/sources/searx/plugins/https_rules/GoogleMainSearch.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/GoogleMaps.xml b/sources/searx/plugins/https_rules/GoogleMaps.xml deleted file mode 100644 index 0f82c52..0000000 --- a/sources/searx/plugins/https_rules/GoogleMaps.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/GoogleMelange.xml b/sources/searx/plugins/https_rules/GoogleMelange.xml deleted file mode 100644 index ec23cd4..0000000 --- a/sources/searx/plugins/https_rules/GoogleMelange.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/sources/searx/plugins/https_rules/GoogleSearch.xml b/sources/searx/plugins/https_rules/GoogleSearch.xml deleted file mode 100644 index 66b7ffd..0000000 --- a/sources/searx/plugins/https_rules/GoogleSearch.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/GoogleServices.xml b/sources/searx/plugins/https_rules/GoogleServices.xml deleted file mode 100644 index 704646b..0000000 --- a/sources/searx/plugins/https_rules/GoogleServices.xml +++ /dev/null @@ -1,345 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/GoogleShopping.xml b/sources/searx/plugins/https_rules/GoogleShopping.xml deleted file mode 100644 index 6ba69a9..0000000 --- a/sources/searx/plugins/https_rules/GoogleShopping.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/GoogleSorry.xml b/sources/searx/plugins/https_rules/GoogleSorry.xml deleted file mode 100644 index 72a1921..0000000 --- a/sources/searx/plugins/https_rules/GoogleSorry.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/sources/searx/plugins/https_rules/GoogleTranslate.xml b/sources/searx/plugins/https_rules/GoogleTranslate.xml deleted file mode 100644 index a004025..0000000 --- a/sources/searx/plugins/https_rules/GoogleTranslate.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - diff --git a/sources/searx/plugins/https_rules/GoogleVideos.xml b/sources/searx/plugins/https_rules/GoogleVideos.xml deleted file mode 100644 index a5e88fc..0000000 --- a/sources/searx/plugins/https_rules/GoogleVideos.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/GoogleWatchBlog.xml b/sources/searx/plugins/https_rules/GoogleWatchBlog.xml deleted file mode 100644 index afec70c..0000000 --- a/sources/searx/plugins/https_rules/GoogleWatchBlog.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/sources/searx/plugins/https_rules/Google_App_Engine.xml b/sources/searx/plugins/https_rules/Google_App_Engine.xml deleted file mode 100644 index 851e051..0000000 --- a/sources/searx/plugins/https_rules/Google_App_Engine.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sources/searx/plugins/https_rules/Googleplex.com.xml b/sources/searx/plugins/https_rules/Googleplex.com.xml deleted file mode 100644 index 7ddbb5b..0000000 --- a/sources/searx/plugins/https_rules/Googleplex.com.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - diff --git a/sources/searx/plugins/https_rules/OpenStreetMap.xml b/sources/searx/plugins/https_rules/OpenStreetMap.xml deleted file mode 100644 index 58a6618..0000000 --- a/sources/searx/plugins/https_rules/OpenStreetMap.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/Rawgithub.com.xml b/sources/searx/plugins/https_rules/Rawgithub.com.xml deleted file mode 100644 index 3868f33..0000000 --- a/sources/searx/plugins/https_rules/Rawgithub.com.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/Soundcloud.xml b/sources/searx/plugins/https_rules/Soundcloud.xml deleted file mode 100644 index 6958e8c..0000000 --- a/sources/searx/plugins/https_rules/Soundcloud.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/ThePirateBay.xml b/sources/searx/plugins/https_rules/ThePirateBay.xml deleted file mode 100644 index 010387b..0000000 --- a/sources/searx/plugins/https_rules/ThePirateBay.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/Torproject.xml b/sources/searx/plugins/https_rules/Torproject.xml deleted file mode 100644 index 69269af..0000000 --- a/sources/searx/plugins/https_rules/Torproject.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/Twitter.xml b/sources/searx/plugins/https_rules/Twitter.xml deleted file mode 100644 index 3285f44..0000000 --- a/sources/searx/plugins/https_rules/Twitter.xml +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/Vimeo.xml b/sources/searx/plugins/https_rules/Vimeo.xml deleted file mode 100644 index f2a3e57..0000000 --- a/sources/searx/plugins/https_rules/Vimeo.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/WikiLeaks.xml b/sources/searx/plugins/https_rules/WikiLeaks.xml deleted file mode 100644 index 977709d..0000000 --- a/sources/searx/plugins/https_rules/WikiLeaks.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/sources/searx/plugins/https_rules/Wikimedia.xml b/sources/searx/plugins/https_rules/Wikimedia.xml deleted file mode 100644 index 9f25831..0000000 --- a/sources/searx/plugins/https_rules/Wikimedia.xml +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/Yahoo.xml b/sources/searx/plugins/https_rules/Yahoo.xml deleted file mode 100644 index 33548c4..0000000 --- a/sources/searx/plugins/https_rules/Yahoo.xml +++ /dev/null @@ -1,2450 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/https_rules/YouTube.xml b/sources/searx/plugins/https_rules/YouTube.xml deleted file mode 100644 index bddc2a5..0000000 --- a/sources/searx/plugins/https_rules/YouTube.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sources/searx/plugins/open_results_on_new_tab.py b/sources/searx/plugins/open_results_on_new_tab.py deleted file mode 100644 index 5ebece1..0000000 --- a/sources/searx/plugins/open_results_on_new_tab.py +++ /dev/null @@ -1,24 +0,0 @@ -''' -searx is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -searx 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 Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with searx. If not, see < http://www.gnu.org/licenses/ >. - -(C) 2016 by Adam Tauber, -''' -from flask.ext.babel import gettext -name = gettext('Open result links on new browser tabs') -description = gettext('Results are opened in the same window by default. ' - 'This plugin overwrites the default behaviour to open links on new tabs/windows. ' - '(JavaScript required)') -default_on = False - -js_dependencies = ('plugins/js/open_results_on_new_tab.js',) diff --git a/sources/searx/plugins/search_on_category_select.py b/sources/searx/plugins/search_on_category_select.py deleted file mode 100644 index 53585fa..0000000 --- a/sources/searx/plugins/search_on_category_select.py +++ /dev/null @@ -1,23 +0,0 @@ -''' -searx is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -searx 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 Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with searx. If not, see < http://www.gnu.org/licenses/ >. - -(C) 2015 by Adam Tauber, -''' -from flask.ext.babel import gettext -name = gettext('Search on category select') -description = gettext('Perform search immediately if a category selected. ' - 'Disable to select multiple categories. (JavaScript required)') -default_on = True - -js_dependencies = ('plugins/js/search_on_category_select.js',) diff --git a/sources/searx/plugins/self_info.py b/sources/searx/plugins/self_info.py deleted file mode 100644 index dc6b7cd..0000000 --- a/sources/searx/plugins/self_info.py +++ /dev/null @@ -1,44 +0,0 @@ -''' -searx is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -searx 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 Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with searx. If not, see < http://www.gnu.org/licenses/ >. - -(C) 2015 by Adam Tauber, -''' -from flask.ext.babel import gettext -import re -name = "Self Informations" -description = gettext('Displays your IP if the query is "ip" and your user agent if the query contains "user agent".') -default_on = True - - -# Self User Agent regex -p = re.compile('.*user[ -]agent.*', re.IGNORECASE) - - -# attach callback to the post search hook -# request: flask request object -# ctx: the whole local context of the pre search hook -def post_search(request, ctx): - if ctx['search'].query == 'ip': - x_forwarded_for = request.headers.getlist("X-Forwarded-For") - if x_forwarded_for: - ip = x_forwarded_for[0] - else: - ip = request.remote_addr - ctx['search'].result_container.answers.clear() - ctx['search'].result_container.answers.add(ip) - elif p.match(ctx['search'].query): - ua = request.user_agent - ctx['search'].result_container.answers.clear() - ctx['search'].result_container.answers.add(ua) - return True diff --git a/sources/searx/plugins/tracker_url_remover.py b/sources/searx/plugins/tracker_url_remover.py deleted file mode 100644 index ed71c94..0000000 --- a/sources/searx/plugins/tracker_url_remover.py +++ /dev/null @@ -1,44 +0,0 @@ -''' -searx is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -searx 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 Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with searx. If not, see < http://www.gnu.org/licenses/ >. - -(C) 2015 by Adam Tauber, -''' - -from flask.ext.babel import gettext -import re -from urlparse import urlunparse - -regexes = {re.compile(r'utm_[^&]+&?'), - re.compile(r'(wkey|wemail)[^&]+&?'), - re.compile(r'&$')} - -name = gettext('Tracker URL remover') -description = gettext('Remove trackers arguments from the returned URL') -default_on = True - - -def on_result(request, ctx): - query = ctx['result']['parsed_url'].query - - if query == "": - return True - - for reg in regexes: - query = reg.sub('', query) - - if query != ctx['result']['parsed_url'].query: - ctx['result']['parsed_url'] = ctx['result']['parsed_url']._replace(query=query) - ctx['result']['url'] = urlunparse(ctx['result']['parsed_url']) - - return True diff --git a/sources/searx/plugins/vim_hotkeys.py b/sources/searx/plugins/vim_hotkeys.py deleted file mode 100644 index e537a3a..0000000 --- a/sources/searx/plugins/vim_hotkeys.py +++ /dev/null @@ -1,10 +0,0 @@ -from flask.ext.babel import gettext - -name = gettext('Vim-like hotkeys') -description = gettext('Navigate search results with Vim-like hotkeys ' - '(JavaScript required). ' - 'Press "h" key on main or result page to get help.') -default_on = False - -js_dependencies = ('plugins/js/vim_hotkeys.js',) -css_dependencies = ('plugins/css/vim_hotkeys.css',) diff --git a/sources/searx/poolrequests.py b/sources/searx/poolrequests.py deleted file mode 100644 index f268df2..0000000 --- a/sources/searx/poolrequests.py +++ /dev/null @@ -1,112 +0,0 @@ -import requests - -from itertools import cycle -from threading import RLock -from searx import settings - - -class HTTPAdapterWithConnParams(requests.adapters.HTTPAdapter): - - def __init__(self, pool_connections=requests.adapters.DEFAULT_POOLSIZE, - pool_maxsize=requests.adapters.DEFAULT_POOLSIZE, - max_retries=requests.adapters.DEFAULT_RETRIES, - pool_block=requests.adapters.DEFAULT_POOLBLOCK, - **conn_params): - if max_retries == requests.adapters.DEFAULT_RETRIES: - self.max_retries = requests.adapters.Retry(0, read=False) - else: - self.max_retries = requests.adapters.Retry.from_int(max_retries) - self.config = {} - self.proxy_manager = {} - - super(requests.adapters.HTTPAdapter, self).__init__() - - self._pool_connections = pool_connections - self._pool_maxsize = pool_maxsize - self._pool_block = pool_block - self._conn_params = conn_params - - self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block, **conn_params) - - def __setstate__(self, state): - # Can't handle by adding 'proxy_manager' to self.__attrs__ because - # because self.poolmanager uses a lambda function, which isn't pickleable. - self.proxy_manager = {} - self.config = {} - - for attr, value in state.items(): - setattr(self, attr, value) - - self.init_poolmanager(self._pool_connections, self._pool_maxsize, - block=self._pool_block, **self._conn_params) - - -connect = settings['outgoing'].get('pool_connections', 100) # Magic number kept from previous code -maxsize = settings['outgoing'].get('pool_maxsize', requests.adapters.DEFAULT_POOLSIZE) # Picked from constructor -if settings['outgoing'].get('source_ips'): - http_adapters = cycle(HTTPAdapterWithConnParams(pool_connections=connect, pool_maxsize=maxsize, - source_address=(source_ip, 0)) - for source_ip in settings['outgoing']['source_ips']) - https_adapters = cycle(HTTPAdapterWithConnParams(pool_connections=connect, pool_maxsize=maxsize, - source_address=(source_ip, 0)) - for source_ip in settings['outgoing']['source_ips']) -else: - http_adapters = cycle((HTTPAdapterWithConnParams(pool_connections=connect, pool_maxsize=maxsize), )) - https_adapters = cycle((HTTPAdapterWithConnParams(pool_connections=connect, pool_maxsize=maxsize), )) - - -class SessionSinglePool(requests.Session): - - def __init__(self): - super(SessionSinglePool, self).__init__() - - # reuse the same adapters - with RLock(): - self.adapters.clear() - self.mount('https://', next(https_adapters)) - self.mount('http://', next(http_adapters)) - - def close(self): - """Call super, but clear adapters since there are managed globaly""" - self.adapters.clear() - super(SessionSinglePool, self).close() - - -def request(method, url, **kwargs): - """same as requests/requests/api.py request(...) except it use SessionSinglePool and force proxies""" - session = SessionSinglePool() - kwargs['proxies'] = settings['outgoing'].get('proxies', None) - response = session.request(method=method, url=url, **kwargs) - session.close() - return response - - -def get(url, **kwargs): - kwargs.setdefault('allow_redirects', True) - return request('get', url, **kwargs) - - -def options(url, **kwargs): - kwargs.setdefault('allow_redirects', True) - return request('options', url, **kwargs) - - -def head(url, **kwargs): - kwargs.setdefault('allow_redirects', False) - return request('head', url, **kwargs) - - -def post(url, data=None, **kwargs): - return request('post', url, data=data, **kwargs) - - -def put(url, data=None, **kwargs): - return request('put', url, data=data, **kwargs) - - -def patch(url, data=None, **kwargs): - return request('patch', url, data=data, **kwargs) - - -def delete(url, **kwargs): - return request('delete', url, **kwargs) diff --git a/sources/searx/preferences.py b/sources/searx/preferences.py deleted file mode 100644 index dd9133d..0000000 --- a/sources/searx/preferences.py +++ /dev/null @@ -1,276 +0,0 @@ -from searx import settings, autocomplete -from searx.languages import language_codes as languages - - -COOKIE_MAX_AGE = 60 * 60 * 24 * 365 * 5 # 5 years -LANGUAGE_CODES = [l[0] for l in languages] -LANGUAGE_CODES.append('all') -DISABLED = 0 -ENABLED = 1 - - -class MissingArgumentException(Exception): - pass - - -class ValidationException(Exception): - pass - - -class Setting(object): - """Base class of user settings""" - - def __init__(self, default_value, **kwargs): - super(Setting, self).__init__() - self.value = default_value - for key, value in kwargs.iteritems(): - setattr(self, key, value) - - self._post_init() - - def _post_init(self): - pass - - def parse(self, data): - self.value = data - - def get_value(self): - return self.value - - def save(self, name, resp): - resp.set_cookie(name, bytes(self.value), max_age=COOKIE_MAX_AGE) - - -class StringSetting(Setting): - """Setting of plain string values""" - pass - - -class EnumStringSetting(Setting): - """Setting of a value which can only come from the given choices""" - - def _post_init(self): - if not hasattr(self, 'choices'): - raise MissingArgumentException('Missing argument: choices') - - if self.value != '' and self.value not in self.choices: - raise ValidationException('Invalid default value: {0}'.format(self.value)) - - def parse(self, data): - if data not in self.choices and data != self.value: - raise ValidationException('Invalid choice: {0}'.format(data)) - self.value = data - - -class MultipleChoiceSetting(EnumStringSetting): - """Setting of values which can only come from the given choices""" - - def _post_init(self): - if not hasattr(self, 'choices'): - raise MissingArgumentException('Missing argument: choices') - for item in self.value: - if item not in self.choices: - raise ValidationException('Invalid default value: {0}'.format(self.value)) - - def parse(self, data): - if data == '': - self.value = [] - return - - elements = data.split(',') - for item in elements: - if item not in self.choices: - raise ValidationException('Invalid choice: {0}'.format(item)) - self.value = elements - - def parse_form(self, data): - self.value = [] - for choice in data: - if choice in self.choices and choice not in self.value: - self.value.append(choice) - - def save(self, name, resp): - resp.set_cookie(name, ','.join(self.value), max_age=COOKIE_MAX_AGE) - - -class MapSetting(Setting): - """Setting of a value that has to be translated in order to be storable""" - - def _post_init(self): - if not hasattr(self, 'map'): - raise MissingArgumentException('missing argument: map') - if self.value not in self.map.values(): - raise ValidationException('Invalid default value') - - def parse(self, data): - if data not in self.map: - raise ValidationException('Invalid choice: {0}'.format(data)) - self.value = self.map[data] - self.key = data - - def save(self, name, resp): - resp.set_cookie(name, bytes(self.key), max_age=COOKIE_MAX_AGE) - - -class SwitchableSetting(Setting): - """ Base class for settings that can be turned on && off""" - - def _post_init(self): - self.disabled = set() - self.enabled = set() - if not hasattr(self, 'choices'): - raise MissingArgumentException('missing argument: choices') - - def transform_form_items(self, items): - return items - - def transform_values(self, values): - return values - - def parse_cookie(self, data): - if data[DISABLED] != '': - self.disabled = set(data[DISABLED].split(',')) - if data[ENABLED] != '': - self.enabled = set(data[ENABLED].split(',')) - - def parse_form(self, items): - items = self.transform_form_items(items) - - self.disabled = set() - self.enabled = set() - for choice in self.choices: - if choice['default_on']: - if choice['id'] in items: - self.disabled.add(choice['id']) - else: - if choice['id'] not in items: - self.enabled.add(choice['id']) - - def save(self, resp): - resp.set_cookie('disabled_{0}'.format(self.value), ','.join(self.disabled), max_age=COOKIE_MAX_AGE) - resp.set_cookie('enabled_{0}'.format(self.value), ','.join(self.enabled), max_age=COOKIE_MAX_AGE) - - def get_disabled(self): - disabled = self.disabled - for choice in self.choices: - if not choice['default_on'] and choice['id'] not in self.enabled: - disabled.add(choice['id']) - return self.transform_values(disabled) - - def get_enabled(self): - enabled = self.enabled - for choice in self.choices: - if choice['default_on'] and choice['id'] not in self.disabled: - enabled.add(choice['id']) - return self.transform_values(enabled) - - -class EnginesSetting(SwitchableSetting): - def _post_init(self): - super(EnginesSetting, self)._post_init() - transformed_choices = [] - for engine_name, engine in self.choices.iteritems(): - for category in engine.categories: - transformed_choice = dict() - transformed_choice['default_on'] = not engine.disabled - transformed_choice['id'] = '{}__{}'.format(engine_name, category) - transformed_choices.append(transformed_choice) - self.choices = transformed_choices - - def transform_form_items(self, items): - return [item[len('engine_'):].replace('_', ' ').replace(' ', '__') for item in items] - - def transform_values(self, values): - if len(values) == 1 and next(iter(values)) == '': - return list() - transformed_values = [] - for value in values: - engine, category = value.split('__') - transformed_values.append((engine, category)) - return transformed_values - - -class PluginsSetting(SwitchableSetting): - def _post_init(self): - super(PluginsSetting, self)._post_init() - transformed_choices = [] - for plugin in self.choices: - transformed_choice = dict() - transformed_choice['default_on'] = plugin.default_on - transformed_choice['id'] = plugin.id - transformed_choices.append(transformed_choice) - self.choices = transformed_choices - - def transform_form_items(self, items): - return [item[len('plugin_'):] for item in items] - - -class Preferences(object): - """Stores, validates and saves preferences to cookies""" - - def __init__(self, themes, categories, engines, plugins): - super(Preferences, self).__init__() - - self.key_value_settings = {'categories': MultipleChoiceSetting(['general'], choices=categories), - 'language': EnumStringSetting('all', choices=LANGUAGE_CODES), - 'locale': EnumStringSetting(settings['ui']['default_locale'], - choices=settings['locales'].keys()), - 'autocomplete': EnumStringSetting(settings['search']['autocomplete'], - choices=autocomplete.backends.keys()), - 'image_proxy': MapSetting(settings['server']['image_proxy'], - map={'': settings['server']['image_proxy'], - '0': False, - '1': True}), - 'method': EnumStringSetting('POST', choices=('GET', 'POST')), - 'safesearch': MapSetting(settings['search']['safe_search'], map={'0': 0, - '1': 1, - '2': 2}), - 'theme': EnumStringSetting(settings['ui']['default_theme'], choices=themes)} - - self.engines = EnginesSetting('engines', choices=engines) - self.plugins = PluginsSetting('plugins', choices=plugins) - self.unknown_params = {} - - def parse_cookies(self, input_data): - for user_setting_name, user_setting in input_data.iteritems(): - if user_setting_name in self.key_value_settings: - self.key_value_settings[user_setting_name].parse(user_setting) - elif user_setting_name == 'disabled_engines': - self.engines.parse_cookie((input_data.get('disabled_engines', ''), - input_data.get('enabled_engines', ''))) - elif user_setting_name == 'disabled_plugins': - self.plugins.parse_cookie((input_data.get('disabled_plugins', ''), - input_data.get('enabled_plugins', ''))) - - def parse_form(self, input_data): - disabled_engines = [] - enabled_categories = [] - disabled_plugins = [] - for user_setting_name, user_setting in input_data.iteritems(): - if user_setting_name in self.key_value_settings: - self.key_value_settings[user_setting_name].parse(user_setting) - elif user_setting_name.startswith('engine_'): - disabled_engines.append(user_setting_name) - elif user_setting_name.startswith('category_'): - enabled_categories.append(user_setting_name[len('category_'):]) - elif user_setting_name.startswith('plugin_'): - disabled_plugins.append(user_setting_name) - else: - self.unknown_params[user_setting_name] = user_setting - self.key_value_settings['categories'].parse_form(enabled_categories) - self.engines.parse_form(disabled_engines) - self.plugins.parse_form(disabled_plugins) - - # cannot be used in case of engines or plugins - def get_value(self, user_setting_name): - if user_setting_name in self.key_value_settings: - return self.key_value_settings[user_setting_name].get_value() - - def save(self, resp): - for user_setting_name, user_setting in self.key_value_settings.iteritems(): - user_setting.save(user_setting_name, resp) - self.engines.save(resp) - self.plugins.save(resp) - for k, v in self.unknown_params.items(): - resp.set_cookie(k, v, max_age=COOKIE_MAX_AGE) - return resp diff --git a/sources/searx/query.py b/sources/searx/query.py deleted file mode 100644 index 3d617ab..0000000 --- a/sources/searx/query.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env python - -''' -searx is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -searx 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 Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with searx. If not, see < http://www.gnu.org/licenses/ >. - -(C) 2014 by Thomas Pointhuber, -''' - -from searx.languages import language_codes -from searx.engines import ( - categories, engines, engine_shortcuts -) -import string -import re - - -class Query(object): - """parse query""" - - def __init__(self, query, disabled_engines): - self.query = query - self.disabled_engines = [] - - if disabled_engines: - self.disabled_engines = disabled_engines - - self.query_parts = [] - self.engines = [] - self.languages = [] - self.specific = False - - # parse query, if tags are set, which - # change the serch engine or search-language - def parse_query(self): - self.query_parts = [] - - # split query, including whitespaces - raw_query_parts = re.split(r'(\s+)', self.query) - - parse_next = True - - for query_part in raw_query_parts: - if not parse_next: - self.query_parts[-1] += query_part - continue - - parse_next = False - - # part does only contain spaces, skip - if query_part.isspace()\ - or query_part == '': - parse_next = True - self.query_parts.append(query_part) - continue - - # this force a language - if query_part[0] == ':': - lang = query_part[1:].lower() - - # check if any language-code is equal with - # declared language-codes - for lc in language_codes: - lang_id, lang_name, country = map(str.lower, lc) - - # if correct language-code is found - # set it as new search-language - if lang == lang_id\ - or lang_id.startswith(lang)\ - or lang == lang_name\ - or lang.replace('_', ' ') == country: - parse_next = True - self.languages.append(lang) - break - - # this force a engine or category - if query_part[0] == '!' or query_part[0] == '?': - prefix = query_part[1:].replace('_', ' ') - - # check if prefix is equal with engine shortcut - if prefix in engine_shortcuts: - parse_next = True - self.engines.append({'category': 'none', - 'name': engine_shortcuts[prefix]}) - - # check if prefix is equal with engine name - elif prefix in engines: - parse_next = True - self.engines.append({'category': 'none', - 'name': prefix}) - - # check if prefix is equal with categorie name - elif prefix in categories: - # using all engines for that search, which - # are declared under that categorie name - parse_next = True - self.engines.extend({'category': prefix, - 'name': engine.name} - for engine in categories[prefix] - if (engine.name, prefix) not in self.disabled_engines) - - if query_part[0] == '!': - self.specific = True - - # append query part to query_part list - self.query_parts.append(query_part) - - def changeSearchQuery(self, search_query): - if len(self.query_parts): - self.query_parts[-1] = search_query - else: - self.query_parts.append(search_query) - - def getSearchQuery(self): - if len(self.query_parts): - return self.query_parts[-1] - else: - return '' - - def getFullQuery(self): - # get full querry including whitespaces - return string.join(self.query_parts, '') diff --git a/sources/searx/results.py b/sources/searx/results.py deleted file mode 100644 index dcd966e..0000000 --- a/sources/searx/results.py +++ /dev/null @@ -1,254 +0,0 @@ -import re -from collections import defaultdict -from operator import itemgetter -from threading import RLock -from urlparse import urlparse, unquote -from searx.engines import engines - -CONTENT_LEN_IGNORED_CHARS_REGEX = re.compile('[,;:!?\./\\\\ ()-_]', re.M | re.U) -WHITESPACE_REGEX = re.compile('( |\t|\n)+', re.M | re.U) - - -# return the meaningful length of the content for a result -def result_content_len(content): - if isinstance(content, basestring): - return len(CONTENT_LEN_IGNORED_CHARS_REGEX.sub('', content)) - else: - return 0 - - -def compare_urls(url_a, url_b): - if url_a.netloc != url_b.netloc or url_a.query != url_b.query: - return False - - # remove / from the end of the url if required - path_a = url_a.path[:-1]\ - if url_a.path.endswith('/')\ - else url_a.path - path_b = url_b.path[:-1]\ - if url_b.path.endswith('/')\ - else url_b.path - - return unquote(path_a) == unquote(path_b) - - -def merge_two_infoboxes(infobox1, infobox2): - if 'urls' in infobox2: - urls1 = infobox1.get('urls', None) - if urls1 is None: - urls1 = [] - infobox1['urls'] = urls1 - - urlSet = set() - for url in infobox1.get('urls', []): - urlSet.add(url.get('url', None)) - - for url in infobox2.get('urls', []): - if url.get('url', None) not in urlSet: - urls1.append(url) - - if 'img_src' in infobox2: - img1 = infobox1.get('img_src', None) - img2 = infobox2.get('img_src') - if img1 is None: - infobox1['img_src'] = img2 - - if 'attributes' in infobox2: - attributes1 = infobox1.get('attributes', None) - if attributes1 is None: - attributes1 = [] - infobox1['attributes'] = attributes1 - - attributeSet = set() - for attribute in infobox1.get('attributes', []): - if attribute.get('label', None) not in attributeSet: - attributeSet.add(attribute.get('label', None)) - - for attribute in infobox2.get('attributes', []): - attributes1.append(attribute) - - if 'content' in infobox2: - content1 = infobox1.get('content', None) - content2 = infobox2.get('content', '') - if content1 is not None: - if result_content_len(content2) > result_content_len(content1): - infobox1['content'] = content2 - else: - infobox1['content'] = content2 - - -def result_score(result): - weight = 1.0 - - for result_engine in result['engines']: - if hasattr(engines[result_engine], 'weight'): - weight *= float(engines[result_engine].weight) - - occurences = len(result['positions']) - - return sum((occurences * weight) / position for position in result['positions']) - - -class ResultContainer(object): - """docstring for ResultContainer""" - def __init__(self): - super(ResultContainer, self).__init__() - self.results = defaultdict(list) - self._merged_results = [] - self.infoboxes = [] - self._infobox_ids = {} - self.suggestions = set() - self.answers = set() - self.number_of_results = 0 - - def extend(self, engine_name, results): - for result in list(results): - if 'suggestion' in result: - self.suggestions.add(result['suggestion']) - results.remove(result) - elif 'answer' in result: - self.answers.add(result['answer']) - results.remove(result) - elif 'infobox' in result: - self._merge_infobox(result) - results.remove(result) - elif 'number_of_results' in result: - self.number_of_results = max(self.number_of_results, result['number_of_results']) - results.remove(result) - - with RLock(): - engines[engine_name].stats['search_count'] += 1 - engines[engine_name].stats['result_count'] += len(results) - - if not results: - return - - self.results[engine_name].extend(results) - - for i, result in enumerate(results): - try: - result['url'] = result['url'].decode('utf-8') - except: - pass - position = i + 1 - self._merge_result(result, position) - - def _merge_infobox(self, infobox): - add_infobox = True - infobox_id = infobox.get('id', None) - if infobox_id is not None: - existingIndex = self._infobox_ids.get(infobox_id, None) - if existingIndex is not None: - merge_two_infoboxes(self.infoboxes[existingIndex], infobox) - add_infobox = False - - if add_infobox: - self.infoboxes.append(infobox) - self._infobox_ids[infobox_id] = len(self.infoboxes) - 1 - - def _merge_result(self, result, position): - result['parsed_url'] = urlparse(result['url']) - - # if the result has no scheme, use http as default - if not result['parsed_url'].scheme: - result['parsed_url'] = result['parsed_url']._replace(scheme="http") - result['url'] = result['parsed_url'].geturl() - - result['host'] = result['parsed_url'].netloc - - if result['host'].startswith('www.'): - result['host'] = result['host'].replace('www.', '', 1) - - result['engines'] = [result['engine']] - - # strip multiple spaces and cariage returns from content - if result.get('content'): - result['content'] = WHITESPACE_REGEX.sub(' ', result['content']) - - # check for duplicates - duplicated = False - for merged_result in self._merged_results: - if compare_urls(result['parsed_url'], merged_result['parsed_url'])\ - and result.get('template') == merged_result.get('template'): - duplicated = merged_result - break - - # merge duplicates together - if duplicated: - # using content with more text - if result_content_len(result.get('content', '')) >\ - result_content_len(duplicated.get('content', '')): - duplicated['content'] = result['content'] - - # add the new position - duplicated['positions'].append(position) - - # add engine to list of result-engines - duplicated['engines'].append(result['engine']) - - # using https if possible - if duplicated['parsed_url'].scheme != 'https' and result['parsed_url'].scheme == 'https': - duplicated['url'] = result['parsed_url'].geturl() - duplicated['parsed_url'] = result['parsed_url'] - - # if there is no duplicate found, append result - else: - result['positions'] = [position] - with RLock(): - self._merged_results.append(result) - - def get_ordered_results(self): - for result in self._merged_results: - score = result_score(result) - result['score'] = score - with RLock(): - for result_engine in result['engines']: - engines[result_engine].stats['score_count'] += score - - results = sorted(self._merged_results, key=itemgetter('score'), reverse=True) - - # pass 2 : group results by category and template - gresults = [] - categoryPositions = {} - - for i, res in enumerate(results): - # FIXME : handle more than one category per engine - category = engines[res['engine']].categories[0] + ':' + ''\ - if 'template' not in res\ - else res['template'] - - current = None if category not in categoryPositions\ - else categoryPositions[category] - - # group with previous results using the same category - # if the group can accept more result and is not too far - # from the current position - if current is not None and (current['count'] > 0)\ - and (len(gresults) - current['index'] < 20): - # group with the previous results using - # the same category with this one - index = current['index'] - gresults.insert(index, res) - - # update every index after the current one - # (including the current one) - for k in categoryPositions: - v = categoryPositions[k]['index'] - if v >= index: - categoryPositions[k]['index'] = v + 1 - - # update this category - current['count'] -= 1 - - else: - # same category - gresults.append(res) - - # update categoryIndex - categoryPositions[category] = {'index': len(gresults), 'count': 8} - - # return gresults - return gresults - - def results_length(self): - return len(self._merged_results) diff --git a/sources/searx/search.py b/sources/searx/search.py deleted file mode 100644 index a408016..0000000 --- a/sources/searx/search.py +++ /dev/null @@ -1,344 +0,0 @@ -''' -searx is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -searx 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 Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with searx. If not, see < http://www.gnu.org/licenses/ >. - -(C) 2013- by Adam Tauber, -''' - -import threading -import searx.poolrequests as requests_lib -from time import time -from searx import settings -from searx.engines import ( - categories, engines -) -from searx.languages import language_codes -from searx.utils import gen_useragent -from searx.query import Query -from searx.results import ResultContainer -from searx import logger - -logger = logger.getChild('search') - -number_of_searches = 0 - - -def search_request_wrapper(fn, url, engine_name, **kwargs): - ret = None - engine = engines[engine_name] - try: - ret = fn(url, **kwargs) - with threading.RLock(): - engine.continuous_errors = 0 - engine.suspend_end_time = 0 - except: - # increase errors stats - with threading.RLock(): - engine.stats['errors'] += 1 - engine.continuous_errors += 1 - engine.suspend_end_time = time() + min(60, engine.continuous_errors) - - # print engine name and specific error message - logger.exception('engine crash: {0}'.format(engine_name)) - return ret - - -def threaded_requests(requests): - timeout_limit = max(r[2]['timeout'] for r in requests) - search_start = time() - for fn, url, request_args, engine_name in requests: - request_args['timeout'] = timeout_limit - th = threading.Thread( - target=search_request_wrapper, - args=(fn, url, engine_name), - kwargs=request_args, - name='search_request', - ) - th._engine_name = engine_name - th.start() - - for th in threading.enumerate(): - if th.name == 'search_request': - remaining_time = max(0.0, timeout_limit - (time() - search_start)) - th.join(remaining_time) - if th.isAlive(): - logger.warning('engine timeout: {0}'.format(th._engine_name)) - - -# get default reqest parameter -def default_request_params(): - return { - 'method': 'GET', - 'headers': {}, - 'data': {}, - 'url': '', - 'cookies': {}, - 'verify': True - } - - -# create a callback wrapper for the search engine results -def make_callback(engine_name, callback, params, result_container): - - # creating a callback wrapper for the search engine results - def process_callback(response, **kwargs): - # check if redirect comparing to the True value, - # because resp can be a Mock object, and any attribut name returns something. - if response.is_redirect is True: - logger.debug('{0} redirect on: {1}'.format(engine_name, response)) - return - - response.search_params = params - - search_duration = time() - params['started'] - # update stats with current page-load-time - with threading.RLock(): - engines[engine_name].stats['page_load_time'] += search_duration - - timeout_overhead = 0.2 # seconds - timeout_limit = engines[engine_name].timeout + timeout_overhead - - if search_duration > timeout_limit: - with threading.RLock(): - engines[engine_name].stats['errors'] += 1 - return - - # callback - search_results = callback(response) - - # add results - for result in search_results: - result['engine'] = engine_name - - result_container.extend(engine_name, search_results) - - return process_callback - - -class Search(object): - - """Search information container""" - - def __init__(self, request): - # init vars - super(Search, self).__init__() - self.query = None - self.engines = [] - self.categories = [] - self.paging = False - self.pageno = 1 - self.lang = 'all' - - # set blocked engines - self.disabled_engines = request.preferences.engines.get_disabled() - - self.result_container = ResultContainer() - self.request_data = {} - - # set specific language if set - self.lang = request.preferences.get_value('language') - - # set request method - if request.method == 'POST': - self.request_data = request.form - else: - self.request_data = request.args - - # TODO better exceptions - if not self.request_data.get('q'): - raise Exception('noquery') - - # set pagenumber - pageno_param = self.request_data.get('pageno', '1') - if not pageno_param.isdigit() or int(pageno_param) < 1: - pageno_param = 1 - - self.pageno = int(pageno_param) - - # parse query, if tags are set, which change - # the serch engine or search-language - query_obj = Query(self.request_data['q'], self.disabled_engines) - query_obj.parse_query() - - # set query - self.query = query_obj.getSearchQuery() - - # get last selected language in query, if possible - # TODO support search with multible languages - if len(query_obj.languages): - self.lang = query_obj.languages[-1] - - self.engines = query_obj.engines - - self.categories = [] - - # if engines are calculated from query, - # set categories by using that informations - if self.engines and query_obj.specific: - self.categories = list(set(engine['category'] - for engine in self.engines)) - - # otherwise, using defined categories to - # calculate which engines should be used - else: - # set categories/engines - load_default_categories = True - for pd_name, pd in self.request_data.items(): - if pd_name == 'categories': - self.categories.extend(categ for categ in map(unicode.strip, pd.split(',')) if categ in categories) - elif pd_name == 'engines': - pd_engines = [{'category': engines[engine].categories[0], - 'name': engine} - for engine in map(unicode.strip, pd.split(',')) if engine in engines] - if pd_engines: - self.engines.extend(pd_engines) - load_default_categories = False - elif pd_name.startswith('category_'): - category = pd_name[9:] - - # if category is not found in list, skip - if category not in categories: - continue - - if pd != 'off': - # add category to list - self.categories.append(category) - elif category in self.categories: - # remove category from list if property is set to 'off' - self.categories.remove(category) - - if not load_default_categories: - if not self.categories: - self.categories = list(set(engine['category'] - for engine in self.engines)) - return - - # if no category is specified for this search, - # using user-defined default-configuration which - # (is stored in cookie) - if not self.categories: - cookie_categories = request.preferences.get_value('categories') - for ccateg in cookie_categories: - if ccateg in categories: - self.categories.append(ccateg) - - # if still no category is specified, using general - # as default-category - if not self.categories: - self.categories = ['general'] - - # using all engines for that search, which are - # declared under the specific categories - for categ in self.categories: - self.engines.extend({'category': categ, - 'name': engine.name} - for engine in categories[categ] - if (engine.name, categ) not in self.disabled_engines) - - # remove suspended engines - self.engines = [e for e in self.engines - if engines[e['name']].suspend_end_time <= time()] - - # do search-request - def search(self, request): - global number_of_searches - - # init vars - requests = [] - - # increase number of searches - number_of_searches += 1 - - # set default useragent - # user_agent = request.headers.get('User-Agent', '') - user_agent = gen_useragent() - - # start search-reqest for all selected engines - for selected_engine in self.engines: - if selected_engine['name'] not in engines: - continue - - engine = engines[selected_engine['name']] - - # if paging is not supported, skip - if self.pageno > 1 and not engine.paging: - continue - - # if search-language is set and engine does not - # provide language-support, skip - if self.lang != 'all' and not engine.language_support: - continue - - # set default request parameters - request_params = default_request_params() - request_params['headers']['User-Agent'] = user_agent - request_params['category'] = selected_engine['category'] - request_params['started'] = time() - request_params['pageno'] = self.pageno - - if hasattr(engine, 'language') and engine.language: - request_params['language'] = engine.language - else: - request_params['language'] = self.lang - - # 0 = None, 1 = Moderate, 2 = Strict - request_params['safesearch'] = request.preferences.get_value('safesearch') - - # update request parameters dependent on - # search-engine (contained in engines folder) - engine.request(self.query.encode('utf-8'), request_params) - - if request_params['url'] is None: - # TODO add support of offline engines - pass - - # create a callback wrapper for the search engine results - callback = make_callback( - selected_engine['name'], - engine.response, - request_params, - self.result_container) - - # create dictionary which contain all - # informations about the request - request_args = dict( - headers=request_params['headers'], - hooks=dict(response=callback), - cookies=request_params['cookies'], - timeout=engine.timeout, - verify=request_params['verify'] - ) - - # specific type of request (GET or POST) - if request_params['method'] == 'GET': - req = requests_lib.get - else: - req = requests_lib.post - request_args['data'] = request_params['data'] - - # ignoring empty urls - if not request_params['url']: - continue - - # append request to list - requests.append((req, request_params['url'], - request_args, - selected_engine['name'])) - - if not requests: - return self - # send all search-request - threaded_requests(requests) - - # return results, suggestions, answers and infoboxes - return self diff --git a/sources/searx/settings.yml b/sources/searx/settings.yml deleted file mode 100644 index 9308756..0000000 --- a/sources/searx/settings.yml +++ /dev/null @@ -1,467 +0,0 @@ -general: - debug : False # Debug mode, only for development - instance_name : "searx" # displayed name - -search: - safe_search : 0 # Filter results. 0: None, 1: Moderate, 2: Strict - autocomplete : "" # Existing autocomplete backends: "dbpedia", "duckduckgo", "google", "startpage", "wikipedia" - leave blank to turn it off by default - -server: - port : 8888 - bind_address : "127.0.0.1" # address to listen on - secret_key : "ultrasecretkey" # change this! - base_url : False # Set custom base_url. Possible values: False or "https://your.custom.host/location/" - image_proxy : False # Proxying image results through searx - -ui: - themes_path : "" # Custom ui themes path - leave it blank if you didn't change - default_theme : oscar # ui theme - default_locale : "" # Default interface locale - leave blank to detect from browser information or use codes from the 'locales' config section - -outgoing: # communication with search engines - request_timeout : 2.0 # seconds - useragent_suffix : "" # suffix of searx_useragent, could contain informations like an email address to the administrator - pool_connections : 100 # Number of different hosts - pool_maxsize : 10 # Number of simultaneous requests by host -# uncomment below section if you want to use a proxy -# see http://docs.python-requests.org/en/latest/user/advanced/#proxies -# SOCKS proxies are not supported : see https://github.com/kennethreitz/requests/pull/478 -# proxies : -# http : http://127.0.0.1:8080 -# https: http://127.0.0.1:8080 -# uncomment below section only if you have more than one network interface -# which can be the source of outgoing search requests -# source_ips: -# - 1.1.1.1 -# - 1.1.1.2 - -engines: - - name : arch linux wiki - engine : archlinux - shortcut : al - - - name : archive is - engine : xpath - search_url : https://archive.is/{query} - url_xpath : (//div[@class="TEXT-BLOCK"]/a)/@href - title_xpath : (//div[@class="TEXT-BLOCK"]/a) - content_xpath : //div[@class="TEXT-BLOCK"]/ul/li - categories : general - timeout : 7.0 - disabled : True - shortcut : ai - - - name : base - engine : base - shortcut : bs - - - name : wikipedia - engine : wikipedia - shortcut : wp - base_url : 'https://{language}.wikipedia.org/' - - - name : bing - engine : bing - shortcut : bi - - - name : bing images - engine : bing_images - shortcut : bii - - - name : bing news - engine : bing_news - shortcut : bin - - - name : bitbucket - engine : xpath - paging : True - search_url : https://bitbucket.org/repo/all/{pageno}?name={query} - url_xpath : //article[@class="repo-summary"]//a[@class="repo-link"]/@href - title_xpath : //article[@class="repo-summary"]//a[@class="repo-link"] - content_xpath : //article[@class="repo-summary"]/p - categories : it - timeout : 4.0 - disabled : True - shortcut : bb - - - name : btdigg - engine : btdigg - shortcut : bt - - - name : currency - engine : currency_convert - categories : general - shortcut : cc - - - name : deezer - engine : deezer - shortcut : dz - - - name : deviantart - engine : deviantart - shortcut : da - timeout: 3.0 - - - name : ddg definitions - engine : duckduckgo_definitions - shortcut : ddd - disabled : True - - - name : digg - engine : digg - shortcut : dg - - - name : erowid - engine : xpath - paging : True - first_page_num : 0 - page_size : 30 - search_url : https://www.erowid.org/search.php?q={query}&s={pageno} - url_xpath : //dl[@class="results-list"]/dt[@class="result-title"]/a/@href - title_xpath : //dl[@class="results-list"]/dt[@class="result-title"]/a/text() - content_xpath : //dl[@class="results-list"]/dd[@class="result-details"] - categories : general - shortcut : ew - disabled : True - - - name : wikidata - engine : wikidata - shortcut : wd - - - name : duckduckgo - engine : duckduckgo - shortcut : ddg - -# api-key required: http://www.faroo.com/hp/api/api.html#key -# - name : faroo -# engine : faroo -# shortcut : fa -# api_key : 'apikey' # required! - - - name : 500px - engine : www500px - shortcut : px - - - name : 1x - engine : www1x - shortcut : 1x - disabled : True - - - name : fdroid - engine : fdroid - shortcut : fd - disabled : True - - - name : flickr - categories : images - shortcut : fl -# You can use the engine using the official stable API, but you need an API key -# See : https://www.flickr.com/services/apps/create/ -# engine : flickr -# api_key: 'apikey' # required! -# Or you can use the html non-stable engine, activated by default - engine : flickr_noapi - - - name : frinkiac - engine : frinkiac - shortcut : frk - disabled : True - - - name : gigablast - engine : gigablast - shortcut : gb - disabled: True - - - name : gitlab - engine : xpath - paging : True - search_url : https://gitlab.com/search?page={pageno}&search={query} - url_xpath : //li[@class="project-row"]//a[@class="project"]/@href - title_xpath : //li[@class="project-row"]//span[contains(@class, "project-full-name")] - content_xpath : //li[@class="project-row"]//div[@class="description"]/p - categories : it - shortcut : gl - timeout : 5.0 - disabled : True - - - name : github - engine : github - shortcut : gh - - - name : google - engine : google - shortcut : go - - - name : google images - engine : google_images - shortcut : goi - - - name : google news - engine : google_news - shortcut : gon - - - name : google play apps - engine : xpath - search_url : https://play.google.com/store/search?q={query}&c=apps - url_xpath : //a[@class="title"]/@href - title_xpath : //a[@class="title"] - content_xpath : //a[@class="subtitle"] - categories : files - shortcut : gpa - disabled : True - - - name : google play movies - engine : xpath - search_url : https://play.google.com/store/search?q={query}&c=movies - url_xpath : //a[@class="title"]/@href - title_xpath : //a[@class="title"] - content_xpath : //a[@class="subtitle"] - categories : videos - shortcut : gpm - disabled : True - - - name : google play music - engine : xpath - search_url : https://play.google.com/store/search?q={query}&c=music - url_xpath : //a[@class="title"]/@href - title_xpath : //a[@class="title"] - content_xpath : //a[@class="subtitle"] - categories : music - shortcut : gps - disabled : True - - - name : geektimes - engine : xpath - paging : True - search_url : https://geektimes.ru/search/page{pageno}/?q={query} - url_xpath : //div[@class="search_results"]//a[@class="post__title_link"]/@href - title_xpath : //div[@class="search_results"]//a[@class="post__title_link"] - content_xpath : //div[@class="search_results"]//div[contains(@class, "content")] - categories : it - timeout : 4.0 - disabled : True - shortcut : gt - - - name : habrahabr - engine : xpath - paging : True - search_url : https://habrahabr.ru/search/page{pageno}/?q={query} - url_xpath : //div[@class="search_results"]//a[@class="post_title"]/@href - title_xpath : //div[@class="search_results"]//a[@class="post_title"] - content_xpath : //div[@class="search_results"]//div[contains(@class, "content")] - categories : it - timeout : 4.0 - disabled : True - shortcut : habr - - - name : mixcloud - engine : mixcloud - shortcut : mc - - - name : nyaa - engine : nyaa - shortcut : nt - disabled : True - - - name : openstreetmap - engine : openstreetmap - shortcut : osm - - - name : photon - engine : photon - shortcut : ph - - - name : piratebay - engine : piratebay - shortcut : tpb - disabled : True - - - name : qwant - engine : qwant - shortcut : qw - categories : general - disabled : True - - - name : qwant images - engine : qwant - shortcut : qwi - categories : images - - - name : qwant news - engine : qwant - shortcut : qwn - categories : news - - - name : qwant social - engine : qwant - shortcut : qws - categories : social media - - - name : reddit - engine : reddit - shortcut : re - page_size : 25 - timeout : 10.0 - disabled : True - - - name : kickass - engine : kickass - shortcut : ka - - - name : soundcloud - engine : soundcloud - shortcut : sc - - - name : stackoverflow - engine : stackoverflow - shortcut : st - - - name : searchcode doc - engine : searchcode_doc - shortcut : scd - - - name : searchcode code - engine : searchcode_code - shortcut : scc - disabled : True - - - name : spotify - engine : spotify - shortcut : stf - - - name : subtitleseeker - engine : subtitleseeker - shortcut : ss -# The language is an option. You can put any language written in english -# Examples : English, French, German, Hungarian, Chinese... -# language : English - - - name : startpage - engine : startpage - shortcut : sp - timeout : 6.0 - disabled : True - - - name : ixquick - engine : startpage - base_url : 'https://www.ixquick.com/' - search_url : 'https://www.ixquick.com/do/search' - shortcut : iq - timeout : 6.0 - disabled : True - - - name : swisscows - engine : swisscows - shortcut : sw - disabled : True - - - name : tokyotoshokan - engine : tokyotoshokan - shortcut : tt - timeout : 6.0 - disabled : True - - - name : torrentz - engine : torrentz - timeout : 5.0 - shortcut : to - - - name : twitter - engine : twitter - shortcut : tw - -# maybe in a fun category -# - name : uncyclopedia -# engine : mediawiki -# shortcut : unc -# base_url : https://uncyclopedia.wikia.com/ -# number_of_results : 5 - -# tmp suspended - too slow, too many errors -# - name : urbandictionary -# engine : xpath -# search_url : http://www.urbandictionary.com/define.php?term={query} -# url_xpath : //div[@class="word"]//a/@href -# title_xpath : //div[@class="word"]//a -# content_xpath : //div[@class="definition"] -# shortcut : ud - - - name : yahoo - engine : yahoo - shortcut : yh - - - name : yandex - engine : yandex - shortcut : yn - disabled : True - - - name : yahoo news - engine : yahoo_news - shortcut : yhn - - - name : youtube - shortcut : yt - # You can use the engine using the official stable API, but you need an API key - # See : https://console.developers.google.com/project - # engine : youtube_api - # api_key: 'apikey' # required! - # Or you can use the html non-stable engine, activated by default - engine : youtube_noapi - - - name : dailymotion - engine : dailymotion - shortcut : dm - - - name : vimeo - engine : vimeo - shortcut : vm - - - name : wolframalpha - shortcut : wa - # You can use the engine using the official stable API, but you need an API key - # See : http://products.wolframalpha.com/api/ - # engine : wolframalpha_api - # api_key: '' # required! - engine : wolframalpha_noapi - timeout: 6.0 - categories : science - -#The blekko technology and team have joined IBM Watson! -> https://blekko.com/ -# - name : blekko images -# engine : blekko_images -# locale : en-US -# shortcut : bli - -# - name : yacy -# engine : yacy -# shortcut : ya -# base_url : 'http://localhost:8090' -# number_of_results : 5 -# timeout : 3.0 - -# Doku engine lets you access to any Doku wiki instance: -# A public one or a privete/corporate one. -# - name : ubuntuwiki -# engine : doku -# shortcut : uw -# base_url : 'http://doc.ubuntu-fr.org' - -locales: - en : English - bg : Български (Bulgarian) - de : Deutsch (German) - el_GR : Ελληνικά (Greek_Greece) - eo : Esperanto (Esperanto) - es : Español (Spanish) - fr : Français (French) - he : עברית (Hebrew) - hu : Magyar (Hungarian) - it : Italiano (Italian) - ja : 日本語 (Japanese) - nl : Nederlands (Dutch) - pt : Português (Portuguese) - pt_BR : Português (Portuguese_Brazil) - ro : Română (Romanian) - ru : Русский (Russian) - tr : Türkçe (Turkish) - zh : 中文 (Chinese) diff --git a/sources/searx/settings_robot.yml b/sources/searx/settings_robot.yml deleted file mode 100644 index 7c7c4ee..0000000 --- a/sources/searx/settings_robot.yml +++ /dev/null @@ -1,38 +0,0 @@ -general: - debug : False - instance_name : "searx_test" - -search: - safe_search : 0 - autocomplete : "" - -server: - port : 11111 - bind_address : 127.0.0.1 - secret_key : "ultrasecretkey" # change this! - base_url : False - image_proxy : False - -ui: - themes_path : "" - default_theme : default - default_locale : "" - -outgoing: - request_timeout : 1.0 # seconds - useragent_suffix : "" - -engines: - - name : general_dummy - engine : dummy - categories : general - shortcut : gd - - - name : dummy_dummy - engine : dummy - categories : dummy - shortcut : dd - -locales: - en : English - hu : Magyar diff --git a/sources/searx/static/css/bootstrap.min.css b/sources/searx/static/css/bootstrap.min.css deleted file mode 100644 index 691604b..0000000 --- a/sources/searx/static/css/bootstrap.min.css +++ /dev/null @@ -1 +0,0 @@ -/*! normalize.css v3.0.1 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*{text-shadow:none !important;color:#000 !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}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff !important}.navbar{display:none}.table td,.table th{background-color:#fff !important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}@font-face{font-family:'Glyphicons Halflings';src:url('../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';font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;width:100% \9;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;width:100% \9;max-width:100%;height:auto}.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;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}mark,.mark{background-color:#fcf8e3;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#428bca}a.text-primary:hover{color:#3071a9}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:bold}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25)}kbd kbd{padding:0;font-size:100%;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;word-break:break-all;word-wrap:break-word;color:#333;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{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{position:static;float:none;display:table-column}table td[class*="col-"],table th[class*="col-"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;overflow-x:auto;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd;-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;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight: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}input[type="range"]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,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;-o-transition:border-color ease-in-out .15s, box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s, box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6)}.form-control::-moz-placeholder{color:#777;opacity:1}.form-control:-ms-input-placeholder{color:#777}.form-control::-webkit-input-placeholder{color:#777}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type="search"]{-webkit-appearance:none}input[type="date"],input[type="time"],input[type="datetime-local"],input[type="month"]{line-height:34px;line-height:1.42857143 \0}input[type="date"].input-sm,input[type="time"].input-sm,input[type="datetime-local"].input-sm,input[type="month"].input-sm{line-height:30px}input[type="date"].input-lg,input[type="time"].input-lg,input[type="datetime-local"].input-lg,input[type="month"].input-lg{line-height:46px}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;min-height:20px;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{padding-left:20px;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{position:absolute;margin-left:-20px;margin-top:4px \9}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:normal;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"].disabled,input[type="checkbox"].disabled,fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.input-sm,.form-horizontal .form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.input-lg,.form-horizontal .form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg,select[multiple].input-lg{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:25px;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,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;border-color:#3c763d;background-color:#dff0d8}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,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;border-color:#8a6d3b;background-color:#fcf8e3}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,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;border-color:#a94442;background-color:#f2dede}.has-error .form-control-feedback{color:#a94442}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}@media (min-width:768px){.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:7px}}.form-horizontal .has-feedback .form-control-feedback{top:0;right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.3px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn:focus,.btn:active:focus,.btn.active:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-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{cursor:not-allowed;pointer-events:none;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:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#3071a9;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#428bca;font-weight:normal;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;text-align:left;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.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#262626;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#428bca}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#777}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top: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{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right: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{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-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-bottom-right-radius:0;border-top-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>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right: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>.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-bottom-left-radius:4px;border-top-right-radius:0;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:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{position:absolute;z-index:-1;opacity:0;filter:alpha(opacity=0)}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*="col-"]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight: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>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#777;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.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{text-align:center;margin-bottom:5px}.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}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.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-left:0;padding-right:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px;height:50px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;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{margin-left:-15px;margin-right:-15px;padding:10px 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);margin-top:8px;margin-bottom:8px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom: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-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-left:15px;margin-right:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#e7e7e7;color:#555}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#333}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#777}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#777}.navbar-inverse .navbar-nav>li>a{color:#777}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#080808;color:#fff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#777}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#777}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#fff}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#ccc}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;line-height:1.42857143;text-decoration:none;color:#428bca;background-color:#fff;border:1px solid #ddd;margin-left:-1px}.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-bottom-right-radius:4px;border-top-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca;cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#777;background-color:#fff;border-color:#ddd;cursor:not-allowed}.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-bottom-right-radius:6px;border-top-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-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:20px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#777;background-color:#fff;cursor:not-allowed}.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}a.label:hover,a.label:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:hover,.label-default[href]:focus{background-color:#5e5e5e}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;color:#fff;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-left:auto;margin-right: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,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.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{overflow:hidden;height:20px;margin-bottom:20px;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;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,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:-o-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,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar[aria-valuenow="1"],.progress-bar[aria-valuenow="2"]{min-width:30px}.progress-bar[aria-valuenow="0"]{color:#777;min-width:30px;background-color:transparent;background-image:none;box-shadow:none}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,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:-o-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:-o-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:-o-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:-o-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{margin-bottom:20px;padding-left:0}.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;color:#555;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{background-color:#eee;color:#777}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.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>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#428bca}.panel-primary>.panel-heading .badge{color:#428bca;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object{position:absolute;top:0;left:0;bottom:0;height:100%;width:100%;border:0}.embed-responsive.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,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{display:none;overflow:hidden;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate3d(0, -25%, 0);transform:translate3d(0, -25%, 0);-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:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-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;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.42857143px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;visibility:visible;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;right:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;background-clip:padding-box;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);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;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{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,0.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,0.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:.5;filter:alpha(opacity=50);font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-control.left{background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.5) 0, 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{left:auto;right:0;background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.0001) 0, 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{outline:0;color:#fff;text-decoration:none;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%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;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 .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important;visibility:hidden !important}.affix{position:fixed;-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none !important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none !important}@media (max-width:767px){.visible-xs{display:block !important}table.visible-xs{display:table}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}@media (max-width:767px){.visible-xs-block{display:block !important}}@media (max-width:767px){.visible-xs-inline{display:inline !important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block !important}table.visible-sm{display:table}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block !important}table.visible-md{display:table}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block !important}}@media (min-width:1200px){.visible-lg{display:block !important}table.visible-lg{display:table}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media (min-width:1200px){.visible-lg-block{display:block !important}}@media (min-width:1200px){.visible-lg-inline{display:inline !important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block !important}}@media (max-width:767px){.hidden-xs{display:none !important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none !important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none !important}}@media (min-width:1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}.visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}.visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}@media print{.hidden-print{display:none !important}}.has-warning .twitter-typeahead .tt-input,.has-warning .twitter-typeahead .tt-hint{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 .twitter-typeahead .tt-input:focus,.has-warning .twitter-typeahead .tt-hint: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-error .twitter-typeahead .tt-input,.has-error .twitter-typeahead .tt-hint{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 .twitter-typeahead .tt-input:focus,.has-error .twitter-typeahead .tt-hint: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-success .twitter-typeahead .tt-input,.has-success .twitter-typeahead .tt-hint{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 .twitter-typeahead .tt-input:focus,.has-success .twitter-typeahead .tt-hint: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}.input-group .twitter-typeahead:first-child .tt-input,.input-group .twitter-typeahead:first-child .tt-hint{border-bottom-left-radius:4px;border-top-left-radius:4px}.input-group .twitter-typeahead:last-child .tt-input,.input-group .twitter-typeahead:last-child .tt-hint{border-bottom-right-radius:4px;border-top-right-radius:4px}.input-group.input-group-sm .twitter-typeahead .tt-input,.input-group.input-group-sm .twitter-typeahead .tt-hint{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group.input-group-sm .twitter-typeahead .tt-input,select.input-group.input-group-sm .twitter-typeahead .tt-hint{height:30px;line-height:30px}textarea.input-group.input-group-sm .twitter-typeahead .tt-input,textarea.input-group.input-group-sm .twitter-typeahead .tt-hint,select[multiple].input-group.input-group-sm .twitter-typeahead .tt-input,select[multiple].input-group.input-group-sm .twitter-typeahead .tt-hint{height:auto}.input-group.input-group-sm .twitter-typeahead:not(:first-child):not(:last-child) .tt-input,.input-group.input-group-sm .twitter-typeahead:not(:first-child):not(:last-child) .tt-hint{border-radius:0}.input-group.input-group-sm .twitter-typeahead:first-child .tt-input,.input-group.input-group-sm .twitter-typeahead:first-child .tt-hint{border-bottom-left-radius:3px;border-top-left-radius:3px;border-bottom-right-radius:0;border-top-right-radius:0}.input-group.input-group-sm .twitter-typeahead:last-child .tt-input,.input-group.input-group-sm .twitter-typeahead:last-child .tt-hint{border-bottom-left-radius:0;border-top-left-radius:0;border-bottom-right-radius:3px;border-top-right-radius:3px}.input-group.input-group-lg .twitter-typeahead .tt-input,.input-group.input-group-lg .twitter-typeahead .tt-hint{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group.input-group-lg .twitter-typeahead .tt-input,select.input-group.input-group-lg .twitter-typeahead .tt-hint{height:46px;line-height:46px}textarea.input-group.input-group-lg .twitter-typeahead .tt-input,textarea.input-group.input-group-lg .twitter-typeahead .tt-hint,select[multiple].input-group.input-group-lg .twitter-typeahead .tt-input,select[multiple].input-group.input-group-lg .twitter-typeahead .tt-hint{height:auto}.input-group.input-group-lg .twitter-typeahead:not(:first-child):not(:last-child) .tt-input,.input-group.input-group-lg .twitter-typeahead:not(:first-child):not(:last-child) .tt-hint{border-radius:0}.input-group.input-group-lg .twitter-typeahead:first-child .tt-input,.input-group.input-group-lg .twitter-typeahead:first-child .tt-hint{border-bottom-left-radius:6px;border-top-left-radius:6px;border-bottom-right-radius:0;border-top-right-radius:0}.input-group.input-group-lg .twitter-typeahead:last-child .tt-input,.input-group.input-group-lg .twitter-typeahead:last-child .tt-hint{border-bottom-left-radius:0;border-top-left-radius:0;border-bottom-right-radius:6px;border-top-right-radius:6px}.twitter-typeahead{width:100%}.input-group .twitter-typeahead{display:table-cell !important;float:left}.twitter-typeahead .tt-hint{color:#777}.twitter-typeahead .tt-input{z-index:2}.twitter-typeahead .tt-input[disabled],.twitter-typeahead .tt-input[readonly],fieldset[disabled] .twitter-typeahead .tt-input{cursor:not-allowed;background-color:#eee !important}.tt-dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;min-width:160px;width:100%;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;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;*border-right-width:2px;*border-bottom-width:2px}.tt-dropdown-menu .tt-suggestion{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.42857143;color:#333;white-space:nowrap;text-align:left;cursor:pointer !important}.tt-dropdown-menu .tt-suggestion.tt-cursor{text-decoration:none;outline:0;background-color:#f5f5f5;color:#262626}.tt-dropdown-menu .tt-suggestion.tt-cursor a{color:#262626}.tt-dropdown-menu .tt-suggestion p{margin:0} \ No newline at end of file diff --git a/sources/searx/static/fonts/glyphicons-halflings-regular.eot b/sources/searx/static/fonts/glyphicons-halflings-regular.eot deleted file mode 100644 index 4a4ca86..0000000 Binary files a/sources/searx/static/fonts/glyphicons-halflings-regular.eot and /dev/null differ diff --git a/sources/searx/static/fonts/glyphicons-halflings-regular.svg b/sources/searx/static/fonts/glyphicons-halflings-regular.svg deleted file mode 100644 index e3e2dc7..0000000 --- a/sources/searx/static/fonts/glyphicons-halflings-regular.svg +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sources/searx/static/fonts/glyphicons-halflings-regular.ttf b/sources/searx/static/fonts/glyphicons-halflings-regular.ttf deleted file mode 100644 index 67fa00b..0000000 Binary files a/sources/searx/static/fonts/glyphicons-halflings-regular.ttf and /dev/null differ diff --git a/sources/searx/static/fonts/glyphicons-halflings-regular.woff b/sources/searx/static/fonts/glyphicons-halflings-regular.woff deleted file mode 100644 index 8c54182..0000000 Binary files a/sources/searx/static/fonts/glyphicons-halflings-regular.woff and /dev/null differ diff --git a/sources/searx/static/js/bootstrap.min.js b/sources/searx/static/js/bootstrap.min.js deleted file mode 100644 index 7c1561a..0000000 --- a/sources/searx/static/js/bootstrap.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! - * Bootstrap v3.2.0 (http://getbootstrap.com) - * Copyright 2011-2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ -if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.2.0",d.prototype.close=function(b){function c(){f.detach().trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",c).emulateTransitionEnd(150):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.2.0",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),d[e](null==f[b]?this.options[b]:f[b]),setTimeout(a.proxy(function(){"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b).on("keydown.bs.carousel",a.proxy(this.keydown,this)),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.2.0",c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},c.prototype.keydown=function(a){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.to=function(b){var c=this,d=this.getItemIndex(this.$active=this.$element.find(".item.active"));return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}if(e.hasClass("active"))return this.sliding=!1;var j=e[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:g});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,f&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(e)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:g});return a.support.transition&&this.$element.hasClass("slide")?(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one("bsTransitionEnd",function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(1e3*d.css("transition-duration").slice(0,-1))):(d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger(m)),f&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(b=!b),e||d.data("bs.collapse",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};c.VERSION="3.2.0",c.DEFAULTS={toggle:!0},c.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},c.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var c=a.Event("show.bs.collapse");if(this.$element.trigger(c),!c.isDefaultPrevented()){var d=this.$parent&&this.$parent.find("> .panel > .in");if(d&&d.length){var e=d.data("bs.collapse");if(e&&e.transitioning)return;b.call(d,"hide"),e||d.data("bs.collapse",null)}var f=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[f](0),this.transitioning=1;var g=function(){this.$element.removeClass("collapsing").addClass("collapse in")[f](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return g.call(this);var h=a.camelCase(["scroll",f].join("-"));this.$element.one("bsTransitionEnd",a.proxy(g,this)).emulateTransitionEnd(350)[f](this.$element[0][h])}}},c.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(d,this)).emulateTransitionEnd(350):d.call(this)}}},c.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var d=a.fn.collapse;a.fn.collapse=b,a.fn.collapse.Constructor=c,a.fn.collapse.noConflict=function(){return a.fn.collapse=d,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(c){var d,e=a(this),f=e.attr("data-target")||c.preventDefault()||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),g=a(f),h=g.data("bs.collapse"),i=h?"toggle":e.data(),j=e.attr("data-parent"),k=j&&a(j);h&&h.transitioning||(k&&k.find('[data-toggle="collapse"][data-parent="'+j+'"]').not(e).addClass("collapsed"),e[g.hasClass("in")?"addClass":"removeClass"]("collapsed")),b.call(g,i)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=c(a(this)),e={relatedTarget:this};d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown",e)),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown",e))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.2.0",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('