From d07267b8a85fde59ef0bfc42a7ca36613981f08c Mon Sep 17 00:00:00 2001 From: ozzmos Date: Fri, 9 Dec 2016 16:28:29 +0100 Subject: [PATCH] upgrade searx to version v0.10 (#4) * remove upstream source files * upgrade searx to version v0.10 --- scripts/install | 2 + scripts/upgrade | 4 +- sources/.coveragerc | 20 - sources/.gitignore | 17 - sources/.landscape.yaml | 3 - sources/.travis.yml | 32 - sources/AUTHORS.rst | 53 - sources/CHANGELOG.rst | 164 - sources/Dockerfile | 54 - sources/LICENSE | 661 -- sources/README.rst | 45 - sources/babel.cfg | 3 - sources/examples/basic_engine.py | 25 - sources/manage.sh | 95 - sources/requirements-dev.txt | 10 - sources/requirements.txt | 12 - sources/searx/__init__.py | 59 - sources/searx/autocomplete.py | 197 - sources/searx/data/currencies.json | 7655 ----------------- sources/searx/engines/__init__.py | 202 - sources/searx/engines/archlinux.py | 141 - sources/searx/engines/base.py | 122 - sources/searx/engines/bing.py | 88 - sources/searx/engines/bing_images.py | 98 - sources/searx/engines/bing_news.py | 111 - sources/searx/engines/blekko_images.py | 70 - sources/searx/engines/btdigg.py | 106 - sources/searx/engines/currency_convert.py | 101 - sources/searx/engines/dailymotion.py | 77 - sources/searx/engines/deezer.py | 67 - sources/searx/engines/deviantart.py | 75 - sources/searx/engines/digg.py | 75 - sources/searx/engines/doku.py | 84 - sources/searx/engines/duckduckgo.py | 78 - .../searx/engines/duckduckgo_definitions.py | 156 - sources/searx/engines/dummy.py | 16 - sources/searx/engines/faroo.py | 116 - sources/searx/engines/fdroid.py | 53 - sources/searx/engines/filecrop.py | 84 - sources/searx/engines/flickr.py | 98 - sources/searx/engines/flickr_noapi.py | 106 - sources/searx/engines/frinkiac.py | 44 - sources/searx/engines/generalfile.py | 62 - sources/searx/engines/gigablast.py | 85 - sources/searx/engines/github.py | 61 - sources/searx/engines/google.py | 349 - sources/searx/engines/google_images.py | 69 - sources/searx/engines/google_news.py | 67 - sources/searx/engines/json_engine.py | 87 - sources/searx/engines/kickass.py | 118 - sources/searx/engines/mediawiki.py | 88 - sources/searx/engines/mixcloud.py | 61 - sources/searx/engines/nyaa.py | 119 - sources/searx/engines/openstreetmap.py | 99 - sources/searx/engines/photon.py | 131 - sources/searx/engines/piratebay.py | 98 - sources/searx/engines/qwant.py | 98 - sources/searx/engines/reddit.py | 79 - sources/searx/engines/searchcode_code.py | 75 - sources/searx/engines/searchcode_doc.py | 63 - sources/searx/engines/soundcloud.py | 98 - sources/searx/engines/spotify.py | 62 - sources/searx/engines/stackoverflow.py | 60 - sources/searx/engines/startpage.py | 124 - sources/searx/engines/subtitleseeker.py | 81 - sources/searx/engines/swisscows.py | 109 - sources/searx/engines/tokyotoshokan.py | 102 - sources/searx/engines/torrentz.py | 93 - sources/searx/engines/twitter.py | 83 - sources/searx/engines/vimeo.py | 75 - sources/searx/engines/wikidata.py | 323 - sources/searx/engines/wikipedia.py | 114 - sources/searx/engines/wolframalpha_api.py | 122 - sources/searx/engines/wolframalpha_noapi.py | 116 - sources/searx/engines/www1x.py | 83 - sources/searx/engines/www500px.py | 66 - sources/searx/engines/xpath.py | 120 - sources/searx/engines/yacy.py | 97 - sources/searx/engines/yahoo.py | 113 - sources/searx/engines/yahoo_news.py | 104 - sources/searx/engines/yandex.py | 63 - sources/searx/engines/youtube_api.py | 83 - sources/searx/engines/youtube_noapi.py | 81 - sources/searx/languages.py | 78 - sources/searx/plugins/__init__.py | 81 - sources/searx/plugins/https_rewrite.py | 230 - sources/searx/plugins/https_rules/00README | 17 - sources/searx/plugins/https_rules/Bing.xml | 56 - .../searx/plugins/https_rules/Dailymotion.xml | 69 - .../searx/plugins/https_rules/Deviantart.xml | 53 - .../searx/plugins/https_rules/DuckDuckGo.xml | 38 - sources/searx/plugins/https_rules/Flickr.xml | 44 - .../plugins/https_rules/Github-Pages.xml | 11 - sources/searx/plugins/https_rules/Github.xml | 94 - .../plugins/https_rules/Google-mismatches.xml | 26 - .../searx/plugins/https_rules/Google.org.xml | 14 - .../searx/plugins/https_rules/GoogleAPIs.xml | 143 - .../plugins/https_rules/GoogleCanada.xml | 6 - .../plugins/https_rules/GoogleImages.xml | 65 - .../plugins/https_rules/GoogleMainSearch.xml | 78 - .../searx/plugins/https_rules/GoogleMaps.xml | 67 - .../plugins/https_rules/GoogleMelange.xml | 6 - .../plugins/https_rules/GoogleSearch.xml | 135 - .../plugins/https_rules/GoogleServices.xml | 345 - .../plugins/https_rules/GoogleShopping.xml | 28 - .../searx/plugins/https_rules/GoogleSorry.xml | 7 - .../plugins/https_rules/GoogleTranslate.xml | 8 - .../plugins/https_rules/GoogleVideos.xml | 83 - .../plugins/https_rules/GoogleWatchBlog.xml | 17 - .../plugins/https_rules/Google_App_Engine.xml | 21 - .../plugins/https_rules/Googleplex.com.xml | 16 - .../plugins/https_rules/OpenStreetMap.xml | 15 - .../plugins/https_rules/Rawgithub.com.xml | 14 - .../searx/plugins/https_rules/Soundcloud.xml | 101 - .../plugins/https_rules/ThePirateBay.xml | 36 - .../searx/plugins/https_rules/Torproject.xml | 18 - sources/searx/plugins/https_rules/Twitter.xml | 169 - sources/searx/plugins/https_rules/Vimeo.xml | 75 - .../searx/plugins/https_rules/WikiLeaks.xml | 13 - .../searx/plugins/https_rules/Wikimedia.xml | 107 - sources/searx/plugins/https_rules/Yahoo.xml | 2450 ------ sources/searx/plugins/https_rules/YouTube.xml | 46 - .../searx/plugins/open_results_on_new_tab.py | 24 - .../plugins/search_on_category_select.py | 23 - sources/searx/plugins/self_info.py | 44 - sources/searx/plugins/tracker_url_remover.py | 44 - sources/searx/plugins/vim_hotkeys.py | 10 - sources/searx/poolrequests.py | 112 - sources/searx/preferences.py | 276 - sources/searx/query.py | 132 - sources/searx/results.py | 254 - sources/searx/search.py | 344 - sources/searx/settings.yml | 467 - sources/searx/settings_robot.yml | 38 - sources/searx/static/css/bootstrap.min.css | 1 - .../fonts/glyphicons-halflings-regular.eot | Bin 20335 -> 0 bytes .../fonts/glyphicons-halflings-regular.svg | 229 - .../fonts/glyphicons-halflings-regular.ttf | Bin 41280 -> 0 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 23320 -> 0 bytes sources/searx/static/js/bootstrap.min.js | 6 - sources/searx/static/js/html5shiv.min.js | 4 - sources/searx/static/js/jquery-1.11.1.min.js | 4 - .../js/mootools-autocompleter-1.1.2-min.js | 2 - .../static/js/mootools-core-1.4.5-min.js | 491 -- sources/searx/static/js/require-2.1.15.min.js | 36 - sources/searx/static/js/respond.min.js | 5 - .../searx/static/js/typeahead.bundle.min.js | 7 - .../searx/static/less/bootstrap/.csscomb.json | 297 - .../searx/static/less/bootstrap/.csslintrc | 19 - .../searx/static/less/bootstrap/alerts.less | 68 - .../searx/static/less/bootstrap/badges.less | 55 - .../static/less/bootstrap/bootstrap.less | 53 - .../static/less/bootstrap/breadcrumbs.less | 26 - .../static/less/bootstrap/button-groups.less | 240 - .../searx/static/less/bootstrap/buttons.less | 157 - .../searx/static/less/bootstrap/carousel.less | 243 - .../searx/static/less/bootstrap/close.less | 33 - sources/searx/static/less/bootstrap/code.less | 68 - .../less/bootstrap/component-animations.less | 31 - .../static/less/bootstrap/dropdowns.less | 215 - .../searx/static/less/bootstrap/forms.less | 540 -- .../static/less/bootstrap/glyphicons.less | 233 - sources/searx/static/less/bootstrap/grid.less | 84 - .../static/less/bootstrap/input-groups.less | 166 - .../static/less/bootstrap/jumbotron.less | 48 - .../searx/static/less/bootstrap/labels.less | 64 - .../static/less/bootstrap/list-group.less | 131 - .../searx/static/less/bootstrap/media.less | 56 - .../searx/static/less/bootstrap/mixins.less | 39 - .../static/less/bootstrap/mixins/alerts.less | 14 - .../bootstrap/mixins/background-variant.less | 8 - .../less/bootstrap/mixins/border-radius.less | 18 - .../static/less/bootstrap/mixins/buttons.less | 50 - .../less/bootstrap/mixins/center-block.less | 7 - .../less/bootstrap/mixins/clearfix.less | 22 - .../static/less/bootstrap/mixins/forms.less | 81 - .../less/bootstrap/mixins/gradients.less | 59 - .../less/bootstrap/mixins/grid-framework.less | 91 - .../static/less/bootstrap/mixins/grid.less | 122 - .../less/bootstrap/mixins/hide-text.less | 21 - .../static/less/bootstrap/mixins/image.less | 34 - .../static/less/bootstrap/mixins/labels.less | 12 - .../less/bootstrap/mixins/list-group.less | 29 - .../less/bootstrap/mixins/nav-divider.less | 10 - .../bootstrap/mixins/nav-vertical-align.less | 9 - .../static/less/bootstrap/mixins/opacity.less | 8 - .../less/bootstrap/mixins/pagination.less | 23 - .../static/less/bootstrap/mixins/panels.less | 24 - .../less/bootstrap/mixins/progress-bar.less | 10 - .../less/bootstrap/mixins/reset-filter.less | 8 - .../static/less/bootstrap/mixins/resize.less | 6 - .../mixins/responsive-visibility.less | 15 - .../static/less/bootstrap/mixins/size.less | 10 - .../less/bootstrap/mixins/tab-focus.less | 9 - .../less/bootstrap/mixins/table-row.less | 28 - .../less/bootstrap/mixins/text-emphasis.less | 8 - .../less/bootstrap/mixins/text-overflow.less | 8 - .../bootstrap/mixins/vendor-prefixes.less | 224 - .../searx/static/less/bootstrap/modals.less | 150 - .../searx/static/less/bootstrap/navbar.less | 655 -- sources/searx/static/less/bootstrap/navs.less | 242 - .../static/less/bootstrap/normalize.less | 425 - .../searx/static/less/bootstrap/pager.less | 55 - .../static/less/bootstrap/pagination.less | 88 - .../searx/static/less/bootstrap/panels.less | 243 - .../searx/static/less/bootstrap/popovers.less | 133 - .../searx/static/less/bootstrap/print.less | 101 - .../static/less/bootstrap/progress-bars.less | 105 - .../less/bootstrap/responsive-embed.less | 34 - .../less/bootstrap/responsive-utilities.less | 194 - .../static/less/bootstrap/scaffolding.less | 150 - .../searx/static/less/bootstrap/tables.less | 233 - .../searx/static/less/bootstrap/theme.less | 258 - .../static/less/bootstrap/thumbnails.less | 36 - .../searx/static/less/bootstrap/tooltip.less | 95 - sources/searx/static/less/bootstrap/type.less | 313 - .../static/less/bootstrap/typeahead.less | 153 - .../static/less/bootstrap/utilities.less | 57 - .../static/less/bootstrap/variables.less | 846 -- .../searx/static/less/bootstrap/wells.less | 29 - .../searx/static/plugins/css/vim_hotkeys.css | 26 - .../plugins/js/open_results_on_new_tab.js | 3 - .../plugins/js/search_on_category_select.js | 16 - .../searx/static/plugins/js/vim_hotkeys.js | 336 - .../static/themes/courgette/css/style-rtl.css | 1 - .../static/themes/courgette/css/style.css | 1 - .../themes/courgette/img/bg-body-index.jpg | Bin 350109 -> 0 bytes .../static/themes/courgette/img/favicon.png | Bin 2060 -> 0 bytes .../themes/courgette/img/github_ribbon.png | Bin 5213 -> 0 bytes .../themes/courgette/img/icons/icon_500px.ico | Bin 8348 -> 0 bytes .../themes/courgette/img/icons/icon_bing.ico | Bin 1150 -> 0 bytes .../courgette/img/icons/icon_dailymotion.ico | Bin 4286 -> 0 bytes .../courgette/img/icons/icon_deezer.ico | Bin 4286 -> 0 bytes .../courgette/img/icons/icon_deviantart.ico | Bin 4286 -> 0 bytes .../themes/courgette/img/icons/icon_digg.ico | Bin 2868 -> 0 bytes .../courgette/img/icons/icon_duckduckgo.ico | Bin 32988 -> 0 bytes .../courgette/img/icons/icon_flickr.ico | Bin 6518 -> 0 bytes .../courgette/img/icons/icon_github.ico | Bin 6518 -> 0 bytes .../img/icons/icon_google play apps.ico | Bin 5430 -> 0 bytes .../img/icons/icon_google play movies.ico | Bin 5430 -> 0 bytes .../img/icons/icon_google play music.ico | Bin 5430 -> 0 bytes .../courgette/img/icons/icon_google.ico | Bin 5430 -> 0 bytes .../courgette/img/icons/icon_kickass.ico | Bin 1150 -> 0 bytes .../img/icons/icon_openstreetmap.ico | Bin 1406 -> 0 bytes .../img/icons/icon_searchcode code.ico | Bin 4094 -> 0 bytes .../img/icons/icon_searchcode doc.ico | Bin 4094 -> 0 bytes .../courgette/img/icons/icon_searchcode.ico | Bin 4094 -> 0 bytes .../courgette/img/icons/icon_soundcloud.ico | Bin 1150 -> 0 bytes .../img/icons/icon_stackoverflow.ico | Bin 1150 -> 0 bytes .../courgette/img/icons/icon_startpage.ico | Bin 1150 -> 0 bytes .../img/icons/icon_subtitleseeker.ico | Bin 1406 -> 0 bytes .../courgette/img/icons/icon_twitter.ico | Bin 1150 -> 0 bytes .../themes/courgette/img/icons/icon_vimeo.ico | Bin 6518 -> 0 bytes .../courgette/img/icons/icon_wikipedia.ico | Bin 2734 -> 0 bytes .../themes/courgette/img/icons/icon_yahoo.ico | Bin 5430 -> 0 bytes .../courgette/img/icons/icon_youtube.ico | Bin 1150 -> 0 bytes .../themes/courgette/img/preference-icon.png | Bin 1315 -> 0 bytes .../themes/courgette/img/search-icon.png | Bin 3270 -> 0 bytes .../themes/courgette/img/searx-mobile.png | Bin 9568 -> 0 bytes .../static/themes/courgette/img/searx.png | Bin 3902 -> 0 bytes .../themes/courgette/img/searx_logo.svg | 203 - .../searx/static/themes/courgette/js/searx.js | 45 - .../themes/courgette/less/style-rtl.less | 42 - .../static/themes/courgette/less/style.less | 691 -- .../static/themes/default/css/style-rtl.css | 1 - .../searx/static/themes/default/css/style.css | 1 - .../static/themes/default/img/favicon.png | Bin 2060 -> 0 bytes .../themes/default/img/github_ribbon.png | Bin 5213 -> 0 bytes .../themes/default/img/icons/icon_500px.ico | Bin 8348 -> 0 bytes .../themes/default/img/icons/icon_bing.ico | Bin 1150 -> 0 bytes .../default/img/icons/icon_dailymotion.ico | Bin 4286 -> 0 bytes .../themes/default/img/icons/icon_deezer.ico | Bin 4286 -> 0 bytes .../default/img/icons/icon_deviantart.ico | Bin 4286 -> 0 bytes .../themes/default/img/icons/icon_digg.ico | Bin 2868 -> 0 bytes .../default/img/icons/icon_duckduckgo.ico | Bin 32988 -> 0 bytes .../themes/default/img/icons/icon_flickr.ico | Bin 6518 -> 0 bytes .../themes/default/img/icons/icon_github.ico | Bin 6518 -> 0 bytes .../img/icons/icon_google play apps.ico | Bin 5430 -> 0 bytes .../img/icons/icon_google play movies.ico | Bin 5430 -> 0 bytes .../img/icons/icon_google play music.ico | Bin 5430 -> 0 bytes .../themes/default/img/icons/icon_google.ico | Bin 5430 -> 0 bytes .../themes/default/img/icons/icon_kickass.ico | Bin 1150 -> 0 bytes .../default/img/icons/icon_openstreetmap.ico | Bin 1406 -> 0 bytes .../img/icons/icon_searchcode code.ico | Bin 4094 -> 0 bytes .../default/img/icons/icon_searchcode doc.ico | Bin 4094 -> 0 bytes .../default/img/icons/icon_searchcode.ico | Bin 4094 -> 0 bytes .../default/img/icons/icon_soundcloud.ico | Bin 1150 -> 0 bytes .../default/img/icons/icon_stackoverflow.ico | Bin 1150 -> 0 bytes .../default/img/icons/icon_startpage.ico | Bin 1150 -> 0 bytes .../default/img/icons/icon_subtitleseeker.ico | Bin 1406 -> 0 bytes .../themes/default/img/icons/icon_twitter.ico | Bin 1150 -> 0 bytes .../themes/default/img/icons/icon_vimeo.ico | Bin 6518 -> 0 bytes .../default/img/icons/icon_wikipedia.ico | Bin 2734 -> 0 bytes .../themes/default/img/icons/icon_yahoo.ico | Bin 5430 -> 0 bytes .../themes/default/img/icons/icon_youtube.ico | Bin 1150 -> 0 bytes .../themes/default/img/preference-icon.png | Bin 532 -> 0 bytes .../static/themes/default/img/search-icon.png | Bin 2329 -> 0 bytes .../searx/static/themes/default/img/searx.png | Bin 3902 -> 0 bytes .../static/themes/default/img/searx_logo.svg | 203 - .../searx/static/themes/default/js/searx.js | 49 - .../themes/default/less/autocompleter.less | 61 - .../static/themes/default/less/code.less | 83 - .../themes/default/less/definitions.less | 119 - .../static/themes/default/less/mixins.less | 27 - .../static/themes/default/less/search.less | 68 - .../static/themes/default/less/style-rtl.less | 11 - .../static/themes/default/less/style.less | 739 -- sources/searx/static/themes/oscar/.gitignore | 1 - sources/searx/static/themes/oscar/README.rst | 17 - .../static/themes/oscar/css/leaflet.min.css | 93 - .../static/themes/oscar/css/logicodev.min.css | 1 - .../static/themes/oscar/css/pointhi.min.css | 1 - .../searx/static/themes/oscar/gruntfile.js | 90 - .../searx/static/themes/oscar/img/favicon.png | Bin 2060 -> 0 bytes .../static/themes/oscar/img/icons/README.md | 2 - .../static/themes/oscar/img/icons/amazon.png | Bin 4133 -> 0 bytes .../themes/oscar/img/icons/dailymotion.png | Bin 3966 -> 0 bytes .../themes/oscar/img/icons/deviantart.png | Bin 3790 -> 0 bytes .../themes/oscar/img/icons/facebook.png | Bin 3685 -> 0 bytes .../static/themes/oscar/img/icons/flickr.png | Bin 3760 -> 0 bytes .../static/themes/oscar/img/icons/github.png | Bin 4336 -> 0 bytes .../static/themes/oscar/img/icons/kickass.png | Bin 4527 -> 0 bytes .../themes/oscar/img/icons/openstreetmap.png | Bin 5184 -> 0 bytes .../static/themes/oscar/img/icons/photon.png | Bin 4177 -> 0 bytes .../oscar/img/icons/searchcode code.png | Bin 4242 -> 0 bytes .../themes/oscar/img/icons/searchcode doc.png | Bin 4242 -> 0 bytes .../themes/oscar/img/icons/soundcloud.png | Bin 3826 -> 0 bytes .../themes/oscar/img/icons/stackoverflow.png | Bin 3990 -> 0 bytes .../static/themes/oscar/img/icons/twitter.png | Bin 3790 -> 0 bytes .../static/themes/oscar/img/icons/vimeo.png | Bin 3894 -> 0 bytes .../themes/oscar/img/icons/wikipedia.png | Bin 3960 -> 0 bytes .../static/themes/oscar/img/icons/youtube.png | Bin 4153 -> 0 bytes .../searx/static/themes/oscar/img/loader.gif | Bin 14190 -> 0 bytes .../static/themes/oscar/img/logo_searx_a.png | Bin 33423 -> 0 bytes .../themes/oscar/img/logo_searx_a_n.png | Bin 33065 -> 0 bytes .../static/themes/oscar/img/map/layers-2x.png | Bin 1763 -> 0 bytes .../static/themes/oscar/img/map/layers.png | Bin 1142 -> 0 bytes .../oscar/img/map/marker-icon-2x-green.png | Bin 3753 -> 0 bytes .../oscar/img/map/marker-icon-2x-orange.png | Bin 3691 -> 0 bytes .../oscar/img/map/marker-icon-2x-red.png | Bin 3692 -> 0 bytes .../themes/oscar/img/map/marker-icon-2x.png | Bin 4033 -> 0 bytes .../oscar/img/map/marker-icon-green.png | Bin 1696 -> 0 bytes .../oscar/img/map/marker-icon-orange.png | Bin 1714 -> 0 bytes .../themes/oscar/img/map/marker-icon-red.png | Bin 1690 -> 0 bytes .../themes/oscar/img/map/marker-icon.png | Bin 1747 -> 0 bytes .../themes/oscar/img/map/marker-shadow.png | Bin 797 -> 0 bytes .../static/themes/oscar/img/searx_logo.png | Bin 16775 -> 0 bytes .../themes/oscar/js/leaflet-0.7.3.min.js | 9 - .../searx/static/themes/oscar/js/searx.min.js | 2 - .../oscar/js/searx_src/00_requirejs_config.js | 23 - .../oscar/js/searx_src/autocompleter.js | 37 - .../oscar/js/searx_src/element_modifiers.js | 99 - .../themes/oscar/js/searx_src/leaflet_map.js | 172 - .../themes/oscar/less/logicodev/checkbox.less | 9 - .../themes/oscar/less/logicodev/code.less | 103 - .../themes/oscar/less/logicodev/cursor.less | 8 - .../themes/oscar/less/logicodev/footer.less | 30 - .../themes/oscar/less/logicodev/infobox.less | 37 - .../themes/oscar/less/logicodev/navbar.less | 54 - .../themes/oscar/less/logicodev/oscar.less | 17 - .../themes/oscar/less/logicodev/results.less | 150 - .../themes/oscar/less/logicodev/search.less | 59 - .../oscar/less/logicodev/variables.less | 10 - .../themes/oscar/less/pointhi/checkbox.less | 9 - .../themes/oscar/less/pointhi/code.less | 79 - .../themes/oscar/less/pointhi/cursor.less | 8 - .../themes/oscar/less/pointhi/footer.less | 19 - .../themes/oscar/less/pointhi/infobox.less | 11 - .../themes/oscar/less/pointhi/oscar.less | 13 - .../themes/oscar/less/pointhi/results.less | 83 - .../themes/oscar/less/pointhi/search.less | 4 - .../searx/static/themes/oscar/package.json | 16 - .../searx/static/themes/pix-art/css/style.css | 1 - .../static/themes/pix-art/img/favicon.png | Bin 2060 -> 0 bytes .../pix-art/img/preference-icon-pixel.png | Bin 242 -> 0 bytes .../themes/pix-art/img/search-icon-pixel.png | Bin 204 -> 0 bytes .../themes/pix-art/img/searx-pixel-small.png | Bin 236 -> 0 bytes .../static/themes/pix-art/img/searx-pixel.png | Bin 439 -> 0 bytes .../searx/static/themes/pix-art/js/searx.js | 141 - .../themes/pix-art/less/definitions.less | 119 - .../static/themes/pix-art/less/mixins.less | 27 - .../static/themes/pix-art/less/search.less | 57 - .../static/themes/pix-art/less/style.less | 451 - sources/searx/templates/courgette/about.html | 66 - sources/searx/templates/courgette/base.html | 43 - .../searx/templates/courgette/categories.html | 9 - sources/searx/templates/courgette/color.css | 34 - .../templates/courgette/github_ribbon.html | 3 - sources/searx/templates/courgette/index.html | 17 - .../searx/templates/courgette/opensearch.xml | 28 - .../courgette/opensearch_response_rss.xml | 23 - .../templates/courgette/preferences.html | 132 - .../courgette/result_templates/code.html | 11 - .../courgette/result_templates/default.html | 13 - .../courgette/result_templates/images.html | 6 - .../courgette/result_templates/map.html | 13 - .../courgette/result_templates/torrent.html | 13 - .../courgette/result_templates/videos.html | 10 - .../searx/templates/courgette/results.html | 87 - sources/searx/templates/courgette/search.html | 7 - sources/searx/templates/courgette/stats.html | 22 - sources/searx/templates/default/about.html | 66 - sources/searx/templates/default/base.html | 38 - .../searx/templates/default/categories.html | 10 - .../templates/default/github_ribbon.html | 3 - sources/searx/templates/default/index.html | 18 - sources/searx/templates/default/infobox.html | 51 - .../searx/templates/default/opensearch.xml | 28 - .../default/opensearch_response_rss.xml | 23 - .../searx/templates/default/preferences.html | 120 - .../default/result_templates/code.html | 11 - .../default/result_templates/default.html | 6 - .../default/result_templates/images.html | 6 - .../default/result_templates/map.html | 13 - .../default/result_templates/torrent.html | 13 - .../default/result_templates/videos.html | 6 - sources/searx/templates/default/results.html | 100 - sources/searx/templates/default/search.html | 8 - sources/searx/templates/default/stats.html | 22 - sources/searx/templates/oscar/about.html | 67 - sources/searx/templates/oscar/base.html | 97 - sources/searx/templates/oscar/categories.html | 42 - sources/searx/templates/oscar/index.html | 22 - sources/searx/templates/oscar/infobox.html | 34 - sources/searx/templates/oscar/macros.html | 76 - .../templates/oscar/messages/first_time.html | 8 - .../templates/oscar/messages/js_disabled.html | 4 - .../templates/oscar/messages/no_cookies.html | 5 - .../oscar/messages/no_data_available.html | 5 - .../templates/oscar/messages/no_results.html | 9 - .../messages/save_settings_successfull.html | 9 - .../oscar/messages/unknow_error.html | 9 - sources/searx/templates/oscar/navbar.html | 40 - sources/searx/templates/oscar/opensearch.xml | 28 - .../oscar/opensearch_response_rss.xml | 23 - .../searx/templates/oscar/preferences.html | 252 - .../oscar/result_templates/code.html | 18 - .../oscar/result_templates/default.html | 31 - .../oscar/result_templates/images.html | 28 - .../templates/oscar/result_templates/map.html | 72 - .../oscar/result_templates/torrent.html | 25 - .../oscar/result_templates/videos.html | 27 - sources/searx/templates/oscar/results.html | 141 - sources/searx/templates/oscar/search.html | 12 - .../searx/templates/oscar/search_full.html | 21 - sources/searx/templates/oscar/stats.html | 33 - sources/searx/templates/pix-art/about.html | 65 - sources/searx/templates/pix-art/base.html | 35 - sources/searx/templates/pix-art/index.html | 12 - .../searx/templates/pix-art/preferences.html | 82 - .../pix-art/result_templates/default.html | 7 - .../pix-art/result_templates/images.html | 6 - sources/searx/templates/pix-art/results.html | 32 - sources/searx/templates/pix-art/search.html | 9 - sources/searx/templates/pix-art/stats.html | 22 - sources/searx/testing.py | 88 - .../translations/bg/LC_MESSAGES/messages.mo | Bin 9643 -> 0 bytes .../translations/bg/LC_MESSAGES/messages.po | 686 -- .../translations/de/LC_MESSAGES/messages.mo | Bin 8110 -> 0 bytes .../translations/de/LC_MESSAGES/messages.po | 693 -- .../el_GR/LC_MESSAGES/messages.mo | Bin 8297 -> 0 bytes .../el_GR/LC_MESSAGES/messages.po | 686 -- .../translations/en/LC_MESSAGES/messages.mo | Bin 7565 -> 0 bytes .../translations/en/LC_MESSAGES/messages.po | 695 -- .../translations/eo/LC_MESSAGES/messages.mo | Bin 7653 -> 0 bytes .../translations/eo/LC_MESSAGES/messages.po | 686 -- .../translations/es/LC_MESSAGES/messages.mo | Bin 8193 -> 0 bytes .../translations/es/LC_MESSAGES/messages.po | 690 -- .../translations/fr/LC_MESSAGES/messages.mo | Bin 8328 -> 0 bytes .../translations/fr/LC_MESSAGES/messages.po | 691 -- .../translations/he/LC_MESSAGES/messages.mo | Bin 8728 -> 0 bytes .../translations/he/LC_MESSAGES/messages.po | 690 -- .../translations/hu/LC_MESSAGES/messages.mo | Bin 7878 -> 0 bytes .../translations/hu/LC_MESSAGES/messages.po | 687 -- .../translations/it/LC_MESSAGES/messages.mo | Bin 7751 -> 0 bytes .../translations/it/LC_MESSAGES/messages.po | 688 -- .../translations/ja/LC_MESSAGES/messages.mo | Bin 9052 -> 0 bytes .../translations/ja/LC_MESSAGES/messages.po | 691 -- .../translations/nl/LC_MESSAGES/messages.mo | Bin 7918 -> 0 bytes .../translations/nl/LC_MESSAGES/messages.po | 687 -- .../translations/pt/LC_MESSAGES/messages.mo | Bin 7931 -> 0 bytes .../translations/pt/LC_MESSAGES/messages.po | 706 -- .../pt_BR/LC_MESSAGES/messages.mo | Bin 8064 -> 0 bytes .../pt_BR/LC_MESSAGES/messages.po | 686 -- .../translations/ro/LC_MESSAGES/messages.mo | Bin 8156 -> 0 bytes .../translations/ro/LC_MESSAGES/messages.po | 686 -- .../translations/ru/LC_MESSAGES/messages.mo | Bin 9537 -> 0 bytes .../translations/ru/LC_MESSAGES/messages.po | 687 -- .../translations/tr/LC_MESSAGES/messages.mo | Bin 8075 -> 0 bytes .../translations/tr/LC_MESSAGES/messages.po | 687 -- .../zh_CN/LC_MESSAGES/messages.mo | Bin 7465 -> 0 bytes .../zh_CN/LC_MESSAGES/messages.po | 687 -- sources/searx/utils.py | 232 - sources/searx/version.py | 26 - sources/searx/webapp.py | 759 -- sources/setup.py | 74 - sources/tests/__init__.py | 0 sources/tests/robot/__init__.py | 0 sources/tests/robot/test_basic.robot | 152 - sources/tests/test_robot.py | 23 - sources/tests/unit/__init__.py | 0 sources/tests/unit/engines/__init__.py | 0 sources/tests/unit/engines/test_archlinux.py | 106 - sources/tests/unit/engines/test_bing.py | 90 - .../tests/unit/engines/test_bing_images.py | 122 - sources/tests/unit/engines/test_bing_news.py | 138 - .../tests/unit/engines/test_blekko_images.py | 71 - sources/tests/unit/engines/test_btdigg.py | 384 - .../unit/engines/test_currency_convert.py | 43 - .../tests/unit/engines/test_dailymotion.py | 74 - sources/tests/unit/engines/test_deezer.py | 57 - sources/tests/unit/engines/test_deviantart.py | 118 - sources/tests/unit/engines/test_digg.py | 101 - sources/tests/unit/engines/test_doku.py | 79 - sources/tests/unit/engines/test_duckduckgo.py | 71 - .../engines/test_duckduckgo_definitions.py | 250 - sources/tests/unit/engines/test_dummy.py | 26 - sources/tests/unit/engines/test_faroo.py | 116 - sources/tests/unit/engines/test_fdroid.py | 49 - sources/tests/unit/engines/test_flickr.py | 142 - .../tests/unit/engines/test_flickr_noapi.py | 328 - sources/tests/unit/engines/test_frinkiac.py | 49 - sources/tests/unit/engines/test_gigablast.py | 85 - sources/tests/unit/engines/test_github.py | 61 - sources/tests/unit/engines/test_google.py | 178 - .../tests/unit/engines/test_google_images.py | 58 - .../tests/unit/engines/test_google_news.py | 136 - sources/tests/unit/engines/test_kickass.py | 397 - sources/tests/unit/engines/test_mediawiki.py | 130 - sources/tests/unit/engines/test_mixcloud.py | 67 - sources/tests/unit/engines/test_nyaa.py | 66 - .../tests/unit/engines/test_openstreetmap.py | 199 - sources/tests/unit/engines/test_photon.py | 166 - sources/tests/unit/engines/test_piratebay.py | 166 - sources/tests/unit/engines/test_qwant.py | 317 - sources/tests/unit/engines/test_reddit.py | 71 - .../unit/engines/test_searchcode_code.py | 75 - .../tests/unit/engines/test_searchcode_doc.py | 73 - sources/tests/unit/engines/test_soundcloud.py | 192 - sources/tests/unit/engines/test_spotify.py | 124 - .../tests/unit/engines/test_stackoverflow.py | 106 - sources/tests/unit/engines/test_startpage.py | 140 - .../tests/unit/engines/test_subtitleseeker.py | 169 - sources/tests/unit/engines/test_swisscows.py | 128 - .../tests/unit/engines/test_tokyotoshokan.py | 110 - sources/tests/unit/engines/test_torrentz.py | 91 - sources/tests/unit/engines/test_twitter.py | 502 -- sources/tests/unit/engines/test_vimeo.py | 101 - sources/tests/unit/engines/test_wikipedia.py | 160 - .../unit/engines/test_wolframalpha_api.py | 164 - .../unit/engines/test_wolframalpha_noapi.py | 222 - sources/tests/unit/engines/test_www1x.py | 57 - sources/tests/unit/engines/test_www500px.py | 83 - sources/tests/unit/engines/test_yacy.py | 96 - sources/tests/unit/engines/test_yahoo.py | 141 - sources/tests/unit/engines/test_yahoo_news.py | 149 - .../tests/unit/engines/test_youtube_api.py | 111 - .../tests/unit/engines/test_youtube_noapi.py | 154 - sources/tests/unit/test_plugins.py | 74 - sources/tests/unit/test_preferences.py | 101 - sources/tests/unit/test_results.py | 41 - sources/tests/unit/test_search.py | 10 - sources/tests/unit/test_utils.py | 101 - sources/tests/unit/test_webapp.py | 155 - sources/tox.ini | 2 - sources/utils/fabfile.py | 117 - sources/utils/fetch_currencies.py | 161 - sources/utils/standalone_search.py | 36 - sources/utils/update-translations.sh | 15 - 569 files changed, 5 insertions(+), 60827 deletions(-) delete mode 100644 sources/.coveragerc delete mode 100644 sources/.gitignore delete mode 100644 sources/.landscape.yaml delete mode 100644 sources/.travis.yml delete mode 100644 sources/AUTHORS.rst delete mode 100644 sources/CHANGELOG.rst delete mode 100644 sources/Dockerfile delete mode 100644 sources/LICENSE delete mode 100644 sources/README.rst delete mode 100644 sources/babel.cfg delete mode 100644 sources/examples/basic_engine.py delete mode 100755 sources/manage.sh delete mode 100644 sources/requirements-dev.txt delete mode 100644 sources/requirements.txt delete mode 100644 sources/searx/__init__.py delete mode 100644 sources/searx/autocomplete.py delete mode 100644 sources/searx/data/currencies.json delete mode 100644 sources/searx/engines/__init__.py delete mode 100644 sources/searx/engines/archlinux.py delete mode 100755 sources/searx/engines/base.py delete mode 100644 sources/searx/engines/bing.py delete mode 100644 sources/searx/engines/bing_images.py delete mode 100644 sources/searx/engines/bing_news.py delete mode 100644 sources/searx/engines/blekko_images.py delete mode 100644 sources/searx/engines/btdigg.py delete mode 100644 sources/searx/engines/currency_convert.py delete mode 100644 sources/searx/engines/dailymotion.py delete mode 100644 sources/searx/engines/deezer.py delete mode 100644 sources/searx/engines/deviantart.py delete mode 100644 sources/searx/engines/digg.py delete mode 100644 sources/searx/engines/doku.py delete mode 100644 sources/searx/engines/duckduckgo.py delete mode 100644 sources/searx/engines/duckduckgo_definitions.py delete mode 100644 sources/searx/engines/dummy.py delete mode 100644 sources/searx/engines/faroo.py delete mode 100644 sources/searx/engines/fdroid.py delete mode 100644 sources/searx/engines/filecrop.py delete mode 100644 sources/searx/engines/flickr.py delete mode 100644 sources/searx/engines/flickr_noapi.py delete mode 100644 sources/searx/engines/frinkiac.py delete mode 100644 sources/searx/engines/generalfile.py delete mode 100644 sources/searx/engines/gigablast.py delete mode 100644 sources/searx/engines/github.py delete mode 100644 sources/searx/engines/google.py delete mode 100644 sources/searx/engines/google_images.py delete mode 100644 sources/searx/engines/google_news.py delete mode 100644 sources/searx/engines/json_engine.py delete mode 100644 sources/searx/engines/kickass.py delete mode 100644 sources/searx/engines/mediawiki.py delete mode 100644 sources/searx/engines/mixcloud.py delete mode 100644 sources/searx/engines/nyaa.py delete mode 100644 sources/searx/engines/openstreetmap.py delete mode 100644 sources/searx/engines/photon.py delete mode 100644 sources/searx/engines/piratebay.py delete mode 100644 sources/searx/engines/qwant.py delete mode 100644 sources/searx/engines/reddit.py delete mode 100644 sources/searx/engines/searchcode_code.py delete mode 100644 sources/searx/engines/searchcode_doc.py delete mode 100644 sources/searx/engines/soundcloud.py delete mode 100644 sources/searx/engines/spotify.py delete mode 100644 sources/searx/engines/stackoverflow.py delete mode 100644 sources/searx/engines/startpage.py delete mode 100644 sources/searx/engines/subtitleseeker.py delete mode 100644 sources/searx/engines/swisscows.py delete mode 100644 sources/searx/engines/tokyotoshokan.py delete mode 100644 sources/searx/engines/torrentz.py delete mode 100644 sources/searx/engines/twitter.py delete mode 100644 sources/searx/engines/vimeo.py delete mode 100644 sources/searx/engines/wikidata.py delete mode 100644 sources/searx/engines/wikipedia.py delete mode 100644 sources/searx/engines/wolframalpha_api.py delete mode 100644 sources/searx/engines/wolframalpha_noapi.py delete mode 100644 sources/searx/engines/www1x.py delete mode 100644 sources/searx/engines/www500px.py delete mode 100644 sources/searx/engines/xpath.py delete mode 100644 sources/searx/engines/yacy.py delete mode 100644 sources/searx/engines/yahoo.py delete mode 100644 sources/searx/engines/yahoo_news.py delete mode 100644 sources/searx/engines/yandex.py delete mode 100644 sources/searx/engines/youtube_api.py delete mode 100644 sources/searx/engines/youtube_noapi.py delete mode 100644 sources/searx/languages.py delete mode 100644 sources/searx/plugins/__init__.py delete mode 100644 sources/searx/plugins/https_rewrite.py delete mode 100644 sources/searx/plugins/https_rules/00README delete mode 100644 sources/searx/plugins/https_rules/Bing.xml delete mode 100644 sources/searx/plugins/https_rules/Dailymotion.xml delete mode 100644 sources/searx/plugins/https_rules/Deviantart.xml delete mode 100644 sources/searx/plugins/https_rules/DuckDuckGo.xml delete mode 100644 sources/searx/plugins/https_rules/Flickr.xml delete mode 100644 sources/searx/plugins/https_rules/Github-Pages.xml delete mode 100644 sources/searx/plugins/https_rules/Github.xml delete mode 100644 sources/searx/plugins/https_rules/Google-mismatches.xml delete mode 100644 sources/searx/plugins/https_rules/Google.org.xml delete mode 100644 sources/searx/plugins/https_rules/GoogleAPIs.xml delete mode 100644 sources/searx/plugins/https_rules/GoogleCanada.xml delete mode 100644 sources/searx/plugins/https_rules/GoogleImages.xml delete mode 100644 sources/searx/plugins/https_rules/GoogleMainSearch.xml delete mode 100644 sources/searx/plugins/https_rules/GoogleMaps.xml delete mode 100644 sources/searx/plugins/https_rules/GoogleMelange.xml delete mode 100644 sources/searx/plugins/https_rules/GoogleSearch.xml delete mode 100644 sources/searx/plugins/https_rules/GoogleServices.xml delete mode 100644 sources/searx/plugins/https_rules/GoogleShopping.xml delete mode 100644 sources/searx/plugins/https_rules/GoogleSorry.xml delete mode 100644 sources/searx/plugins/https_rules/GoogleTranslate.xml delete mode 100644 sources/searx/plugins/https_rules/GoogleVideos.xml delete mode 100644 sources/searx/plugins/https_rules/GoogleWatchBlog.xml delete mode 100644 sources/searx/plugins/https_rules/Google_App_Engine.xml delete mode 100644 sources/searx/plugins/https_rules/Googleplex.com.xml delete mode 100644 sources/searx/plugins/https_rules/OpenStreetMap.xml delete mode 100644 sources/searx/plugins/https_rules/Rawgithub.com.xml delete mode 100644 sources/searx/plugins/https_rules/Soundcloud.xml delete mode 100644 sources/searx/plugins/https_rules/ThePirateBay.xml delete mode 100644 sources/searx/plugins/https_rules/Torproject.xml delete mode 100644 sources/searx/plugins/https_rules/Twitter.xml delete mode 100644 sources/searx/plugins/https_rules/Vimeo.xml delete mode 100644 sources/searx/plugins/https_rules/WikiLeaks.xml delete mode 100644 sources/searx/plugins/https_rules/Wikimedia.xml delete mode 100644 sources/searx/plugins/https_rules/Yahoo.xml delete mode 100644 sources/searx/plugins/https_rules/YouTube.xml delete mode 100644 sources/searx/plugins/open_results_on_new_tab.py delete mode 100644 sources/searx/plugins/search_on_category_select.py delete mode 100644 sources/searx/plugins/self_info.py delete mode 100644 sources/searx/plugins/tracker_url_remover.py delete mode 100644 sources/searx/plugins/vim_hotkeys.py delete mode 100644 sources/searx/poolrequests.py delete mode 100644 sources/searx/preferences.py delete mode 100644 sources/searx/query.py delete mode 100644 sources/searx/results.py delete mode 100644 sources/searx/search.py delete mode 100644 sources/searx/settings.yml delete mode 100644 sources/searx/settings_robot.yml delete mode 100644 sources/searx/static/css/bootstrap.min.css delete mode 100644 sources/searx/static/fonts/glyphicons-halflings-regular.eot delete mode 100644 sources/searx/static/fonts/glyphicons-halflings-regular.svg delete mode 100644 sources/searx/static/fonts/glyphicons-halflings-regular.ttf delete mode 100644 sources/searx/static/fonts/glyphicons-halflings-regular.woff delete mode 100644 sources/searx/static/js/bootstrap.min.js delete mode 100644 sources/searx/static/js/html5shiv.min.js delete mode 100644 sources/searx/static/js/jquery-1.11.1.min.js delete mode 100644 sources/searx/static/js/mootools-autocompleter-1.1.2-min.js delete mode 100644 sources/searx/static/js/mootools-core-1.4.5-min.js delete mode 100644 sources/searx/static/js/require-2.1.15.min.js delete mode 100644 sources/searx/static/js/respond.min.js delete mode 100644 sources/searx/static/js/typeahead.bundle.min.js delete mode 100644 sources/searx/static/less/bootstrap/.csscomb.json delete mode 100644 sources/searx/static/less/bootstrap/.csslintrc delete mode 100644 sources/searx/static/less/bootstrap/alerts.less delete mode 100644 sources/searx/static/less/bootstrap/badges.less delete mode 100644 sources/searx/static/less/bootstrap/bootstrap.less delete mode 100644 sources/searx/static/less/bootstrap/breadcrumbs.less delete mode 100644 sources/searx/static/less/bootstrap/button-groups.less delete mode 100644 sources/searx/static/less/bootstrap/buttons.less delete mode 100644 sources/searx/static/less/bootstrap/carousel.less delete mode 100644 sources/searx/static/less/bootstrap/close.less delete mode 100644 sources/searx/static/less/bootstrap/code.less delete mode 100644 sources/searx/static/less/bootstrap/component-animations.less delete mode 100644 sources/searx/static/less/bootstrap/dropdowns.less delete mode 100644 sources/searx/static/less/bootstrap/forms.less delete mode 100644 sources/searx/static/less/bootstrap/glyphicons.less delete mode 100644 sources/searx/static/less/bootstrap/grid.less delete mode 100644 sources/searx/static/less/bootstrap/input-groups.less delete mode 100644 sources/searx/static/less/bootstrap/jumbotron.less delete mode 100644 sources/searx/static/less/bootstrap/labels.less delete mode 100644 sources/searx/static/less/bootstrap/list-group.less delete mode 100644 sources/searx/static/less/bootstrap/media.less delete mode 100644 sources/searx/static/less/bootstrap/mixins.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/alerts.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/background-variant.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/border-radius.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/buttons.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/center-block.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/clearfix.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/forms.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/gradients.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/grid-framework.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/grid.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/hide-text.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/image.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/labels.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/list-group.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/nav-divider.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/nav-vertical-align.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/opacity.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/pagination.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/panels.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/progress-bar.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/reset-filter.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/resize.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/responsive-visibility.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/size.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/tab-focus.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/table-row.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/text-emphasis.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/text-overflow.less delete mode 100644 sources/searx/static/less/bootstrap/mixins/vendor-prefixes.less delete mode 100644 sources/searx/static/less/bootstrap/modals.less delete mode 100644 sources/searx/static/less/bootstrap/navbar.less delete mode 100644 sources/searx/static/less/bootstrap/navs.less delete mode 100644 sources/searx/static/less/bootstrap/normalize.less delete mode 100644 sources/searx/static/less/bootstrap/pager.less delete mode 100644 sources/searx/static/less/bootstrap/pagination.less delete mode 100644 sources/searx/static/less/bootstrap/panels.less delete mode 100644 sources/searx/static/less/bootstrap/popovers.less delete mode 100644 sources/searx/static/less/bootstrap/print.less delete mode 100644 sources/searx/static/less/bootstrap/progress-bars.less delete mode 100644 sources/searx/static/less/bootstrap/responsive-embed.less delete mode 100644 sources/searx/static/less/bootstrap/responsive-utilities.less delete mode 100644 sources/searx/static/less/bootstrap/scaffolding.less delete mode 100644 sources/searx/static/less/bootstrap/tables.less delete mode 100644 sources/searx/static/less/bootstrap/theme.less delete mode 100644 sources/searx/static/less/bootstrap/thumbnails.less delete mode 100644 sources/searx/static/less/bootstrap/tooltip.less delete mode 100644 sources/searx/static/less/bootstrap/type.less delete mode 100644 sources/searx/static/less/bootstrap/typeahead.less delete mode 100644 sources/searx/static/less/bootstrap/utilities.less delete mode 100644 sources/searx/static/less/bootstrap/variables.less delete mode 100644 sources/searx/static/less/bootstrap/wells.less delete mode 100644 sources/searx/static/plugins/css/vim_hotkeys.css delete mode 100644 sources/searx/static/plugins/js/open_results_on_new_tab.js delete mode 100644 sources/searx/static/plugins/js/search_on_category_select.js delete mode 100644 sources/searx/static/plugins/js/vim_hotkeys.js delete mode 100644 sources/searx/static/themes/courgette/css/style-rtl.css delete mode 100644 sources/searx/static/themes/courgette/css/style.css delete mode 100644 sources/searx/static/themes/courgette/img/bg-body-index.jpg delete mode 100644 sources/searx/static/themes/courgette/img/favicon.png delete mode 100644 sources/searx/static/themes/courgette/img/github_ribbon.png delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_500px.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_bing.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_dailymotion.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_deezer.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_deviantart.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_digg.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_duckduckgo.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_flickr.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_github.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_google play apps.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_google play movies.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_google play music.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_google.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_kickass.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_openstreetmap.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_searchcode code.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_searchcode doc.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_searchcode.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_soundcloud.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_stackoverflow.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_startpage.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_subtitleseeker.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_twitter.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_vimeo.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_wikipedia.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_yahoo.ico delete mode 100644 sources/searx/static/themes/courgette/img/icons/icon_youtube.ico delete mode 100644 sources/searx/static/themes/courgette/img/preference-icon.png delete mode 100644 sources/searx/static/themes/courgette/img/search-icon.png delete mode 100644 sources/searx/static/themes/courgette/img/searx-mobile.png delete mode 100644 sources/searx/static/themes/courgette/img/searx.png delete mode 100644 sources/searx/static/themes/courgette/img/searx_logo.svg delete mode 100644 sources/searx/static/themes/courgette/js/searx.js delete mode 100644 sources/searx/static/themes/courgette/less/style-rtl.less delete mode 100644 sources/searx/static/themes/courgette/less/style.less delete mode 100644 sources/searx/static/themes/default/css/style-rtl.css delete mode 100644 sources/searx/static/themes/default/css/style.css delete mode 100644 sources/searx/static/themes/default/img/favicon.png delete mode 100644 sources/searx/static/themes/default/img/github_ribbon.png delete mode 100644 sources/searx/static/themes/default/img/icons/icon_500px.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_bing.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_dailymotion.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_deezer.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_deviantart.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_digg.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_duckduckgo.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_flickr.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_github.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_google play apps.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_google play movies.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_google play music.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_google.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_kickass.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_openstreetmap.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_searchcode code.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_searchcode doc.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_searchcode.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_soundcloud.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_stackoverflow.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_startpage.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_subtitleseeker.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_twitter.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_vimeo.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_wikipedia.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_yahoo.ico delete mode 100644 sources/searx/static/themes/default/img/icons/icon_youtube.ico delete mode 100644 sources/searx/static/themes/default/img/preference-icon.png delete mode 100644 sources/searx/static/themes/default/img/search-icon.png delete mode 100644 sources/searx/static/themes/default/img/searx.png delete mode 100644 sources/searx/static/themes/default/img/searx_logo.svg delete mode 100644 sources/searx/static/themes/default/js/searx.js delete mode 100644 sources/searx/static/themes/default/less/autocompleter.less delete mode 100644 sources/searx/static/themes/default/less/code.less delete mode 100644 sources/searx/static/themes/default/less/definitions.less delete mode 100644 sources/searx/static/themes/default/less/mixins.less delete mode 100644 sources/searx/static/themes/default/less/search.less delete mode 100644 sources/searx/static/themes/default/less/style-rtl.less delete mode 100644 sources/searx/static/themes/default/less/style.less delete mode 100644 sources/searx/static/themes/oscar/.gitignore delete mode 100644 sources/searx/static/themes/oscar/README.rst delete mode 100644 sources/searx/static/themes/oscar/css/leaflet.min.css delete mode 100644 sources/searx/static/themes/oscar/css/logicodev.min.css delete mode 100644 sources/searx/static/themes/oscar/css/pointhi.min.css delete mode 100644 sources/searx/static/themes/oscar/gruntfile.js delete mode 100644 sources/searx/static/themes/oscar/img/favicon.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/README.md delete mode 100644 sources/searx/static/themes/oscar/img/icons/amazon.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/dailymotion.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/deviantart.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/facebook.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/flickr.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/github.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/kickass.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/openstreetmap.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/photon.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/searchcode code.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/searchcode doc.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/soundcloud.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/stackoverflow.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/twitter.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/vimeo.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/wikipedia.png delete mode 100644 sources/searx/static/themes/oscar/img/icons/youtube.png delete mode 100644 sources/searx/static/themes/oscar/img/loader.gif delete mode 100644 sources/searx/static/themes/oscar/img/logo_searx_a.png delete mode 100644 sources/searx/static/themes/oscar/img/logo_searx_a_n.png delete mode 100644 sources/searx/static/themes/oscar/img/map/layers-2x.png delete mode 100644 sources/searx/static/themes/oscar/img/map/layers.png delete mode 100644 sources/searx/static/themes/oscar/img/map/marker-icon-2x-green.png delete mode 100644 sources/searx/static/themes/oscar/img/map/marker-icon-2x-orange.png delete mode 100644 sources/searx/static/themes/oscar/img/map/marker-icon-2x-red.png delete mode 100644 sources/searx/static/themes/oscar/img/map/marker-icon-2x.png delete mode 100644 sources/searx/static/themes/oscar/img/map/marker-icon-green.png delete mode 100644 sources/searx/static/themes/oscar/img/map/marker-icon-orange.png delete mode 100644 sources/searx/static/themes/oscar/img/map/marker-icon-red.png delete mode 100644 sources/searx/static/themes/oscar/img/map/marker-icon.png delete mode 100644 sources/searx/static/themes/oscar/img/map/marker-shadow.png delete mode 100644 sources/searx/static/themes/oscar/img/searx_logo.png delete mode 100644 sources/searx/static/themes/oscar/js/leaflet-0.7.3.min.js delete mode 100644 sources/searx/static/themes/oscar/js/searx.min.js delete mode 100644 sources/searx/static/themes/oscar/js/searx_src/00_requirejs_config.js delete mode 100644 sources/searx/static/themes/oscar/js/searx_src/autocompleter.js delete mode 100644 sources/searx/static/themes/oscar/js/searx_src/element_modifiers.js delete mode 100644 sources/searx/static/themes/oscar/js/searx_src/leaflet_map.js delete mode 100644 sources/searx/static/themes/oscar/less/logicodev/checkbox.less delete mode 100644 sources/searx/static/themes/oscar/less/logicodev/code.less delete mode 100644 sources/searx/static/themes/oscar/less/logicodev/cursor.less delete mode 100644 sources/searx/static/themes/oscar/less/logicodev/footer.less delete mode 100644 sources/searx/static/themes/oscar/less/logicodev/infobox.less delete mode 100644 sources/searx/static/themes/oscar/less/logicodev/navbar.less delete mode 100644 sources/searx/static/themes/oscar/less/logicodev/oscar.less delete mode 100644 sources/searx/static/themes/oscar/less/logicodev/results.less delete mode 100644 sources/searx/static/themes/oscar/less/logicodev/search.less delete mode 100644 sources/searx/static/themes/oscar/less/logicodev/variables.less delete mode 100644 sources/searx/static/themes/oscar/less/pointhi/checkbox.less delete mode 100644 sources/searx/static/themes/oscar/less/pointhi/code.less delete mode 100644 sources/searx/static/themes/oscar/less/pointhi/cursor.less delete mode 100644 sources/searx/static/themes/oscar/less/pointhi/footer.less delete mode 100644 sources/searx/static/themes/oscar/less/pointhi/infobox.less delete mode 100644 sources/searx/static/themes/oscar/less/pointhi/oscar.less delete mode 100644 sources/searx/static/themes/oscar/less/pointhi/results.less delete mode 100644 sources/searx/static/themes/oscar/less/pointhi/search.less delete mode 100644 sources/searx/static/themes/oscar/package.json delete mode 100644 sources/searx/static/themes/pix-art/css/style.css delete mode 100644 sources/searx/static/themes/pix-art/img/favicon.png delete mode 100644 sources/searx/static/themes/pix-art/img/preference-icon-pixel.png delete mode 100644 sources/searx/static/themes/pix-art/img/search-icon-pixel.png delete mode 100644 sources/searx/static/themes/pix-art/img/searx-pixel-small.png delete mode 100644 sources/searx/static/themes/pix-art/img/searx-pixel.png delete mode 100644 sources/searx/static/themes/pix-art/js/searx.js delete mode 100644 sources/searx/static/themes/pix-art/less/definitions.less delete mode 100644 sources/searx/static/themes/pix-art/less/mixins.less delete mode 100644 sources/searx/static/themes/pix-art/less/search.less delete mode 100644 sources/searx/static/themes/pix-art/less/style.less delete mode 100644 sources/searx/templates/courgette/about.html delete mode 100644 sources/searx/templates/courgette/base.html delete mode 100644 sources/searx/templates/courgette/categories.html delete mode 100644 sources/searx/templates/courgette/color.css delete mode 100644 sources/searx/templates/courgette/github_ribbon.html delete mode 100644 sources/searx/templates/courgette/index.html delete mode 100644 sources/searx/templates/courgette/opensearch.xml delete mode 100644 sources/searx/templates/courgette/opensearch_response_rss.xml delete mode 100644 sources/searx/templates/courgette/preferences.html delete mode 100644 sources/searx/templates/courgette/result_templates/code.html delete mode 100644 sources/searx/templates/courgette/result_templates/default.html delete mode 100644 sources/searx/templates/courgette/result_templates/images.html delete mode 100644 sources/searx/templates/courgette/result_templates/map.html delete mode 100644 sources/searx/templates/courgette/result_templates/torrent.html delete mode 100644 sources/searx/templates/courgette/result_templates/videos.html delete mode 100644 sources/searx/templates/courgette/results.html delete mode 100644 sources/searx/templates/courgette/search.html delete mode 100644 sources/searx/templates/courgette/stats.html delete mode 100644 sources/searx/templates/default/about.html delete mode 100644 sources/searx/templates/default/base.html delete mode 100644 sources/searx/templates/default/categories.html delete mode 100644 sources/searx/templates/default/github_ribbon.html delete mode 100644 sources/searx/templates/default/index.html delete mode 100644 sources/searx/templates/default/infobox.html delete mode 100644 sources/searx/templates/default/opensearch.xml delete mode 100644 sources/searx/templates/default/opensearch_response_rss.xml delete mode 100644 sources/searx/templates/default/preferences.html delete mode 100644 sources/searx/templates/default/result_templates/code.html delete mode 100644 sources/searx/templates/default/result_templates/default.html delete mode 100644 sources/searx/templates/default/result_templates/images.html delete mode 100644 sources/searx/templates/default/result_templates/map.html delete mode 100644 sources/searx/templates/default/result_templates/torrent.html delete mode 100644 sources/searx/templates/default/result_templates/videos.html delete mode 100644 sources/searx/templates/default/results.html delete mode 100644 sources/searx/templates/default/search.html delete mode 100644 sources/searx/templates/default/stats.html delete mode 100644 sources/searx/templates/oscar/about.html delete mode 100644 sources/searx/templates/oscar/base.html delete mode 100644 sources/searx/templates/oscar/categories.html delete mode 100644 sources/searx/templates/oscar/index.html delete mode 100644 sources/searx/templates/oscar/infobox.html delete mode 100644 sources/searx/templates/oscar/macros.html delete mode 100644 sources/searx/templates/oscar/messages/first_time.html delete mode 100644 sources/searx/templates/oscar/messages/js_disabled.html delete mode 100644 sources/searx/templates/oscar/messages/no_cookies.html delete mode 100644 sources/searx/templates/oscar/messages/no_data_available.html delete mode 100644 sources/searx/templates/oscar/messages/no_results.html delete mode 100644 sources/searx/templates/oscar/messages/save_settings_successfull.html delete mode 100644 sources/searx/templates/oscar/messages/unknow_error.html delete mode 100644 sources/searx/templates/oscar/navbar.html delete mode 100644 sources/searx/templates/oscar/opensearch.xml delete mode 100644 sources/searx/templates/oscar/opensearch_response_rss.xml delete mode 100644 sources/searx/templates/oscar/preferences.html delete mode 100644 sources/searx/templates/oscar/result_templates/code.html delete mode 100644 sources/searx/templates/oscar/result_templates/default.html delete mode 100644 sources/searx/templates/oscar/result_templates/images.html delete mode 100644 sources/searx/templates/oscar/result_templates/map.html delete mode 100644 sources/searx/templates/oscar/result_templates/torrent.html delete mode 100644 sources/searx/templates/oscar/result_templates/videos.html delete mode 100644 sources/searx/templates/oscar/results.html delete mode 100644 sources/searx/templates/oscar/search.html delete mode 100644 sources/searx/templates/oscar/search_full.html delete mode 100644 sources/searx/templates/oscar/stats.html delete mode 100644 sources/searx/templates/pix-art/about.html delete mode 100644 sources/searx/templates/pix-art/base.html delete mode 100644 sources/searx/templates/pix-art/index.html delete mode 100644 sources/searx/templates/pix-art/preferences.html delete mode 100644 sources/searx/templates/pix-art/result_templates/default.html delete mode 100644 sources/searx/templates/pix-art/result_templates/images.html delete mode 100644 sources/searx/templates/pix-art/results.html delete mode 100644 sources/searx/templates/pix-art/search.html delete mode 100644 sources/searx/templates/pix-art/stats.html delete mode 100644 sources/searx/testing.py delete mode 100644 sources/searx/translations/bg/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/bg/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/de/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/de/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/el_GR/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/el_GR/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/en/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/en/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/eo/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/eo/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/es/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/es/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/fr/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/fr/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/he/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/he/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/hu/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/hu/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/it/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/it/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/ja/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/ja/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/nl/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/nl/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/pt/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/pt/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/pt_BR/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/pt_BR/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/ro/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/ro/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/ru/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/ru/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/tr/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/tr/LC_MESSAGES/messages.po delete mode 100644 sources/searx/translations/zh_CN/LC_MESSAGES/messages.mo delete mode 100644 sources/searx/translations/zh_CN/LC_MESSAGES/messages.po delete mode 100644 sources/searx/utils.py delete mode 100644 sources/searx/version.py delete mode 100644 sources/searx/webapp.py delete mode 100644 sources/setup.py delete mode 100644 sources/tests/__init__.py delete mode 100644 sources/tests/robot/__init__.py delete mode 100644 sources/tests/robot/test_basic.robot delete mode 100644 sources/tests/test_robot.py delete mode 100644 sources/tests/unit/__init__.py delete mode 100644 sources/tests/unit/engines/__init__.py delete mode 100644 sources/tests/unit/engines/test_archlinux.py delete mode 100644 sources/tests/unit/engines/test_bing.py delete mode 100644 sources/tests/unit/engines/test_bing_images.py delete mode 100644 sources/tests/unit/engines/test_bing_news.py delete mode 100644 sources/tests/unit/engines/test_blekko_images.py delete mode 100644 sources/tests/unit/engines/test_btdigg.py delete mode 100644 sources/tests/unit/engines/test_currency_convert.py delete mode 100644 sources/tests/unit/engines/test_dailymotion.py delete mode 100644 sources/tests/unit/engines/test_deezer.py delete mode 100644 sources/tests/unit/engines/test_deviantart.py delete mode 100644 sources/tests/unit/engines/test_digg.py delete mode 100644 sources/tests/unit/engines/test_doku.py delete mode 100644 sources/tests/unit/engines/test_duckduckgo.py delete mode 100644 sources/tests/unit/engines/test_duckduckgo_definitions.py delete mode 100644 sources/tests/unit/engines/test_dummy.py delete mode 100644 sources/tests/unit/engines/test_faroo.py delete mode 100644 sources/tests/unit/engines/test_fdroid.py delete mode 100644 sources/tests/unit/engines/test_flickr.py delete mode 100644 sources/tests/unit/engines/test_flickr_noapi.py delete mode 100644 sources/tests/unit/engines/test_frinkiac.py delete mode 100644 sources/tests/unit/engines/test_gigablast.py delete mode 100644 sources/tests/unit/engines/test_github.py delete mode 100644 sources/tests/unit/engines/test_google.py delete mode 100644 sources/tests/unit/engines/test_google_images.py delete mode 100644 sources/tests/unit/engines/test_google_news.py delete mode 100644 sources/tests/unit/engines/test_kickass.py delete mode 100644 sources/tests/unit/engines/test_mediawiki.py delete mode 100644 sources/tests/unit/engines/test_mixcloud.py delete mode 100644 sources/tests/unit/engines/test_nyaa.py delete mode 100644 sources/tests/unit/engines/test_openstreetmap.py delete mode 100644 sources/tests/unit/engines/test_photon.py delete mode 100644 sources/tests/unit/engines/test_piratebay.py delete mode 100644 sources/tests/unit/engines/test_qwant.py delete mode 100644 sources/tests/unit/engines/test_reddit.py delete mode 100644 sources/tests/unit/engines/test_searchcode_code.py delete mode 100644 sources/tests/unit/engines/test_searchcode_doc.py delete mode 100644 sources/tests/unit/engines/test_soundcloud.py delete mode 100644 sources/tests/unit/engines/test_spotify.py delete mode 100644 sources/tests/unit/engines/test_stackoverflow.py delete mode 100644 sources/tests/unit/engines/test_startpage.py delete mode 100644 sources/tests/unit/engines/test_subtitleseeker.py delete mode 100644 sources/tests/unit/engines/test_swisscows.py delete mode 100644 sources/tests/unit/engines/test_tokyotoshokan.py delete mode 100644 sources/tests/unit/engines/test_torrentz.py delete mode 100644 sources/tests/unit/engines/test_twitter.py delete mode 100644 sources/tests/unit/engines/test_vimeo.py delete mode 100644 sources/tests/unit/engines/test_wikipedia.py delete mode 100644 sources/tests/unit/engines/test_wolframalpha_api.py delete mode 100644 sources/tests/unit/engines/test_wolframalpha_noapi.py delete mode 100644 sources/tests/unit/engines/test_www1x.py delete mode 100644 sources/tests/unit/engines/test_www500px.py delete mode 100644 sources/tests/unit/engines/test_yacy.py delete mode 100644 sources/tests/unit/engines/test_yahoo.py delete mode 100644 sources/tests/unit/engines/test_yahoo_news.py delete mode 100644 sources/tests/unit/engines/test_youtube_api.py delete mode 100644 sources/tests/unit/engines/test_youtube_noapi.py delete mode 100644 sources/tests/unit/test_plugins.py delete mode 100644 sources/tests/unit/test_preferences.py delete mode 100644 sources/tests/unit/test_results.py delete mode 100644 sources/tests/unit/test_search.py delete mode 100644 sources/tests/unit/test_utils.py delete mode 100644 sources/tests/unit/test_webapp.py delete mode 100644 sources/tox.ini delete mode 100644 sources/utils/fabfile.py delete mode 100644 sources/utils/fetch_currencies.py delete mode 100644 sources/utils/standalone_search.py delete mode 100755 sources/utils/update-translations.sh 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 4a4ca865d67e86f961bc6e2ef00bffa4e34bb9ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20335 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

!oRptb@n+ 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 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 67fa00bf83801d2fa568546b982c80d27f6ef74e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41280 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

PBK;&Wcg|NX{>QR@W3{K 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 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 8c54182aa5d4d1ab3c9171976b615c1dcb1dc187..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23320 zcmY&6mA1(8T6a0V( z7zzkXUYUXEN9+9I!ap!DFOd#1wlTB=0s{G=z_>rwLFyJd-Ppy62nY!Dzg$rNAC#b> zW_IQ_KN{(eU)_(Nsd6JjiMgTUPb}E#|M~#|A(>mdoBe3JKtOVEKtTU^2nd*oEldqf zfPj=PfBaZ}zy@NZ@n!KN0s$!#{qXEt`TP45!w50c8!{TL10RAG)dniu*zrR^LTrn}O+tRb0xd~0E&>H($0brSGJ*iX z8bUAslphEzmTHiWB72`anLv4VuEY~_ za}WVZu^zT;R-~y&T~BYSiJ>00^O~gpl9q$zHI%Y>Lhsr-MaOrb%y%q|(42pX<4bce z&%S(EIYGx}q8~@4pX*EKdS?h=SI&tEv`GGM8)AScL0;U}brn10v;~p2;1NOn2Um$W z*U=i%VuwBRz@Z11qKr(qgO8vr*&X5{?12dd{6*l`Yp`?k3MDcih%qI+g!qV2n61L{ zS-80y9H-NmrN`sSUC*p$lut-w`?nyb*goYXni_zf3okCBA{zrCwXDq^$DQB5U?DQ* z61o2X9r4;yA!5sN`)f6pe9e8pguH(cK5%0-vMf9zrWWth^A{_9wXmH0nW$}wo9hf@Mt&V*5m2_W0Zac{Bwl*3N0W}7D6V5mO|AbT zMePe7b5d1qntWOB)2(kfH3+1h@`qdCj$7%?Ws`6C=E;z?vBmFy(ZuU>?ZKAjdKnE_$3iyZHlp%_ z77-FteGS2x>7s==RC=EgNc20pi}B5ZYP?<*;Yn$7M)<7;<>9ljc|Q@}q1HAXA>?XX z{-<=FYU*8Yx_bmPn*eq|(6}#S=KV{`|BZ*Xn#BSEOxT0n<2%3UJglMVh`FJxT)N*_o6m(8iH0h%=F{CzZaZ8j3d^x{KT0bRC__^79ko z=tr+cA_{hBgbop+gr}pTjdh4lR9OGJYID{f-h7TdFVsTYrJ)sVL)@`Nes|mRJSCBQ z1vY;D{cTS=MKu(Wy%|e~Iy~QIi?KJEB~oXKHbERbMSWb} zZ$4oLo6Q7!JY7E&nSn99sadal3PMV~{548>MpAHY2H1T`ZcmF;%7p*Gd@)Z2X$V%V z$1bYU`a7{N-&8b(7EKxaD_#{2yNI&{t3rygLIQh8i%wdtQ^A4QWPw@AUkIZjStyRy zt6gfVP}$xz$w}4TO!~910gWc?ujr|I`%rxo*~ZRJj0)|c2kf0tbH}jLi*?h7#a}r#3UcIh%=Rq+9Oy<}9gOY2vy$@K}ixTio-4X=M1@9qI z^=K!qz=h?boc7!Dn&OoiZq*aBh4h7*kXhO z>pcXk->0DSLp`H8gAy`9imj3RrTwYMLn%~ax2R;y6z$S#bv?dXh$n!f{I%|F6CUzH zNglJr&iX(OdhO|M-zijiorLRikL!4b&v<-I;cb2U*9AhJqg6Km0|C@3UPi3VuIeHB zEvJkk^d768V;-U<9n39OEzwHebV z^!;=ohVM{+SKmNmc(fHuOajOg)eZg4gP9Z?_0r_5C&wd<_hxoo_+<48kwZJ{Y3kdj z-euRxbNtS4ORoUDw~*0{d?YbybVf*Z&j3f0Df|p6wtg}#){z60vHIVDYyvXYiqtw5fLstI@;wPh+Bd5ldW?|#AJXDCfR%eUYew_;&(+g6-=ThC?S3>8w7??8cY@rx zXANRWBOACbA6cC_l4+aF!&NSKMmjmK4PZoF7UG%C5 zf)X%cLC&;>^$NdUhi>}OaeOh-03Qt>c;rBMl8FXlh6u#+T;)aNQAM7iYm9MwQAwQ$ zauN?iXC->xfF|9A>Yn3rfOkVpm+8&z?LmtUcZTECdVP6@K8N`=NVn%wvgYT?wv(~@ zRQi1syDn_w+iAw6*B2j_C#*4Oa=3>>HsxLFzfc-lqHiBWPsG=v_Rqfna_4v6=XxDj zbWvX=bCj4jf>-mGLa)^qT)yEMN*AOa6}Y=z5r^W#5+eB*=NMYFLlxp|l;Umkrykmm z>1Pb@=d7ZMXh-p<@vNTD{%C%$y%YYN-VTD)5%>5QvQPlpLYJRSmulc?J zubo~#6g|MIS#tM^y?0~C`jU2#a#T$VEGW;6HZHFWLEd6C6gfhTw6Hw56Q8*V+~VWN z4AL!NdF6?QxaUpsR*ZThZ22BrG(+5-Ud8j`|8n^?HPZ7*MH$Y-GdTEy_<}Ip%UH`% zC_ybkuvZT`(*5-7zTSgt1y-AX_=4Vq{_y1PK|t=n8Jsz8N`x^1R#L(Hf(SZ(R}et= z20=K0`i!{GTB{~I3$HZ!fZ7PE0K3mgrlOj^=HLjmlzB{Q!INjU2`4JhvkVArhWI3g z2BFDRMNusx)0QK>n-{_BPLkO*tH?}~b^*t2 zL|B8@3a#it1GzFLG>-jntCpno1TF0OMs-3&ICPgAm$awK{?_0%(W?W=|3Ym<2B399 z6?sOv=odFeFq-4ZH~dK}*A#W0I_F%hOcy3B(B=(oS9N?rZK6R)u8SFgYl67%j$Vzn zT2com)G;k5ej>5&f(ldAjf;DQ6!5hOSn{C{3@HGgJfyHHbCwb;JWINl)t_@@KmMH+bk8Q`tU&fRBnQ(#)4NSadxDOZI(w zdDV`IZHTev{l3e|YJOjG)!*{Qd3Bbc-oK>W2LbR{;`&r7v=uuYN}Q!j?bR6qQf6%Z zD|U^HaP=Duw&<9^4wcHPM`Vo0d8#?cwduvt)W!CY2}SzBBsBVDmS^qNq)C$4z-w!v zu|}GDNU(nCqGP?m2nGh>so7Y#2jSAF;UD3l zTWTJlAQB4XoWDz=q%Vn+jEY#AwT@9A52;uB*W>Xje?f=`^s2DJ+s}6b zZHctO--vJs(vA6u2D!C~MMV%ZF_OWKERqY*L7bn~pu>emnX~};w>xKsx+HmlModD* zRe7jxvS`Tr6uHz_O`!|yld+VyK0FQd$icoJ&6I5J_C@tYl{!GM>wg8ezB^sMFG{SP z+~tO=8DM|68>>8kL{vLa+9stZVE2&^q(j&WrimlxADG12>h3l$)MnnoG~F+Q9%u&_RYNWV-S zu8Zij1T3udO7yF++y7qK8?@Qy;j&>d29gBr(=CZ4lKGZq^?3#ajS1CkdX7~BF>3+> zYZVG#qpmz`T?l5}q@jYe4}&tAuC*{c-?JynbwY*R0wc+;hotR!1CBsHEV}H{pEV_Q zQbs{v@#pEsI<-g|xh#rQJeXH}di`N|kNqjL$UE~3So5Z0bsl-UTxtBvq=J|gu+RPErd8o zq%Cu)1CPBz7A=EEzAUR|YC=IU9%hvt-M5s$vP}yYbrS8_xEfnDFCI~k&{z?w$lx zkHl$$>l6w9E<=%h&m}p0DcU+fGPM`d($iGo+S3fJhaypcIE2yU{5H<0HCgoFK{GLe zCVD+P9e_etX_H9_t6xc?c?>7@pb;TOf6%r&2oND`VL682Y@H zo9cs|v@$?BZbm;;TeI&1a|hDjryghe`LAHHYtRh=V`G;8&hH=u_R(Y1pv%n=LH^3^ zFkvIs>V~3aP^2c9bjt$HI!&KIsHF;<6GGV<&cs3&h&!7&F_0TJrW*V^F`?h4z4b9P z)shrVOIq;gnBtPE8xy|c?B+5Qhe9v=A{q0$_8i?gn>U-#3cMhdDV#r)gg$jBSHuwk zk}gryawT5)H|i8gP1CW0tGr3sKVvSH=C;mKYmExi&<#lKQbxbVfh72pcQ7oRvXB%= zj1OXzBoz0nqSwe)?dUE|N0dA`Jm0((=&k$p`L1c)=>Mo*a}LJx~+>;2tcjSh+G1pg5Y6PO}pj8+;DLXc4La-kzxi{dPSiJ7 z8JC>pyci_t`xsI3_*zD$W!*$<4tXVP|Lyd;LAI{(?h2Cw%dD@_;lH-jHe9S+i*4E z4mm+=yxP3;fjmRcM+tj5WK$Q-9_(!w&4?Zu{~+v=o|o`vvKeY_m&uw>iUOhrn)3ws&_6vxHpM+hCYx}osCc0Y-Tyq0z_HH?lw9s=QM+-Q{gQx~FocK9j!8!mtbNX&zBR0Xt$l zvErya$XNJ@m2B@ie45(Z(19?S0|j@Eej=zw0gE??YVlwp4LSl7VHUHoo|LraFf00W znbw<}e@IUzes(fu}n<{VdSNo|T`)7axnJ2E3 zGN-K>ywjN_qvqSYS+3(Tift}Ac+Th~V)w~#F13j;D~$iUE^?zyrm7R;K!FVAfwf4+ zgEe5#q65&2_@2P9Xi0@IzKKB$Mr=t77zjDw^ry*`L~i%3hjv^6l}?gMTjnmHPNyRD!RE? zVzeC>gkFuW>V5P|ms&5GT4O@NM-mhCx+a!f0)LQsDAs{!i(cE9Ov8j9Ot~S$SX^Tu zbvv@~cen9fE3YI>r2~|YyQVnWpZ-X~m^M6OE$L`m&MG`G=33X8DprYlBgvrAjN>#) zf7F5}TO}Od#i%Pvr08HxB1L|F7Lms;vt;^z`LYoE^HAlcM$*80N!_Nc@Z0C)>z37! zB*8pC&7s#0b$L(fb6zzb_{hxyz+_iYonkQLn|M^r48oOlXXt>e7{zFo03wLhcxL@> zruxmZD;ZM5U?3RR7ni`br#{#)H87#K@FBbE7!;=-Y}c+8!h3d5JExlz2JatQJ+?rH zEiUGqC0jaoW>(Evnh`H^?>C|E?;wdM>7y!8D4dVkC<+|T0zP?LNZT4#$T22k5m50< zzoALNpZ84Yo=WEiK^k;g##y>nq*73%RqJFJOX%P{Sin)USV69lwgt`-QDJjC{IgNf zBW4`*siNB=F5h|FpHc}mY9&H}jGvvlX!|~~dIc_J`?;(WsSic(jU>39iqS|Q7u!DA zY&kA%G@cdsQv^FWgQ+Nx#A;({7tI>&nigS1N0T`xz+mg6@_{zT%;E%P(``j&bsETN zs(q(bWF8KI1M_eY6S%3}4I-pbgJgDL2EYIzPp(Kd(4_CqWI0N zt8t_kb+H2&h#4kT$#q>Ac%Z2bj@0N+O;y@sWv$8hU9Zv@p#uT7sP~{kG6820-K~jc zzx+zAW+=CEi%kufkYzrAXi1hFg5D^8VfWJSQx~1y>x~0bBV$33&FY`a087m+i@@r# zv~L(PphOgimWm81wL^lXk96(eK$#U=hQ}pu<-Srb@X)RzEK4@vVL9cwNBv&D7`P0@ zqV@&7+T19`yV}oc>o1R%dLPHOtgykfkQ$mBKeZU*==5=O;{`t7RV`&nOFus5HWa@{ zXbhx+TZxRv=(Ko|DZe>7Tjhggvxn2ed0umrYSl8cq1^h1GLxv~Ovi$ld?|yHWQbL0 z!Ivh5s&TPz0K^%VfE05%mJqQKs?A%Hu%Xt@^>Aoa$L6|fp<>G;+%>slePPEnR_yRL zj;yc0lCyoP$Ic|g#bX(o<$00nsg*!S33aGHMx(FL1IZKmm2(3;)8v{BEh zq+0};_3dYnO)g&8rn2p~Esgh&5iy4}Tc`s#l(NQVP*B`-s(Tsgb%=E*x!`vNJk-`k z+fm(7Qcae_0=zlj<0~2F)s}a7tknTT`cdo_)g;9@CX6}Sx(tZ-vBXh9eV`-C^l3uT_&kk_ zy!QGr?i9qmGaJ`03`VTK^)eYd43pD#6!NwJr0B=zjQz5pDVIxqPspfGxc527cKuN} zM+02tzw?((Ojfsh0mh)!EsE8yz$@B*zv5LC{@~DSWie_CKtd_%3$Mw8a()p(IDD|g zE`aGjSXm`BggX|S0Iz8=DQwWq7Y>nH=l2gF6&gHY9=4{U@)*&>a5Lg$i6r`O!H}dD zW;VLr?c@ISTZz-X^w-r)NsJz*7Ik*4Ly0i!Bq{Zd;rF?m8fkO1OM@>WW%j&Gv#v`$ zQmZ$kLeIBScr38Jb@l%c_PQ|;xB~H7qh?jaoofQxl!Mou$divTfpW_5t{jt5n6rPK z!vRqg8v?Nc`M^e6lM(@2!!NA&BnKun1vVjc1z9YJv06oEUF=G;UtEZ%aSas1z8-O2 z9BC#xzszD?1bF!myHOXw5=A=9o9-@Lhm!h0YZ-|@A8@Y(+_Z-DK5aN{$p1>cump2t zD5Y<$oDGvcGH&@I&=`_@&z9%lM_#_W8iyXJa<&`Ydn;~#brX*PwN-j%3hf05d z4E%>Bj9t_c-iGDTJ%p5oMe%gVzvc6bd`PTb9cQF~$q=bA787VjPi04Chi`i>W<+{G zV&FRA7KPur^W&w!IseMOaI{i>RU}bnWQwl$BQA-{N7}-t4=-KVk!vbXQ}zLtKK~Vb zh}Ni+HS~8TjiAhC5SP%}5)++t1N`_`^O*%;^P^`Rj#KY=G1%z*MAySF&MiUH~wJ&BDU^kXcQH6%9!xbzqRA z*C;FT!ttCmLLmGAVU95En90d_(qX5~%fa`pstx}K4cq`D|L4WUM|^?pXIDSM7j{_` z3G3~Fb+5YFcta__mAzP+vqYM1(W%@8)d!*dz-)tf@tMWp!rn*|T0x9DwQmg`{~HF^ z(&{06L_~x$VO)QgY!}xSiz9L|mX(gredtzS?t3cy_RjmTIU(u5dB$Pw+b^CLxKo!Kal-ql57+p#JJ3zg*_!Lh#CTQlhLZaSdUpir$y9?7cH^D{5SFz4E4#R}~cZf9Y7m zo;9Cm&MV)C>%p+!bv-*M+$WJVT;|RqRPchoQ_7BbK-|yWM-<~FecpFY< z*+V%yqBEN@TuW|VvPKxu;wzn6PE#vLx(^m2Npl0_=R`(f{eE#>@hhO=C}MNbxWW_v z>i*?56p5poIt)%$`T(F>Fbvwm_u72fIj{*&-QjYl(EG&}&x2XCp-|gm&6LNw(*^~r z(;e^7)q{$HCsydP(lnZ{CMFoZw`Di*O0teoyeuOUSTp1qVs*`Z9<21;EeAe2nsvN~ zRC6*s$3cgHx807}TdF!K-J0iGN^SO{w>QZ;&Y$k3Kg?6j$YHFGxQg*a{%}-aq4xqy z&jBywOH07(H!X%N)*9k*pouLg-u)|*fP*&bSExgq7b56vts%pZKc$!0Wz)kTr{n^c zH0~1dFP!u<3h8{HY$Lt50id%$jqN@8k8{VALlSz2UVh`a-#R#>zHXSNNR|{7e9pN> z7TX5KSq#wFmVO-1xo)>HN)vR#Rlnv;&}%R75X^KT9xE{?m|>iz_BH-9O;l0+ZPl<= zgateSH#Dy&8cL!Z-sT5hq(D<^FoqY@mUzl=C-x$j>?y7nvAexvXwZ#MsHgqBZp zatbN4V_H3K-L2vU@+EGATIm6Ap`GU7lnAV|6g`8C(61y*zDel%2}VNAy1~`blPHN= zu~bPszDZI*Nw!P&qvtzvpA@&tGdJu;DIn1jLdX; z)t`xZwPI`TdB?s+nt}J71mU}hawwEbPnX$OL8-5nO5zHu%kT?MIW=*XjkB-H;p1>i zcVuPz(G&BP?D09Rzm-PH5sJ;n5|jQEen*(AWy!9%8%FrobT2yz?d&1r2KSS&4>U<6 zI`!cdm9dC1Hqn|R>+xX&B?|~3hd5zh)13!mfVsLczdYF0Z^iL|oZ=M%0c8`h0j{;h z%1hkP*~06j7+rI@eA;#HV5_3yPVSKp^*V2eP_Sfgqg3u-*%?R0LP3RyTYh<}z$74T zm;u}KQ$iP(LarIp;*m~l_iNZU>-f~@+~!>SGMv8xF)qs2Y$b}ymmJp+*51+kk=cjL zmrRQpnwbhoGj^9~t(5N((?x;Acs$~9zAnWpC^CsfbL2PPH_JB*;3Rr>5>gypdKu}@ z_u^!zU-oM)A~Rv>w@^Qe=A>t8Iv^I5(_hL|C*0994Dztje1-tP3-Ei}#z%jPDdt{8 zyj~NQD-NaTJp#iw;$eW^b71W?UD@s5BzgyHwZ@1vXRIB(t^Jc6R_Dv)Hs|F8qoLtu zkC$6KPc3aY4^Z{pf-Y8+AhHwBfE}WYF<334Vo!l}AXb%trV`AC8!T6My>xRvk#pm3 zHHM+JX=1+RLngN;k-3IQ<#A5MJ7DB2=>^LqDb1%kc#Q5A6%d%>IN;UIK4n-`2>D{q z6jHM}#0~z-%3!K9@Y#+aN0N<0nV7!}Yjdma*li{=yZCa;H1McT5{GWCXe?F`+{8IZy5ljQQS zrTFrqEl5LQ6y%wNh;`4Sr5J9RFfaH9Na!?n-MFD%$2Vk4(|tbc=g}P52_RgNSWcn3t)I333gCka0q_DoXC$EE|u?la)3Hi z^Oqsl%8F|h!WfxtA3&}E0KOg)%}(*;8p7JP~oIr7x~qr5ZS zt}-eG#D;|kb-q_a=YwMke!SFlTUXIIIyhgBr@r1$`M=v573zGUZ&Z;ovB#T+9BM0n zr7D53GV;cMPnitw@6~l#XLgD-r1|n4y?bO!UcEc(qc7(MCKr0=6j!>Gfu7UOSM}Wr zrxrvQMB^yRGbu2{3OLrjP=6`>V`nK;{YAu2$`B8FPF$7gZq2ZawtwRV0kK!LeuHJz zBRuR2nG8L&T7&sF(BmF^9-`K%l-a6BxnQhEsSCcMv@ca`7C+N|8~^)`NY6R>9&v-F zrSt9am3)7()aGkIp=6JF|$3I0`=vgS2}W>J>gIe0La)`lZ1P z{l;udc}QmIM(7D`(wZl?Lb}i=W9(rVd}caMm3YX@2^XEe7&6ov>SA_Ul!YAv^tDYe z*R}KK;n3W|(DgTksHFp3@6t-fBvNI)YrjgMY^JK*K9SzP;OKf3rVT zZIRx%tWtOEFkX+LaNh*i3kxphn^$o6AR{?)Vf=48wJF#hmJAL{4=%^PHvR5{s~IP{ zw@K5SuH&}_b#waDN@Dr*1#;8 zj3>L`zy2mj!ymgpko;mUZsF9%+di@q6&^JI&CNM|2-W!Zeqx=@JCWw~Na&^Xr+cBx zD~Z_rhQn8JeQezgl~_%EHY<}DHhMelQ2W>38M}*g^5Ct4+hNyYc-PQrKYdKg5LHHH z5W7c4sF^;~J5~Mpel;s1wg&NA+sZYw=yb=+oocgx@pdsA=k7k;S&^0Ye2PKV+jA=J z%kv8!s;L>%L)sb~z5JD`X-KkMJ5d1~ffCHpybzHPuu8Wkh9i;1AKMAU1s;ZClWgMl z9P`0tCm%NxKJ+&MOk+0dFd)syx<+DEDBOC1G?twC@TmJP@Pf+(*wj=;G#0iQZJ(iJ zhG-xA3G|5*R@}e@#7hh_*PQ0J_Ka#hcc~Q+8mb_($57A2Z^ikOt#!vf@PA|k3?1E5 z^UZ$&A+KqZAMh0`O@?fzgWeM%dCVoQ%|~*CFOh+?GLu=z8cs0Doi&=R*WpzS47aux zHba&$jRt-gFb4(L@D#uGjmM|c$++VCtQCqFUas=KKW6lql}beIi}Ay+xI^LtKc@0l zdkQ#o-z()ZN*r?{x*<KqloOmbT5w&V zwbjn3a$Q(Enfrp$2j4p_eha~MoJ&}&iUWxSZ!8q_P97wWkI`RGWaL1RonK|Uak^P; z{w86F#atZuy~}Jq{ejUdkdpr)fS;-)D&h^{m;kRv&q0P&gY>_Wn_t;WSnIeQ`eb z%#)mE*~XX(4i>^EwvF2`&wtc>49nS`qmL5rVz_@uPo?s)>dW#p*sb5eNQ$qmB5fE7 zIKEk*|9H&Y!}-D4T&BI9rH|YQxZHIugY!WQFWiyQn?n9k3;PL8)U< z#A$~V3iae6z(8e(o%*Jz6x-yjLA3G>j@cDD{8TQFa@~$UQzl;@bJcoH%=3~W6|DQs z(HWs+Dv4k7d(U{^^k~iOA&FEyEHm?ov{QGSJr>~ zNBu!tDZKyZ{}g5cj*I*BSypu7bHuIB>1sJ{JNP717@@1r>7Y4r23)bUfoFRm^)9*) zCp9u|gQ?d{lA>+D7QCSr-=sytp!RCmlefdPbI3o?<*$WGQBXkp!Cmif{c*L*AGg&b z?7DWdx+ZbqK6&wh=w7UbYfJvH%6U0zyA-;}t7CBq?(%dq3th6bFl7)PLYI4xVL;II zyHxo?4$HrM`P6?8Tvl|24X-t54n_i-h0-n0Sl27fDZZL8HpAEcQr6*yVHCb~N7E27 zmK=cCh>pD6WTW;ikgkvgiM7ROCf}QC3cT(BH$oGu-0t^8PgZ6MX?z=8Lz0ne4T4^V z-thAcyiPMh&#zu3J_ES$FBkO~$SuMt-s!u@48@57H?*$e8Pwbi2Yrp3CQGtR8@!yj zUk8vkyy#dDr0sf^D6wod7j5Ylf6w`wCmvcUyN^|w?dyUD_KL31 zE~V1>J!2e)z`E#xwN&7d0=DYa2DB6pQ4$wj;@8aSM@4AZA{vjr3qxAHqrY=7T1`94 z_r7;6x{PXo9hdnJ!N8{tBM9uaKE8=KN-T_n=P(rOra}Vi)`j2v%gIZ{7+g3|lAtj* zB}}a4stt3~a*NENyqPR5c(%njgkzR6v4J&RA53RN_zXRj1VRWa@ngnMMCvLZvQ@+s}}=U?P|DLxeem<(Nuv7p63NlkA7!CE10D3wO$!ANw9 zObXX`YL=R6%2TeGd1?xrLK$VEwP`qN7HPlo`MM}dK3I_H9Mzu;W}$)%JINEGUpF90 z#}mTOLB17SWhL}ZMRGTaFgmU`2O4g(>;@kprlF*Cp)kpy38(i>~14$R3s?6^?3 z(HgVQFov4jM7QWqadph`*vm$aIIXJNNcy|m2$G|ntBgb!GwWC48iMztD|o=(>;15q z{$%3Oyvm9@O`4JoB64cJ6IF%XU*;BiuoJW(Z#j^UH$l#9HR{Mm7GhSUp-f9TbS(>+ z=TBhELjbeJW#KE%-tr3Zh`nd{*Z|1O0F`(MTCf5%G2HfRAaIr0SmvO)Tb5xAR`)IS zDJQ*_aT_PknaBS3@{3I7may&O+zm8(y_ea0+%G2M5N-*A7TFy3Ev_pPhhj93^hy2p zsf~STscg0VHv6)-suJJ_HvfhYQrC_Zn#OPKnOTJx| zt$bef1E2v24uA^CoX;uvbNr#<^;$Bn%#1V#=IB2G9-e7lqg49ji0~i?uStqONO;%fa+^ReCL3RZjio@nXo^g1nNPbwp1HNQV$> z1@gTfZyF)87$l6~%5yxJnEQ+ie9+G%;f-}&?6HbOe(kPIzzE$iqX`vfok4&ai`W-d zwC99WD{QBt=6MXVD;D962#XX?i!3ihIshIg{q>fXgAMys=@kLkS%9d+mfwd@#_C~~ zWK@5#ngAyP8WOs%@7M-tVjQG={`OIT#6O?~USMV}Aqz>h#^!wFb!x$Ak5eY`gw_Il z+T)(XzI$10nIxlz0YQ2v4bhDugbSQ_y@s>>rHp1+Svi2@-tSsqlpIzzPTyUJ4&6Wg z8t%*#w>(z0UiMXQELXctsZ9~k5wCOwHVp$8E;=11PHAtA3;??YDwCu|jO0#YA&u$Y zH5r8Whl=eb)AhDqcB?eTs5~8M?tF{1{8~NvkvAAqv1XpE@W8WAi4NlSL<2eyn*gM< z`9H|9_I|T^m{J0!3b3`LzciFAtd2LRu7s*s_Jsb0!7S+S7aJc*lt;`*gA-fKO8ArY zhA?VR7)jaRX;6nU@n|8Tf?%{mBM3tZ{xr8|dm^KZpSP}F*K>^y1+c#*N_x*PnQV4j zHXXs6C)_oV)=7T8wRg}#7y$*Oxzi|WxACj3t`$g+Hqob;^h}z0MYNO*)*)W%TP2K^ z8+E9AzoFgl+*G|4FIloWVp$TG!&6mGHAR&+;NTh5J^p6y6{5nltCkJrWQ|oU6qW*h zPfOY$qZTp;a(A%n4fddVdJyiB=7!MR^#1%L6Aw9d{;jcxYG!qJqe2pMrVyVhg_AWH zCaVB55F%KKa5^A)lmMTPG=x(hh32&U*SA$xDMyd3{ZPxizi!QSz5K)*82;WGBaTay zHDeWU8ME{rnLTO@q8U-xW(Oe4ST5z)w)yoW?X}$W+~i-yIXAq7T_olt03# zG2Gu}eml^<1&ha=qIj=`nCg>Wm_0+Cwd6oS*LRkQkSgAw;gvpLKW`3noP`D1=r5(` zPz>bAt@<5_%*bgTP#IghY!XJ=NFJ98zDt@(K^*}B$ts!PZjYpvq%tq5kYKLcJ@r)h zpjGeWgspjG$}U5I3;E(wFu-T*ttBj99nkVSJy04B*>3M>M=4CJBW{W+wr zmo8Lbm?dVE#ijL><;n9dCt|#Od|9HFF4#}Y<2rV})IKejs~q4`MWlQNc41Kjp$r;F zAUY8dDHmc{hLF%=Kik+j1W{WEZP4aaE0T_9G2k3)50J+n4@!F~;6Mm#3~zA2!(uNW zD?3~9!k5Ezu$*P; z0Z-5cF&^e2ZT=G7;H2(U6=DL_gI^{}SNj?dg8|^Sxt0p`cq^jwVM;7!Xjm8d4}Ns& zKcd#kpeC&YrVPU?^63<(P>{Ui+6jp;gFDhm^1pecu3C8b+kR_Tdy{IMWKB?1fmzJA zRrWbi2iAWJf`OWX5*Mgp>n7+MnqV+8M&DPEmPa?H%ZJ7^zBIqoh9?*U3kCchz3T<( z{o=DphBZPs)&O&+xL<}PTrSUw@BBJF-j`J7B@go*T)LO-j{0ZZpPSq}+fSEg4@}1L zZ8|B8jgb2gyHh2Popw{~EdhN#pk1m(0#ygca8F4f!i2@Brzr~+t!U)sEME!yD(7c} zHIM`C5Sn4OHuPfASSw^KEK{5G&ZKT-udhQ|yIrv`02n2nEE6 zJaaj=cYtkxDp%*vn;v7!mw#(ERHUI8&%?XwWWwd^?J-?@A*9kw-cvd2{8XJT$}8H$!5 z(CR70IjoaC>DD~Sdvbq8(GW$Ab&QVqs>5qM-s&(pM zPqqe9RFj;kYc-8w?^V+V%7{u54k`7Ve?+hh+r~`oRnKXVB3p_X{b-SP*}HtZ{G!PA zYJH&DPN4_-LI0Qq?XoMhMUDvc#~1H5z9hRdmx!A;m8^?6m~Y-#b1hlP<)Eq8U>?U? zbrG~tojEl{f3~|C?x{5NaaOUOJ;yJ2hOz;`4;z|OgBGHrpdB>_F3<8WI*%OHZMd3j zy2oRMzZ)xk)fy^F3L0R20hg0paZ$rdG{I|!)H%|BW%n4OCnFJO{@5hlKEt@{ZF)bo zm3&_P62l@ToZ9vsZl7rqgY|j&J=M}0aCXo$QWJ`uVjhB(*uS+H^UDM}9(ER4+JpW&Q9Bny4m*?YQ~L|5@IZr?xwVdan$7a%9{gv7nROdai@`14 zG+-^|Z})4_OtE~I#aE~AS0(LCtNXU(!?C{8pLWYD$$@TV2HsDljoVJZ)B}69$9)?5 ziNy=R_Yv5a^;THLpxNLO zy{q2MTR&jkfAcY;d3}8rjNG3Cyi-4GYlGzJkoOXtWoKd{@;N{&Tdn@M?Y}BW7UX`* zGLMt1)|BC45~;O zYEbYSZ2{~+yv)QlkAVg?M_pjZ-!GCpjqn>zMaydQ%*lyE0`=2E_1o>1!sJ380i_My zB})!KN8vNL^sR*WbvXhjt`v!TIljZl+nd*r_Ksa?e3=XQf1O-aR2;mzg<{2Bixzj6 z!AsHN?hb=%ahKw5#bL1GFgQgEgBN$VL0hCa#pd##a~|%x_wD3M@@21YV9+3{YvzBcTXYf<5#f zw@nazWj_=%=H(>O2QSy@P=u8`{8`_bk}x;!P%>I-jlqoScuG}=Yua=oBl+#ICF~F+ znS@$6yzx^4vw5R$n+4Gep@PYrOxf{U!b#0SW0W|~0Cd`pgH+d9 zHF2Y}rq%oV6;IeW|n{J_U0dOcSD`AWh!D^dDYCb*c8^ladlx6e8v=7}U zpGCJ-DErivDK7O9PLYZ!KW$fh`Bl7Ghke)_A2^fB_mP3$@dtVOu4PdD;J9^%pt#r7 z9aUCSF@MAA8f69~*msmp;gomRMsbEyIuir9mRT;mS7@#2U>)4Yq%WOoTL5&hULy8K z>kDnMX|3fn-RNuw(0Sen*8dtIY+Cz>5U7I^6VXeO{2jLdd$q><>Xl&1Vu0p7fs&1| z$PbIJ`zdYzEI~m!7&#%G%tX&h5*}N*sl~^UqaR>nhkNBS8AZM}wh=ZX zrjv;)`|w%_y2#qZAId_YsddV+wJ2*du<$W+5t&FUFZk{rEi3ntr&SUnt|%1C=Jd5_ ze_CF4u9zeMdmT+erqTwwyjqRMS zXmyK_a6D!#O9m>R+q5u*q)F~4F&iq;iKuj7YDjg=gR!K0M@3p&cI+#a>do7bc+EFf zp}{hAArKj;X%SHZ6D9Rz4`|SSmahv#VAGy11cXaX)Mt;d8M1&}1|-hAvZVNiXA6o< z6cfy5!JL;QBlt}Ru*oAMLs~|FY5`ga72TPzIc9tZFpU~37kdem-*}k9(J*PIpJJ^J zsSU)i+YsOesy~Wy%t%w6zMqz(_qC;@@v>^vIJuyqXhxU}irkNHR{VlcZHy_J-_{`! z{(i{Z^`o?+;-T}NH3_eik^=@7nJ{&KH>NC>I8$+d06Es1h|Pqo^o{1;)^}_EW(|57 zyJj+53*y)m6e5F~AR#?Ia_O;t0+cCf@_;lqd9@>cWM%$cNkbgsDZ7Cp`OsmBv5a=TQADA0^??l-fO1^j=fqzmv>$Ik zsF<+b%&B*pk!HX9Wifnau{En>S<+**we#g+tIq++C!fFshl@IZ%_AS&j%yNkj=w#j zV1zL4>BCBv?8m!_A8vU5w_+jRJAUa*K$Sh=>u;o)@%gZm(Hl#>>H9yA=VDeWW`zerl}&-1icy~%Cs2WRZT1JiK;)SUZQ>Vwq?HIZ#4y{7%`Ht@uU9-2mT?U8mz zC94OXy-c}dfYYZ@TnK!7OnYwUnU#=S)k-Tj1Py{Y_*g>!$igUn_8Hg?Yd`YAZ|zO)ET;+xY)CD|&4M8hSGJ5rwlLozN)`xJkphmTWhnkH7R zp|GN?86tSl;KdX2OoQGhRYBxMNYX@MpSn5D7F}DSPf1*q`Ib#*a4Jg@qHh z`7qyVkKaMCcRemWNY651aHvi)Dt;N!*0nRH%gv3csv7=?{>O*|2rMzztJ4FC53iHh~I24S*ZN8u3B45qTO2k zV#a%2-hio? zIFEIohf8EYWRDv0QIK6XdRv9JD+t>+-4?eH^&08HLs(EaIj}>ufdPG-&FK`ox(hP) zSX*Zqbos^?mzT7`kU=2R(_sFto#;e1-jS!3{wMk2OMcoJ>~6zIk%mvT-Jh7Kvbt$B z8|rO?J^g2Xr^H3M{Vu`P<)l*|Vr*E1X<+$j`p8kgt6ScMbN952xjmdzc;`UuBmU19zH1 zdQm<7)we%}!ruutZS5wmd;bx?EJ416t*z8Mi{3Jr!!9It;_W3U$&c}W?2NupfPAbz zaEvS>tF=;!K5Ao~-wL{`AaKW`2vX9W!v);+3Ne%UcVx zb;L=lm)%rYtA=x^cwa@f^IsmG_fHBMF!yLCJ+BFOHR>7stJd)?=Nxz%8iP-Ve6eSZD~t{%G|HvhpWj*; za3=~ov&HyCmD2vW$N+mUE$10$G3&6M?QY&iR^o`>Vh|lw=YCxOOE?w`X@(U<9Y7~6 z)Fcq!<`YOUk`P*#e17Azvnu6Onjf2;iYsll!t!`CbngkGOAaC^m4^RW((d+S-n)L~ zTM!mauKzQ?74*h_S1@6)A_2|}RmHj8#A&~vV*Vg@W*Y<^Q_2%(ZD@hdlKyCe zl)xetJ8!pZ#}qf;Cj>*iNq*>30qx?euIoKYV8uSrbVuX;KB~UnQ#KvGL+w`BNcSS1 z;U~2{1T}vKDOh?GjZqA^@8P+OEsh={qVYmQ$vY&4jYp=IpNGGesr;aBWx6o41JoSQ z(}BH4cv2?sB~?BFm6;E1bvk7aC#n*P%Oi?dG5L^1-hlm5(P&r2+cnG+!{_XV`;L8< zl|p)Pedy^d3gl4Zq{eg%;hsN&VW1 z*YjjpggMwY-|~3Adr8jW^cl@Ov{4xMvHHP;dHlW{U@^uuI}B#!zEBT+oebadmu;(T zo?I5REG^zcKLB?tC^&z^j$_l$2Lu>djULQa(#{(k8C0@jcH@Y5plQC>XSdZR<%2Fn zC1CnY9?x1zI@i^uFuX5uMtLaq!#%??TkQR2I!ifI;x}j8 zfr`BP^Q6sA8vDu}yITqBe`9jn(s4p+U@XAi4YXGwT!~ej6K_%!Fo)U1FJx5?IX7s? znI|z&$~=$$T+LNGw@LY9(K6|S?R%;K9(2@!slJPxmJQWG-*CpPI!DGkfnTM3=U`@k zo*N7*koGrw`pli4^pJpjgSMLFVm&}>!aSM4cPn7hzsL14QkK>UK(EW*q=T~B>6G2r z3kc0PU=Gmf_i1!^$IwY;XsZc*z39uQZd1T0?3v{XK|jR#Tw@inoudHrzw!~8x`ZUL zP>9mhb4GJ95$7l35USY0dK*R}JR4u>ysHdTTaV{r`q%*N4gv7}Dp8PMMD8}ve;U>< zz?5tAj*Jp>e1)7Dm#5|^+uIQ)R zX62|+|J^j_h#O};zES66?fadp5IKr-?2tmw=@pHfATcp)iM6Rfhw?q^hF;g%B>Ngy zio;8u$*OB7`R;LZ8jGhZ+?gbNu(sYscLxZv$G)#thMhWlfXW2Q$W_rJ(Q!NDXH0+x zQ3s->rPUy=JY3Vfy|$uMz(uPW}@g0hNlv$ z8ijAn!zVyZm6Y}Z3dOh3D#DU@xDFGReL@V#ku=QZMao^QT&DAIy!9xSy^UP-`SW&!tYS7JG zFuK6m-6-0VSp-+>X2;maXQ{4IlvcA2;7P8*nSegnv|P;nf$F9NvbhM?*;a6o)S^Gb z(#qjN-*PB$lw~&sFU;|DeLP1Jbw(%3@f$Qif%2~O;`X-ZWzTE(*kP+j%s0<2)Gc{o zZK-afhs+SDT!8Ina4zgiAp9*+$_7H7)cTEKJW8+e^gJKxMz$6cypGY^89fs|HazKi z9n3p~+HR|@$_yMOa9sUnF;{1K)uoFj5JlS{O;LE*{bHusUdI3Tf@H8^QTqikAog%~ zKpdW@gb&u4i17=8{|9yEsYL~NCnUb3#Jq@Qp#7zhik~?7U0OP-<_c7yiHiuw$`g5h z4Dk+W4~Sojj=p;}luTuL6Lg+6F>9i|YRt#X8cuo(eUrk>Z>~;aJ7ZEaCnWA`MdBc) zfcc&Z3TO&v%@gFl5^ijq;B^ zvz8RN(2l6Y91W9g(>MrZChD2F_&#rCv~!t_YmXK2dn;Sfp`KiR*b4t{fjQf3Q%`r#62E zj5SJx>6Fh)rVp`o2&;!MR!DuBI_q1wKrBVwev-|v@UfT;AjKp)rCR(I^k*jgDeg(( zdIc?W4ny#lvCc_WrNwMjR|zJNNMLrso)T%|FFxc4pSXieYJ+Job9`0RJB;*H!b0G7 zyjcJul}ATXgRQD@Yuqc@Nx`3oT8^GKT7Y2wB1^J~i?05JS~|{5gv0O!nY8;jhq0iY zVPoNDo!<0;UZgQ{97H7O8$7r_f}$GyC*2ad(Cb5O_SsS6e2xlbCFI@169mKacNBKf zncO?#D0m>Z?KHU#0TyrHUQLXd?I=E6L`*jy4f(hrAVIealGr`&NqObgCPsaV$ z8;05!V_^4BID!xGSMV_+$cnGE^*&HvV`wNmYWa_4B{2+)8oakTZumHz++1AiUv>v2 z#nF>*L#C+#6)*VlrjjSHLTcbM41+%nJ9?1D{^dNxjG)t8k0`ncWIu@OM^XynqfH0G z=WwG`Md9|NH0e)Y7u}|NWi1mh^%BJSW&Nd4yG7L! zA@u}#ogp?Nh4ArWVO%kyr}loh$H1|nzQ_RWz(EfYHvCCq4=quN)z(Gd%sNZ1qRFGv z^hc>BnG`qrT+|>4Uw)fXDcX!5DHZN5M4oHh9*!Q7CqcvjL}A1_)JxPVR25u2+)p?i^lS|4 zjQzB!bd8Ey${wkDsmttcR2Kpl#CSw_%6N}-o^&?yFDaL)RVk|sp31*snxmUTn+rX1 zuLX`#W=*Z`t%|L_j&!B*r;5=rQZLcp$!;nKg+9Uml|yqxGeC1j^F_la5N8H5Q>wdb z2p1WZcd5uoTc?ikYU3_oEdZ)=wYDl{Dm^PsHT{bw%L~eaR3K8cGL})_vJVJrMQa6D zNmp~5gOA&f#-}&RAC)+jT~aqW16dJJ!<{1SBRwNC-+@s#0J0xpc8U*({ev?ecGPiyM}y+{LPI^Pz?Ji3a8#5efn?b(KWc-fBU|^ znzO>c4x)cqC;rQm)MvF;V?w20k|d9a4=;gCLFjI~FAkIXegCKr4lG7?rbLS=Ln@|L z3$L)>=Fje6xLl#+7Nq=-S)MTw-AEsaotO9R?|`NzO}OzLB(ed{M5IYv+ZmE2)-yjn z2;LdNB6l201nn}Usb78XPvsv(=a!oOv=Mt%G*z0SZdP*I7d0QUxQDKO-T~4G=ztAc z@B5-Vu`Zg*ttfNbRp&NiZ?^jV+^pKthCKh^v*imA8R6#*MAthXKqK*C3<_ro+!3&|sV3VO#qfx35<~sF#wVm#wXr zv7ndFub0-Mm+PsQd81c|xtyG^oTa>+{`$UVUrwz(!b9^**P7>RzFx_3TK;;vTtKm$ zGI}yV@QugpOa4lP@k+wRO1RicT=z;;;7ZanAOryr9S->N5fBdngwX{r(}c7_!*5CkfA>g#46{`oCAdW=8fv-O$1Et7)?S0IJTuYb}cw|G&rE{b=#ln zcJ1qS4CYi+WlZDI*ue}(LFN#t^cb$&^Ceg#i;iA!~bT6jrXc!gwoNoab7xphgg zb%h{ti7#=5-h273_iFgwj`wgXy8!hHIC13FsTn2m{qdX#eajU}YW!4kITQvWO?tT;Vf8g(x{~xTU8MmMO%erSx?CP6!SO0-5{u$k4 zCf4#NV_{_?ECrJF}4UgOzZ`I+?ZFg9Uc||hEIS~1iw|&Yk-GO)NhbQ mX4Rtsthis.$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('