on master help sign in
Merge branch 'master' into fix-engine-spotify
36e72a4Markus Heiser
.dir-locals.elnew file+133
@@ -0,0 +1,133 @@
1+;;; .dir-locals.el
2+;;
3+;; If you get ``*** EPC Error ***`` (even after a jedi:install-server) in your
4+;; emacs session, mostly you have jedi-mode enabled but the python enviroment is
5+;; missed. The python environment has to be next to the
6+;; ``<repo>/.dir-locals.el`` in::
7+;;
8+;; ./local/py3
9+;;
10+;; In Emacs, some buffer locals are referencing the project environment:
11+;;
12+;; - prj-root --> <repo>/
13+;; - python-environment-directory --> <repo>/local
14+;; - python-environment-default-root-name --> py3
15+;; - python-shell-virtualenv-root --> <repo>/local/py3
16+;; When this variable is set with the path of the virtualenv to use,
17+;; `process-environment' and `exec-path' get proper values in order to run
18+;; shells inside the specified virtualenv, example::
19+;; (setq python-shell-virtualenv-root "/path/to/env/")
20+;;
21+;; To setup such an environment build target 'pyenv' or 'pyenvinstall'::
22+;;
23+;; $ make pyenvinstall
24+;;
25+;; Alternatively create the virtualenv, source it and install jedi + epc
26+;; (required by `emacs-jedi <https://tkf.github.io/emacs-jedi>`_)::
27+;;
28+;; $ virtualenv --python=python3 "--no-site-packages" ./local/py3
29+;; ...
30+;; $ source ./local/py3/bin/activate
31+;; (py3)$ # now install into the activated 'py3' environment ..
32+;; (py3)$ pip install jedi epc
33+;; ...
34+;;
35+;; Here is what also I found useful to add to my .emacs::
36+;;
37+;; (global-set-key [f6] 'flycheck-mode)
38+;; (add-hook 'python-mode-hook 'my:python-mode-hook)
39+;;
40+;; (defun my:python-mode-hook ()
41+;; (add-to-list 'company-backends 'company-jedi)
42+;; (require 'jedi-core)
43+;; (jedi:setup)
44+;; (define-key python-mode-map (kbd "C-c C-d") 'jedi:show-doc)
45+;; (define-key python-mode-map (kbd "M-.") 'jedi:goto-definition)
46+;; (define-key python-mode-map (kbd "M-,") 'jedi:goto-definition-pop-marker)
47+;; )
48+;;
49+
50+((nil
51+ . ((fill-column . 80)
52+ ))
53+ (python-mode
54+ . ((indent-tabs-mode . nil)
55+
56+ ;; project root folder is where the `.dir-locals.el' is located
57+ (eval . (setq-local
58+ prj-root (locate-dominating-file default-directory ".dir-locals.el")))
59+
60+ (eval . (setq-local
61+ python-environment-directory (expand-file-name "./local" prj-root)))
62+
63+ ;; use 'py3' enviroment as default
64+ (eval . (setq-local
65+ python-environment-default-root-name "py3"))
66+
67+ (eval . (setq-local
68+ python-shell-virtualenv-root
69+ (concat python-environment-directory
70+ "/"
71+ python-environment-default-root-name)))
72+
73+ ;; python-shell-virtualenv-path is obsolete, use python-shell-virtualenv-root!
74+ ;; (eval . (setq-local
75+ ;; python-shell-virtualenv-path python-shell-virtualenv-root))
76+
77+ (eval . (setq-local
78+ python-shell-interpreter
79+ (expand-file-name "bin/python" python-shell-virtualenv-root)))
80+
81+ (eval . (setq-local
82+ python-environment-virtualenv
83+ (list (expand-file-name "bin/virtualenv" python-shell-virtualenv-root)
84+ ;;"--system-site-packages"
85+ "--quiet")))
86+
87+ (eval . (setq-local
88+ pylint-command
89+ (expand-file-name "bin/pylint" python-shell-virtualenv-root)))
90+
91+ ;; pylint will find the '.pylintrc' file next to the CWD
92+ ;; https://pylint.readthedocs.io/en/latest/user_guide/run.html#command-line-options
93+ (eval . (setq-local
94+ flycheck-pylintrc ".pylintrc"))
95+
96+ ;; flycheck & other python stuff should use the local py3 environment
97+ (eval . (setq-local
98+ flycheck-python-pylint-executable python-shell-interpreter))
99+
100+ ;; use 'M-x jedi:show-setup-info' and 'M-x epc:controller' to inspect jedi server
101+
102+ ;; https://tkf.github.io/emacs-jedi/latest/#jedi:environment-root -- You
103+ ;; can specify a full path instead of a name (relative path). In that case,
104+ ;; python-environment-directory is ignored and Python virtual environment
105+ ;; is created at the specified path.
106+ (eval . (setq-local jedi:environment-root python-shell-virtualenv-root))
107+
108+ ;; https://tkf.github.io/emacs-jedi/latest/#jedi:server-command
109+ (eval .(setq-local
110+ jedi:server-command
111+ (list python-shell-interpreter
112+ jedi:server-script)
113+ ))
114+
115+ ;; jedi:environment-virtualenv --> see above 'python-environment-virtualenv'
116+ ;; is set buffer local! No need to setup jedi:environment-virtualenv:
117+ ;;
118+ ;; Virtualenv command to use. A list of string. If it is nil,
119+ ;; python-environment-virtualenv is used instead. You must set non-nil
120+ ;; value to jedi:environment-root in order to make this setting work.
121+ ;;
122+ ;; https://tkf.github.io/emacs-jedi/latest/#jedi:environment-virtualenv
123+ ;;
124+ ;; (eval . (setq-local
125+ ;; jedi:environment-virtualenv
126+ ;; (list (expand-file-name "bin/virtualenv" python-shell-virtualenv-root)
127+ ;; ;;"--python"
128+ ;; ;;"/usr/bin/python3.4"
129+ ;; )))
130+
131+ ;; jedi:server-args
132+
133+ )))
.gitignore+6
@@ -18,3 +18,9 @@ setup.cfg
18node_modules/
18node_modules/
19
19
20.tx/
20.tx/
21+
22+build/
23+dist/
24+local/
25+gh-pages/
26+searx.egg-info/
.pylintrcnew file+444
@@ -0,0 +1,444 @@
1+# -*- coding: utf-8; mode: conf -*-
2+# lint Python modules using external checkers.
3+#
4+# This is the main checker controlling the other ones and the reports
5+# generation. It is itself both a raw checker and an astng checker in order
6+# to:
7+# * handle message activation / deactivation at the module level
8+# * handle some basic but necessary stats'data (number of classes, methods...)
9+#
10+[MASTER]
11+
12+# A comma-separated list of package or module names from where C extensions may
13+# be loaded. Extensions are loading into the active Python interpreter and may
14+# run arbitrary code
15+extension-pkg-whitelist=
16+
17+# Add files or directories to the blacklist. They should be base names, not
18+# paths.
19+ignore=CVS, .git, .svn
20+
21+# Add files or directories matching the regex patterns to the blacklist. The
22+# regex matches against base names, not paths.
23+ignore-patterns=
24+
25+# Python code to execute, usually for sys.path manipulation such as
26+# pygtk.require().
27+#init-hook=
28+
29+# Use multiple processes to speed up Pylint.
30+jobs=1
31+
32+# List of plugins (as comma separated values of python modules names) to load,
33+# usually to register additional checkers.
34+load-plugins=
35+
36+# Pickle collected data for later comparisons.
37+persistent=yes
38+
39+# Specify a configuration file.
40+#rcfile=
41+
42+# Allow loading of arbitrary C extensions. Extensions are imported into the
43+# active Python interpreter and may run arbitrary code.
44+unsafe-load-any-extension=no
45+
46+
47+[MESSAGES CONTROL]
48+
49+# Only show warnings with the listed confidence levels. Leave empty to show
50+# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
51+confidence=
52+
53+# Disable the message, report, category or checker with the given id(s). You
54+# can either give multiple identifiers separated by comma (,) or put this
55+# option multiple times (only on the command line, not in the configuration
56+# file where it should appear only once).You can also use "--disable=all" to
57+# disable everything first and then reenable specific checks. For example, if
58+# you want to run only the similarities checker, you can use "--disable=all
59+# --enable=similarities". If you want to run only the classes checker, but have
60+# no Warning level messages displayed, use"--disable=all --enable=classes
61+# --disable=W"
62+disable=bad-whitespace, duplicate-code
63+
64+# Enable the message, report, category or checker with the given id(s). You can
65+# either give multiple identifier separated by comma (,) or put this option
66+# multiple time (only on the command line, not in the configuration file where
67+# it should appear only once). See also the "--disable" option for examples.
68+enable=
69+
70+
71+[REPORTS]
72+
73+# Python expression which should return a note less than 10 (10 is the highest
74+# note). You have access to the variables errors warning, statement which
75+# respectively contain the number of errors / warnings messages and the total
76+# number of statements analyzed. This is used by the global evaluation report
77+# (RP0004).
78+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
79+
80+# Template used to display messages. This is a python new-style format string
81+# used to format the message information. See doc for all details
82+
83+# HINT: do not set this here, use argument --msg-template=...
84+#msg-template={path}:{line}: [{msg_id}({symbol}),{obj}] {msg}
85+
86+# Set the output format. Available formats are text, parseable, colorized, json
87+# and msvs (visual studio).You can also give a reporter class, eg
88+# mypackage.mymodule.MyReporterClass.
89+
90+# HINT: do not set this here, use argument --output-format=...
91+#output-format=text
92+
93+# Tells whether to display a full report or only the messages
94+reports=no
95+
96+# Activate the evaluation score.
97+score=yes
98+
99+
100+[REFACTORING]
101+
102+# Maximum number of nested blocks for function / method body
103+max-nested-blocks=5
104+
105+
106+[BASIC]
107+
108+# List of builtins function names that should not be used, separated by a comma
109+bad-functions=map,filter,apply,input
110+
111+# Naming hint for argument names
112+argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
113+
114+# Regular expression matching correct argument names
115+argument-rgx=(([a-z][a-zA-Z0-9_]{2,30})|(_[a-z0-9_]*))$
116+
117+# Naming hint for attribute names
118+attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
119+
120+# Regular expression matching correct attribute names
121+attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*)|([A-Z0-9_]*))$
122+
123+# Bad variable names which should always be refused, separated by a comma
124+bad-names=foo,bar,baz,toto,tutu,tata
125+
126+# Naming hint for class attribute names
127+class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
128+
129+# Regular expression matching correct class attribute names
130+class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
131+
132+# Naming hint for class names
133+class-name-hint=[A-Z_][a-zA-Z0-9]+$
134+
135+# Regular expression matching correct class names
136+class-rgx=[A-Z_][a-zA-Z0-9]+$
137+
138+# Naming hint for constant names
139+const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
140+
141+# Regular expression matching correct constant names
142+const-rgx=(([a-zA-Z_][a-zA-Z0-9_]*)|(__.*__))$
143+#const-rgx=[f]?[A-Z_][a-zA-Z0-9_]{2,30}$
144+
145+# Minimum line length for functions/classes that require docstrings, shorter
146+# ones are exempt.
147+docstring-min-length=-1
148+
149+# Naming hint for function names
150+function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
151+
152+# Regular expression matching correct function names
153+function-rgx=(([a-z][a-zA-Z0-9_]{2,30})|(_[a-z0-9_]*))$
154+
155+# Good variable names which should always be accepted, separated by a comma
156+good-names=i,j,k,ex,Run,_,log,cfg,id
157+
158+# Include a hint for the correct naming format with invalid-name
159+include-naming-hint=no
160+
161+# Naming hint for inline iteration names
162+inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
163+
164+# Regular expression matching correct inline iteration names
165+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
166+
167+# Naming hint for method names
168+method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
169+
170+# Regular expression matching correct method names
171+method-rgx=(([a-z][a-zA-Z0-9_]{2,30})|(_[a-z0-9_]*))$
172+
173+# Naming hint for module names
174+module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
175+
176+# Regular expression matching correct module names
177+#module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
178+module-rgx=([a-z_][a-z0-9_]*)$
179+
180+# Colon-delimited sets of names that determine each other's naming style when
181+# the name regexes allow several styles.
182+name-group=
183+
184+# Regular expression which should only match function or class names that do
185+# not require a docstring.
186+no-docstring-rgx=^_
187+
188+# List of decorators that produce properties, such as abc.abstractproperty. Add
189+# to this list to register other decorators that produce valid properties.
190+property-classes=abc.abstractproperty
191+
192+# Naming hint for variable names
193+variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
194+
195+# Regular expression matching correct variable names
196+variable-rgx=(([a-z][a-zA-Z0-9_]{2,30})|(_[a-z0-9_]*)|([a-z]))$
197+
198+
199+[FORMAT]
200+
201+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
202+expected-line-ending-format=
203+
204+# Regexp for a line that is allowed to be longer than the limit.
205+ignore-long-lines=^\s*(# )?<?https?://\S+>?$
206+
207+# Number of spaces of indent required inside a hanging or continued line.
208+indent-after-paren=4
209+
210+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
211+# tab).
212+indent-string=' '
213+
214+# Maximum number of characters on a single line.
215+max-line-length=120
216+
217+# Maximum number of lines in a module
218+max-module-lines=2000
219+
220+# List of optional constructs for which whitespace checking is disabled. `dict-
221+# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
222+# `trailing-comma` allows a space between comma and closing bracket: (a, ).
223+# `empty-line` allows space-only lines.
224+no-space-check=trailing-comma,dict-separator
225+
226+# Allow the body of a class to be on the same line as the declaration if body
227+# contains single statement.No config file found, using default configuration
228+
229+single-line-class-stmt=no
230+
231+# Allow the body of an if to be on the same line as the test if there is no
232+# else.
233+single-line-if-stmt=no
234+
235+
236+[LOGGING]
237+
238+# Logging modules to check that the string format arguments are in logging
239+# function parameter format
240+logging-modules=logging
241+
242+
243+[MISCELLANEOUS]
244+
245+# List of note tags to take in consideration, separated by a comma.
246+notes=FIXME,XXX,TODO
247+
248+
249+[SIMILARITIES]
250+
251+# Ignore comments when computing similarities.
252+ignore-comments=yes
253+
254+# Ignore docstrings when computing similarities.
255+ignore-docstrings=yes
256+
257+# Ignore imports when computing similarities.
258+ignore-imports=no
259+
260+# Minimum lines number of a similarity.
261+min-similarity-lines=4
262+
263+
264+[SPELLING]
265+
266+# Spelling dictionary name. Available dictionaries: none. To make it working
267+# install python-enchant package.
268+spelling-dict=
269+
270+# List of comma separated words that should not be checked.
271+spelling-ignore-words=
272+
273+# A path to a file that contains private dictionary; one word per line.
274+spelling-private-dict-file=
275+
276+# Tells whether to store unknown words to indicated private dictionary in
277+# --spelling-private-dict-file option instead of raising a message.
278+spelling-store-unknown-words=no
279+
280+
281+[TYPECHECK]
282+
283+# List of decorators that produce context managers, such as
284+# contextlib.contextmanager. Add to this list to register other decorators that
285+# produce valid context managers.
286+contextmanager-decorators=contextlib.contextmanager
287+
288+# List of members which are set dynamically and missed by pylint inference
289+# system, and so shouldn't trigger E1101 when accessed. Python regular
290+# expressions are accepted.
291+generated-members=
292+
293+# Tells whether missing members accessed in mixin class should be ignored. A
294+# mixin class is detected if its name ends with "mixin" (case insensitive).
295+ignore-mixin-members=yes
296+
297+# This flag controls whether pylint should warn about no-member and similar
298+# checks whenever an opaque object is returned when inferring. The inference
299+# can return multiple potential results while evaluating a Python object, but
300+# some branches might not be evaluated, which results in partial inference. In
301+# that case, it might be useful to still emit no-member and other checks for
302+# the rest of the inferred objects.
303+ignore-on-opaque-inference=yes
304+
305+# List of class names for which member attributes should not be checked (useful
306+# for classes with dynamically set attributes). This supports the use of
307+# qualified names.
308+ignored-classes=optparse.Values,thread._local,_thread._local
309+
310+# List of module names for which member attributes should not be checked
311+# (useful for modules/projects where namespaces are manipulated during runtime
312+# and thus existing member attributes cannot be deduced by static analysis. It
313+# supports qualified module names, as well as Unix pattern matching.
314+ignored-modules=
315+
316+# Show a hint with possible names when a member name was not found. The aspect
317+# of finding the hint is based on edit distance.
318+missing-member-hint=yes
319+
320+# The minimum edit distance a name should have in order to be considered a
321+# similar match for a missing member name.
322+missing-member-hint-distance=1
323+
324+# The total number of similar names that should be taken in consideration when
325+# showing a hint for a missing member.
326+missing-member-max-choices=1
327+
328+
329+[VARIABLES]
330+
331+# List of additional names supposed to be defined in builtins. Remember that
332+# you should avoid to define new builtins when possible.
333+additional-builtins=
334+
335+# Tells whether unused global variables should be treated as a violation.
336+allow-global-unused-variables=yes
337+
338+# List of strings which can identify a callback function by name. A callback
339+# name must start or end with one of those strings.
340+callbacks=cb_,_cb
341+
342+# A regular expression matching the name of dummy variables (i.e. expectedly
343+# not used).
344+dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
345+
346+# Argument names that match this expression will be ignored. Default to name
347+# with leading underscore
348+ignored-argument-names=_.*|^ignored_|^unused_
349+
350+# Tells whether we should check for unused import in __init__ files.
351+init-import=no
352+
353+# List of qualified module names which can have objects that can redefine
354+# builtins.
355+redefining-builtins-modules=six.moves,future.builtins
356+
357+
358+[CLASSES]
359+
360+# List of method names used to declare (i.e. assign) instance attributes.
361+defining-attr-methods=__init__,__new__,setUp
362+
363+# List of member names, which should be excluded from the protected access
364+# warning.
365+exclude-protected=_asdict,_fields,_replace,_source,_make
366+
367+# List of valid names for the first argument in a class method.
368+valid-classmethod-first-arg=cls
369+
370+# List of valid names for the first argument in a metaclass class method.
371+valid-metaclass-classmethod-first-arg=mcs
372+
373+
374+[DESIGN]
375+
376+# Maximum number of arguments for function / method
377+max-args=8
378+
379+# Maximum number of attributes for a class (see R0902).
380+max-attributes=20
381+
382+# Maximum number of boolean expressions in a if statement
383+max-bool-expr=5
384+
385+# Maximum number of branch for function / method body
386+max-branches=12
387+
388+# Maximum number of locals for function / method body
389+max-locals=20
390+
391+# Maximum number of parents for a class (see R0901).
392+max-parents=7
393+
394+# Maximum number of public methods for a class (see R0904).
395+max-public-methods=20
396+
397+# Maximum number of return / yield for function / method body
398+max-returns=6
399+
400+# Maximum number of statements in function / method body
401+max-statements=50
402+
403+# Minimum number of public methods for a class (see R0903).
404+min-public-methods=2
405+
406+
407+[IMPORTS]
408+
409+# Allow wildcard imports from modules that define __all__.
410+allow-wildcard-with-all=no
411+
412+# Analyse import fallback blocks. This can be used to support both Python 2 and
413+# 3 compatible code, which means that the block might have code that exists
414+# only in one or another interpreter, leading to false positives when analysed.
415+analyse-fallback-blocks=no
416+
417+# Deprecated modules which should not be used, separated by a comma
418+deprecated-modules=optparse,tkinter.tix
419+
420+# Create a graph of external dependencies in the given file (report RP0402 must
421+# not be disabled)
422+ext-import-graph=
423+
424+# Create a graph of every (i.e. internal and external) dependencies in the
425+# given file (report RP0402 must not be disabled)
426+import-graph=
427+
428+# Create a graph of internal dependencies in the given file (report RP0402 must
429+# not be disabled)
430+int-import-graph=
431+
432+# Force import order to recognize a module as part of the standard
433+# compatibility libraries.
434+known-standard-library=
435+
436+# Force import order to recognize a module as part of a third party library.
437+known-third-party=enchant
438+
439+
440+[EXCEPTIONS]
441+
442+# Exceptions that will emit a warning when being caught. Defaults to
443+# "Exception"
444+overgeneral-exceptions=Exception
AUTHORS.rst+3−1
@@ -1,4 +1,4 @@
1−Searx was created by Adam Tauber and is maintained by Adam Tauber, Alexandre Flament and Noémi Ványi.
1+Searx was created by Adam Tauber and is maintained by Adam Tauber, Alexandre Flament, Noémi Ványi, @pofilo and Markus Heiser.
2
2
3Major contributing authors:
3Major contributing authors:
4
4
@@ -9,6 +9,8 @@ Major contributing authors:
9- @Cqoicebordel
9- @Cqoicebordel
10- Noémi Ványi
10- Noémi Ványi
11- Marc Abonce Seguin @a01200356
11- Marc Abonce Seguin @a01200356
12+- @pofilo
13+- Markus Heiser @return42
12
14
13People who have submitted patches/translates, reported bugs, consulted features or
15People who have submitted patches/translates, reported bugs, consulted features or
14generally made searx better:
16generally made searx better:
Dockerfile+19−17
@@ -1,32 +1,36 @@
1FROM alpine:3.10
1FROM alpine:3.10
2+ENTRYPOINT ["/sbin/tini","--","/usr/local/searx/dockerfiles/docker-entrypoint.sh"]
3+EXPOSE 8080
4+VOLUME /etc/searx
5+VOLUME /var/log/uwsgi
2
6
3−ARG VERSION_GITCOMMIT=unknow
7+ARG VERSION_GITCOMMIT=unknown
4−ARG SEARX_GIT_VERSION=unknow
8+ARG SEARX_GIT_VERSION=unknown
5
9
6−ARG SEARX_GID=1000
10+ARG SEARX_GID=977
7−ARG SEARX_UID=1000
11+ARG SEARX_UID=977
12+
13+RUN addgroup -g ${SEARX_GID} searx && \
14+ adduser -u ${SEARX_UID} -D -h /usr/local/searx -s /bin/sh -G searx searx
8
15
9ARG TIMESTAMP_SETTINGS=0
16ARG TIMESTAMP_SETTINGS=0
10ARG TIMESTAMP_UWSGI=0
17ARG TIMESTAMP_UWSGI=0
11ARG LABEL_VCS_REF=
18ARG LABEL_VCS_REF=
12ARG LABEL_VCS_URL=
19ARG LABEL_VCS_URL=
13
20
21+ENV INSTANCE_NAME=searx \
22+ AUTOCOMPLETE= \
14−ENV BASE_URL= \
23+ BASE_URL= \
15 MORTY_KEY= \
24 MORTY_KEY= \
16 MORTY_URL=
25 MORTY_URL=
17−EXPOSE 8080
18−VOLUME /etc/searx
19−VOLUME /var/log/uwsgi
20
26
21WORKDIR /usr/local/searx
27WORKDIR /usr/local/searx
22
28
23−RUN addgroup -g ${SEARX_GID} searx && \
24− adduser -u ${SEARX_UID} -D -h /usr/local/searx -s /bin/sh -G searx searx
25
29
26COPY requirements.txt ./requirements.txt
30COPY requirements.txt ./requirements.txt
27
31
28−RUN apk -U upgrade \
32+RUN apk upgrade --no-cache \
29− && apk add -t build-dependencies \
33+ && apk add --no-cache -t build-dependencies \
30 build-base \
34 build-base \
31 py3-setuptools \
35 py3-setuptools \
32 python3-dev \
36 python3-dev \
@@ -36,7 +40,7 @@ RUN apk -U upgrade \
36 openssl-dev \
40 openssl-dev \
37 tar \
41 tar \
38 git \
42 git \
39− && apk add \
43+ && apk add --no-cache \
40 ca-certificates \
44 ca-certificates \
41 su-exec \
45 su-exec \
42 python3 \
46 python3 \
@@ -48,8 +52,7 @@ RUN apk -U upgrade \
48 uwsgi-python3 \
52 uwsgi-python3 \
49 && pip3 install --upgrade pip \
53 && pip3 install --upgrade pip \
50 && pip3 install --no-cache -r requirements.txt \
54 && pip3 install --no-cache -r requirements.txt \
51− && apk del build-dependencies \
55+ && apk del build-dependencies
52− && rm -f /var/cache/apk/*
53
56
54COPY --chown=searx:searx . .
57COPY --chown=searx:searx . .
55
58
@@ -60,7 +63,6 @@ RUN su searx -c "/usr/bin/python3 -m compileall -q searx"; \
60 echo "VERSION_STRING = VERSION_STRING + \"-$VERSION_GITCOMMIT\"" >> /usr/local/searx/searx/version.py; \
63 echo "VERSION_STRING = VERSION_STRING + \"-$VERSION_GITCOMMIT\"" >> /usr/local/searx/searx/version.py; \
61 fi
64 fi
62
65
63−ENTRYPOINT ["/sbin/tini","--","/usr/local/searx/dockerfiles/docker-entrypoint.sh"]
64
66
65# Keep this argument at the end since it change each time
67# Keep this argument at the end since it change each time
66ARG LABEL_DATE=
68ARG LABEL_DATE=
@@ -69,7 +71,7 @@ LABEL maintainer="searx <https://github.com/asciimoo/searx>" \
69 version="${SEARX_GIT_VERSION}" \
71 version="${SEARX_GIT_VERSION}" \
70 org.label-schema.schema-version="1.0" \
72 org.label-schema.schema-version="1.0" \
71 org.label-schema.name="searx" \
73 org.label-schema.name="searx" \
72− org.label-schema.schema-version="${SEARX_GIT_VERSION}" \
74+ org.label-schema.version="${SEARX_GIT_VERSION}" \
73 org.label-schema.url="${LABEL_VCS_URL}" \
75 org.label-schema.url="${LABEL_VCS_URL}" \
74 org.label-schema.vcs-ref=${LABEL_VCS_REF} \
76 org.label-schema.vcs-ref=${LABEL_VCS_REF} \
75 org.label-schema.vcs-url=${LABEL_VCS_URL} \
77 org.label-schema.vcs-url=${LABEL_VCS_URL} \
Makefilenew file+89
@@ -0,0 +1,89 @@
1+# -*- coding: utf-8; mode: makefile-gmake -*-
2+
3+export GIT_URL=https://github.com/asciimoo/searx
4+export SEARX_URL=https://searx.me
5+export DOCS_URL=https://asciimoo.github.io/searx
6+
7+PYOBJECTS = searx
8+DOC = docs
9+PY_SETUP_EXTRAS ?= \[test\]
10+
11+PYDIST=./dist/py
12+PYBUILD=./build/py
13+
14+include utils/makefile.include
15+include utils/makefile.python
16+include utils/makefile.sphinx
17+
18+all: clean install
19+
20+PHONY += help
21+help:
22+ @echo ' test - run developer tests'
23+ @echo ' docs - build documentation'
24+ @echo ' docs-live - autobuild HTML documentation while editing'
25+ @echo ' run - run developer instance'
26+ @echo ' install - developer install (./local)'
27+ @echo ' uninstall - uninstall (./local)'
28+ @echo ' gh-pages - build docs & deploy on gh-pages branch'
29+ @echo ' clean - drop builds and environments'
30+ @echo ''
31+ @$(MAKE) -s -f utils/makefile.include make-help
32+ @echo ''
33+ @$(MAKE) -s -f utils/makefile.python python-help
34+
35+PHONY += install
36+install: pyenvinstall
37+
38+PHONY += uninstall
39+uninstall: pyenvuninstall
40+
41+PHONY += clean
42+clean: pyclean
43+ $(call cmd,common_clean)
44+
45+PHONY += run
46+run: pyenvinstall
47+ $(Q) ( \
48+ sed -i -e "s/debug : False/debug : True/g" ./searx/settings.yml ; \
49+ sleep 2 ; \
50+ xdg-open http://127.0.0.1:8888/ ; \
51+ sleep 3 ; \
52+ sed -i -e "s/debug : True/debug : False/g" ./searx/settings.yml ; \
53+ ) &
54+ $(PY_ENV)/bin/python ./searx/webapp.py
55+
56+# docs
57+# ----
58+
59+PHONY += docs
60+docs: pyenvinstall sphinx-doc
61+ $(call cmd,sphinx,html,docs,docs)
62+
63+PHONY += docs-live
64+docs-live: pyenvinstall sphinx-live
65+ $(call cmd,sphinx_autobuild,html,docs,docs)
66+
67+$(GH_PAGES)::
68+ @echo "doc available at --> $(DOCS_URL)"
69+
70+# test
71+# ----
72+
73+PHONY += test test.pylint test.pep8 test.unit test.robot
74+
75+# TODO: balance linting with pylint
76+test: test.pep8 test.unit test.robot
77+ - make pylint
78+
79+test.pep8: pyenvinstall
80+ $(PY_ENV_ACT); ./manage.sh pep8_check
81+
82+test.unit: pyenvinstall
83+ $(PY_ENV_ACT); ./manage.sh unit_tests
84+
85+test.robot: pyenvinstall
86+ $(PY_ENV_ACT); ./manage.sh install_geckodriver
87+ $(PY_ENV_ACT); ./manage.sh robot_tests
88+
89+.PHONY: $(PHONY)
README.rst+3−3
@@ -23,13 +23,13 @@ Go to the `searx-docker <https://github.com/searx/searx-docker>`__ project.
23
23
24Without Docker
24Without Docker
25------
25------
26−For all the details, follow this `step by step installation <https://asciimoo.github.io/searx/dev/install/installation.html>`__.
26+For all of the details, follow this `step by step installation <https://asciimoo.github.io/searx/dev/install/installation.html>`__.
27
27
28Note: the documentation needs to be updated.
28Note: the documentation needs to be updated.
29
29
30−If you are in hurry
30+If you are in a hurry
31------
31------
32−- clone source:
32+- clone the source:
33 ``git clone https://github.com/asciimoo/searx.git && cd searx``
33 ``git clone https://github.com/asciimoo/searx.git && cd searx``
34- install dependencies: ``./manage.sh update_packages``
34- install dependencies: ``./manage.sh update_packages``
35- edit your
35- edit your
dockerfiles/docker-entrypoint.sh+7−3
@@ -29,6 +29,8 @@ do
29 printf " -f Always update on the configuration files (existing files are renamed with the .old suffix)\n"
29 printf " -f Always update on the configuration files (existing files are renamed with the .old suffix)\n"
30 printf " Without this option, new configuration files are copied with the .new suffix\n"
30 printf " Without this option, new configuration files are copied with the .new suffix\n"
31 printf "\nEnvironment variables:\n\n"
31 printf "\nEnvironment variables:\n\n"
32+ printf " INSTANCE_NAME settings.yml : general.instance_name\n"
33+ printf " AUTOCOMPLETE settings.yml : search.autocomplete\n"
32 printf " BASE_URL settings.yml : server.base_url\n"
34 printf " BASE_URL settings.yml : server.base_url\n"
33 printf " MORTY_URL settings.yml : result_proxy.url\n"
35 printf " MORTY_URL settings.yml : result_proxy.url\n"
34 printf " MORTY_KEY settings.yml : result_proxy.key\n"
36 printf " MORTY_KEY settings.yml : result_proxy.key\n"
@@ -53,6 +55,8 @@ patch_searx_settings() {
53
55
54 # update settings.yml
56 # update settings.yml
55 sed -i -e "s|base_url : False|base_url : ${BASE_URL}|g" \
57 sed -i -e "s|base_url : False|base_url : ${BASE_URL}|g" \
58+ -e "s/instance_name : \"searx\"/instance_name : \"${INSTANCE_NAME}\"/g" \
59+ -e "s/autocomplete : \"\"/autocomplete : \"${AUTOCOMPLETE}\"/g" \
56 -e "s/ultrasecretkey/$(openssl rand -hex 32)/g" \
60 -e "s/ultrasecretkey/$(openssl rand -hex 32)/g" \
57 "${CONF}"
61 "${CONF}"
58
62
@@ -71,7 +75,7 @@ EOF
71}
75}
72
76
73update_conf() {
77update_conf() {
74− FORCE_CONF_UPDATE="$1"
78+ FORCE_CONF_UPDATE=$1
75 CONF="$2"
79 CONF="$2"
76 NEW_CONF="${2}.new"
80 NEW_CONF="${2}.new"
77 OLD_CONF="${2}.old"
81 OLD_CONF="${2}.old"
@@ -81,7 +85,7 @@ update_conf() {
81 if [ -f "${CONF}" ]; then
85 if [ -f "${CONF}" ]; then
82 if [ "${REF_CONF}" -nt "${CONF}" ]; then
86 if [ "${REF_CONF}" -nt "${CONF}" ]; then
83 # There is a new version
87 # There is a new version
84− if [ $FORCE_CONF_UPDATE ]; then
88+ if [ $FORCE_CONF_UPDATE -ne 0 ]; then
85 # Replace the current configuration
89 # Replace the current configuration
86 printf '⚠️ Automaticaly update %s to the new version\n' "${CONF}"
90 printf '⚠️ Automaticaly update %s to the new version\n' "${CONF}"
87 if [ ! -f "${OLD_CONF}" ]; then
91 if [ ! -f "${OLD_CONF}" ]; then
@@ -107,7 +111,7 @@ update_conf() {
107}
111}
108
112
109# make sure there are uwsgi settings
113# make sure there are uwsgi settings
110−update_conf "${FORCE_CONF_UPDATE}" "${UWSGI_SETTINGS_PATH}" "/usr/local/searx/dockerfiles/uwsgi.ini" "patch_uwsgi_settings"
114+update_conf ${FORCE_CONF_UPDATE} "${UWSGI_SETTINGS_PATH}" "/usr/local/searx/dockerfiles/uwsgi.ini" "patch_uwsgi_settings"
111
115
112# make sure there are searx settings
116# make sure there are searx settings
113update_conf "${FORCE_CONF_UPDATE}" "${SEARX_SETTINGS_PATH}" "/usr/local/searx/searx/settings.yml" "patch_searx_settings"
117update_conf "${FORCE_CONF_UPDATE}" "${SEARX_SETTINGS_PATH}" "/usr/local/searx/searx/settings.yml" "patch_searx_settings"
docs/_themes/searx/static/searx.cssnew file+130
@@ -0,0 +1,130 @@
1+@import url("pocoo.css");
2+
3+a, a.reference, a.footnote-reference {
4+ color: #004b6b;
5+ border-color: #004b6b;
6+}
7+
8+a:hover {
9+ color: #6d4100;
10+ border-color: #6d4100;
11+}
12+
13+p.version-warning {
14+ background-color: #004b6b;
15+}
16+
17+div.sidebar {
18+ background-color: whitesmoke;
19+ border-color: lightsteelblue;
20+ border-radius: 3pt;
21+}
22+
23+p.sidebar-title, .sidebar p {
24+ margin: 6pt;
25+}
26+
27+.sidebar li,
28+.hlist li {
29+ list-style-type: disclosure-closed;
30+}
31+
32+
33+/* admonitions
34+*/
35+
36+div.admonition, div.topic {
37+ background-color: #fafafa;
38+ margin: 8px 0px;
39+ padding: 1em;
40+ border-radius: 3pt 0 0 3pt;
41+ border-top: none;
42+ border-right: none;
43+ border-bottom: none;
44+ border-left: 5pt solid #ccc;
45+}
46+
47+p.admonition-title:after {
48+ content: none;
49+}
50+
51+.admonition.hint { border-color: #416dc0b0; }
52+.admonition.note { border-color: #6c856cb0; }
53+.admonition.tip { border-color: #85c5c2b0; }
54+.admonition.attention { border-color: #ecec97b0; }
55+.admonition.caution { border-color: #a6c677b0; }
56+.admonition.danger { border-color: #d46262b0; }
57+.admonition.important { border-color: #dfa3a3b0; }
58+.admonition.error { border-color: red; }
59+.admonition.warning { border-color: darkred; }
60+
61+.admonition.admonition-generic-admonition-title {
62+ border-color: #416dc0b0;
63+}
64+
65+
66+/* admonitions with (rendered) reST markup examples (:class: rst-example)
67+ *
68+ * .. admonition:: title of the example
69+ * :class: rst-example
70+ * ....
71+*/
72+
73+div.rst-example {
74+ background-color: inherit;
75+ margin: 0;
76+ border-top: none;
77+ border-right: 1px solid #ccc;
78+ border-bottom: none;
79+ border-left: none;
80+ border-radius: none;
81+ padding: 0;
82+}
83+
84+div.rst-example > p.admonition-title {
85+ font-family: Sans Serif;
86+ font-style: italic;
87+ font-size: 0.8em;
88+ display: block;
89+ border-bottom: 1px solid #ccc;
90+ padding: 0.5em 1em;
91+ text-align: right;
92+}
93+
94+/* code block in figures
95+ */
96+
97+div.highlight pre {
98+ text-align: left;
99+}
100+
101+/* Table theme
102+*/
103+
104+thead, tfoot {
105+ background-color: #fff;
106+}
107+
108+th:hover, td:hover {
109+ background-color: #ffc;
110+}
111+
112+thead th, tfoot th, tfoot td, tbody th {
113+ background-color: #fffaef;
114+}
115+
116+tbody tr:nth-child(odd) {
117+ background-color: #fff;
118+}
119+
120+tbody tr:nth-child(even) {
121+ background-color: #fafafa;
122+}
123+
124+caption {
125+ font-family: Sans Serif;
126+ padding: 0.5em;
127+ margin: 0.5em 0 0.5em 0;
128+ caption-side: top;
129+ text-align: left;
130+}
docs/_themes/searx/theme.confnew file+6
@@ -0,0 +1,6 @@
1+[theme]
2+inherit = pocoo
3+stylesheet = searx.css
4+
5+[options]
6+touch_icon =
docs/admin/api.rstnew file+96
@@ -0,0 +1,96 @@
1+.. _adminapi:
2+
3+==================
4+Administration API
5+==================
6+
7+Get configuration data
8+======================
9+
10+.. code:: http
11+
12+ GET /config HTTP/1.1
13+
14+Sample response
15+---------------
16+
17+.. code:: json
18+
19+ {
20+ "autocomplete": "",
21+ "categories": [
22+ "map",
23+ "it",
24+ "images",
25+ ],
26+ "default_locale": "",
27+ "default_theme": "oscar",
28+ "engines": [
29+ {
30+ "categories": [
31+ "map"
32+ ],
33+ "enabled": true,
34+ "name": "openstreetmap",
35+ "shortcut": "osm"
36+ },
37+ {
38+ "categories": [
39+ "it"
40+ ],
41+ "enabled": true,
42+ "name": "arch linux wiki",
43+ "shortcut": "al"
44+ },
45+ {
46+ "categories": [
47+ "images"
48+ ],
49+ "enabled": true,
50+ "name": "google images",
51+ "shortcut": "goi"
52+ },
53+ {
54+ "categories": [
55+ "it"
56+ ],
57+ "enabled": false,
58+ "name": "bitbucket",
59+ "shortcut": "bb"
60+ },
61+ ],
62+ "instance_name": "searx",
63+ "locales": {
64+ "de": "Deutsch (German)",
65+ "en": "English",
66+ "eo": "Esperanto (Esperanto)",
67+ },
68+ "plugins": [
69+ {
70+ "enabled": true,
71+ "name": "HTTPS rewrite"
72+ },
73+ {
74+ "enabled": false,
75+ "name": "Vim-like hotkeys"
76+ }
77+ ],
78+ "safe_search": 0
79+ }
80+
81+
82+Embed search bar
83+================
84+
85+The search bar can be embedded into websites. Just paste the example into the
86+HTML of the site. URL of the searx instance and values are customizable.
87+
88+.. code:: html
89+
90+ <form method="post" action="https://searx.me/">
91+ <!-- search --> <input type="text" name="q" />
92+ <!-- categories --> <input type="hidden" name="categories" value="general,social media" />
93+ <!-- language --> <input type="hidden" name="lang" value="all" />
94+ <!-- locale --> <input type="hidden" name="locale" value="en" />
95+ <!-- date filter --> <input type="hidden" name="time_range" value="month" />
96+ </form>
docs/admin/arch_public.dotnew file+33
@@ -0,0 +1,33 @@
1+digraph G {
2+
3+ node [style=filled, shape=box, fillcolor="#ffffcc", fontname="Sans"];
4+ edge [fontname="Sans"];
5+
6+ browser [label="Browser", shape=Mdiamond];
7+ rp [label="Reverse Proxy", href="url to configure reverse proxy"];
8+ filtron [label="Filtron", href="https://github.com/asciimoo/filtron"];
9+ morty [label="Morty", href="https://github.com/asciimoo/morty"];
10+ static [label="Static files", href="url to configure static files"];
11+ uwsgi [label="uwsgi", href="url to configure uwsgi"]
12+ searx1 [label="Searx #1"];
13+ searx2 [label="Searx #2"];
14+ searx3 [label="Searx #3"];
15+ searx4 [label="Searx #4"];
16+
17+ browser -> rp [label="HTTPS"]
18+
19+ subgraph cluster_searx {
20+ label = "Searx instance" fontname="Sans";
21+ bgcolor="#fafafa";
22+ { rank=same; static rp };
23+ rp -> morty [label="optional: images and HTML pages proxy"];
24+ rp -> static [label="optional: reverse proxy serves directly static files"];
25+ rp -> filtron [label="HTTP"];
26+ filtron -> uwsgi [label="HTTP"];
27+ uwsgi -> searx1;
28+ uwsgi -> searx2;
29+ uwsgi -> searx3;
30+ uwsgi -> searx4;
31+ }
32+
33+}
docs/admin/architecture.rstnew file+24
@@ -0,0 +1,24 @@
1+.. _architecture:
2+
3+============
4+Architecture
5+============
6+
7+.. sidebar:: Needs work!
8+
9+ This article needs some work / Searx is a collaborative effort. If you have
10+ any contribution, feel welcome to send us your :pull:`PR <../pulls>`, see
11+ :ref:`how to contribute`.
12+
13+Herein you will find some hints and suggestions about typical architectures of
14+searx infrastructures.
15+
16+We start with a contribution from :pull:`@dalf <1776#issuecomment-567917320>`.
17+It shows a *reference* setup for public searx instances.
18+
19+.. _arch public:
20+
21+.. kernel-figure:: arch_public.dot
22+ :alt: arch_public.dot
23+
24+ Reference architecture of a public searx setup.
docs/admin/buildhosts.rstnew file+103
@@ -0,0 +1,103 @@
1+.. _buildhosts:
2+
3+==========
4+Buildhosts
5+==========
6+
7+.. sidebar:: This article needs some work
8+
9+ If you have any contribution send us your :pull:`PR <../pulls>`, see
10+ :ref:`how to contribute`.
11+
12+To get best results from build, its recommend to install additional packages
13+on build hosts.
14+
15+.. _docs build:
16+
17+Build docs
18+==========
19+
20+.. _Graphviz: https://graphviz.gitlab.io
21+.. _ImageMagick: https://www.imagemagick.org
22+.. _XeTeX: https://tug.org/xetex/
23+.. _dvisvgm: https://dvisvgm.de/
24+
25+.. sidebar:: Sphinx build needs
26+
27+ - ImageMagick_
28+ - Graphviz_
29+ - XeTeX_
30+ - dvisvgm_
31+
32+Most of the sphinx requirements are installed from :origin:`setup.py` and the
33+docs can be build from scratch with ``make docs``. For better math and image
34+processing additional packages are needed. The XeTeX_ needed not only for PDF
35+creation, its also needed for :ref:`math` when HTML output is build.
36+
37+To be able to do :ref:`sphinx:math-support` without CDNs, the math are rendered
38+as images (``sphinx.ext.imgmath`` extension). If your docs build (``make
39+docs``) shows warnings like this::
40+
41+ WARNING: dot(1) not found, for better output quality install \
42+ graphviz from http://www.graphviz.org
43+ ..
44+ WARNING: LaTeX command 'latex' cannot be run (needed for math \
45+ display), check the imgmath_latex setting
46+
47+you need to install additional packages on your build host, to get better HTML
48+output.
49+
50+.. _system requirements:
51+
52+.. tabs::
53+
54+ .. group-tab:: Ubuntu / debian
55+
56+ .. code-block:: sh
57+
58+ $ sudo apt install graphviz imagemagick texlive-xetex librsvg2-bin
59+
60+ .. group-tab:: Arch Linux
61+
62+ .. code-block:: sh
63+
64+ $ sudo pacman -S graphviz imagemagick texlive-bin extra/librsvg
65+
66+ .. group-tab:: Fedora / RHEL
67+
68+ .. code-block:: sh
69+
70+ $ sudo dnf install graphviz graphviz-gd texlive-xetex-bin librsvg2-tools
71+
72+
73+For PDF output you also need:
74+
75+.. tabs::
76+
77+ .. group-tab:: Ubuntu / debian
78+
79+ .. code:: sh
80+
81+ $ sudo apt texlive-latex-recommended texlive-extra-utils ttf-dejavu
82+
83+ .. group-tab:: Arch Linux
84+
85+ .. code:: sh
86+
87+ $ sudo pacman -S texlive-core texlive-latexextra ttf-dejavu
88+
89+ .. group-tab:: Fedora / RHEL
90+
91+ .. code:: sh
92+
93+ $ sudo dnf install \
94+ texlive-collection-fontsrecommended texlive-collection-latex \
95+ dejavu-sans-fonts dejavu-serif-fonts dejavu-sans-mono-fonts
96+
97+.. _system requirements END:
98+
99+.. literalinclude:: ../conf.py
100+ :language: python
101+ :start-after: # sphinx.ext.imgmath setup
102+ :end-before: # sphinx.ext.imgmath setup END
103+
docs/admin/engines.rstnew file+68
@@ -0,0 +1,68 @@
1+.. _engines generic:
2+
3+=======
4+engines
5+=======
6+
7+.. sidebar:: Further reading ..
8+
9+ - :ref:`engines generic`
10+ - :ref:`configured engines`
11+ - :ref:`engine settings`
12+ - :ref:`engine file`
13+
14+============= =========== ==================== ============
15+:ref:`engine settings` :ref:`engine file`
16+------------------------- ---------------------------------
17+Name (cfg) Categories
18+------------------------- ---------------------------------
19+Engine .. Paging support **P**
20+------------------------- -------------------- ------------
21+Shortcut **S** Language support **L**
22+Timeout **TO** Time range support **TR**
23+Disabled **D** Offline **O**
24+------------- ----------- -------------------- ------------
25+Suspend end **SE**
26+------------- ----------- ---------------------------------
27+Safe search **SS**
28+============= =========== =================================
29+
30+Configuration defaults (at built time):
31+
32+.. _configured engines:
33+
34+.. jinja:: webapp
35+
36+ .. flat-table:: Engines configured at built time (defaults)
37+ :header-rows: 1
38+ :stub-columns: 2
39+
40+ * - Name (cfg)
41+ - S
42+ - Engine
43+ - TO
44+ - Categories
45+ - P
46+ - L
47+ - SS
48+ - D
49+ - TR
50+ - O
51+ - SE
52+
53+ {% for name, mod in engines.items() %}
54+
55+ * - {{name}}
56+ - !{{mod.shortcut}}
57+ - {{mod.__name__}}
58+ - {{mod.timeout}}
59+ - {{", ".join(mod.categories)}}
60+ - {{(mod.paging and "y") or ""}}
61+ - {{(mod.language_support and "y") or ""}}
62+ - {{(mod.safesearch and "y") or ""}}
63+ - {{(mod.disabled and "y") or ""}}
64+ - {{(mod.time_range_support and "y") or ""}}
65+ - {{(mod.offline and "y") or ""}}
66+ - {{mod.suspend_end_time}}
67+
68+ {% endfor %}
docs/admin/filtron.rstnew file+148
@@ -0,0 +1,148 @@
1+==========================
2+How to protect an instance
3+==========================
4+
5+Searx depens on external search services. To avoid the abuse of these services
6+it is advised to limit the number of requests processed by searx.
7+
8+An application firewall, ``filtron`` solves exactly this problem. Information
9+on how to install it can be found at the `project page of filtron
10+<https://github.com/asciimoo/filtron>`__.
11+
12+
13+Sample configuration of filtron
14+===============================
15+
16+An example configuration can be find below. This configuration limits the access
17+of:
18+
19+- scripts or applications (roboagent limit)
20+- webcrawlers (botlimit)
21+- IPs which send too many requests (IP limit)
22+- too many json, csv, etc. requests (rss/json limit)
23+- the same UserAgent of if too many requests (useragent limit)
24+
25+.. code:: json
26+
27+ [{
28+ "name":"search request",
29+ "filters":[
30+ "Param:q",
31+ "Path=^(/|/search)$"
32+ ],
33+ "interval":"<time-interval-in-sec (int)>",
34+ "limit":"<max-request-number-in-interval (int)>",
35+ "subrules":[
36+ {
37+ "name":"roboagent limit",
38+ "interval":"<time-interval-in-sec (int)>",
39+ "limit":"<max-request-number-in-interval (int)>",
40+ "filters":[
41+ "Header:User-Agent=(curl|cURL|Wget|python-requests|Scrapy|FeedFetcher|Go-http-client)"
42+ ],
43+ "actions":[
44+ {
45+ "name":"block",
46+ "params":{
47+ "message":"Rate limit exceeded"
48+ }
49+ }
50+ ]
51+ },
52+ {
53+ "name":"botlimit",
54+ "limit":0,
55+ "stop":true,
56+ "filters":[
57+ "Header:User-Agent=(Googlebot|bingbot|Baiduspider|yacybot|YandexMobileBot|YandexBot|Yahoo! Slurp|MJ12bot|AhrefsBot|archive.org_bot|msnbot|MJ12bot|SeznamBot|linkdexbot|Netvibes|SMTBot|zgrab|James BOT)"
58+ ],
59+ "actions":[
60+ {
61+ "name":"block",
62+ "params":{
63+ "message":"Rate limit exceeded"
64+ }
65+ }
66+ ]
67+ },
68+ {
69+ "name":"IP limit",
70+ "interval":"<time-interval-in-sec (int)>",
71+ "limit":"<max-request-number-in-interval (int)>",
72+ "stop":true,
73+ "aggregations":[
74+ "Header:X-Forwarded-For"
75+ ],
76+ "actions":[
77+ {
78+ "name":"block",
79+ "params":{
80+ "message":"Rate limit exceeded"
81+ }
82+ }
83+ ]
84+ },
85+ {
86+ "name":"rss/json limit",
87+ "interval":"<time-interval-in-sec (int)>",
88+ "limit":"<max-request-number-in-interval (int)>",
89+ "stop":true,
90+ "filters":[
91+ "Param:format=(csv|json|rss)"
92+ ],
93+ "actions":[
94+ {
95+ "name":"block",
96+ "params":{
97+ "message":"Rate limit exceeded"
98+ }
99+ }
100+ ]
101+ },
102+ {
103+ "name":"useragent limit",
104+ "interval":"<time-interval-in-sec (int)>",
105+ "limit":"<max-request-number-in-interval (int)>",
106+ "aggregations":[
107+ "Header:User-Agent"
108+ ],
109+ "actions":[
110+ {
111+ "name":"block",
112+ "params":{
113+ "message":"Rate limit exceeded"
114+ }
115+ }
116+ ]
117+ }
118+ ]
119+ }]
120+
121+
122+
123+Route request through filtron
124+=============================
125+
126+Filtron can be started using the following command:
127+
128+.. code:: sh
129+
130+ $ filtron -rules rules.json
131+
132+It listens on ``127.0.0.1:4004`` and forwards filtered requests to
133+``127.0.0.1:8888`` by default.
134+
135+Use it along with ``nginx`` with the following example configuration.
136+
137+.. code:: nginx
138+
139+ location / {
140+ proxy_set_header Host $http_host;
141+ proxy_set_header X-Real-IP $remote_addr;
142+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
143+ proxy_set_header X-Scheme $scheme;
144+ proxy_pass http://127.0.0.1:4004/;
145+ }
146+
147+Requests are coming from port 4004 going through filtron and then forwarded to
148+port 8888 where a searx is being run.
docs/admin/index.rstnew file+15
@@ -0,0 +1,15 @@
1+===========================
2+Administrator documentation
3+===========================
4+
5+.. toctree::
6+ :maxdepth: 1
7+
8+ installation
9+ api
10+ architecture
11+ filtron
12+ morty
13+ engines
14+ plugins
15+ buildhosts
docs/admin/installation.rstnew file+341
@@ -0,0 +1,341 @@
1+.. _installation:
2+
3+============
4+Installation
5+============
6+
7+.. contents::
8+ :depth: 3
9+
10+Basic installation
11+==================
12+
13+Step by step installation for Debian/Ubuntu with virtualenv. For Ubuntu, be sure
14+to have enable universe repository.
15+
16+Install packages:
17+
18+.. code:: sh
19+
20+ $ sudo -H apt-get install \
21+ git build-essential libxslt-dev \
22+ python-dev python-virtualenv python-babel \
23+ zlib1g-dev libffi-dev libssl-dev
24+
25+Install searx:
26+
27+.. code:: sh
28+
29+ cd /usr/local
30+ sudo -H git clone https://github.com/asciimoo/searx.git
31+ sudo -H useradd searx -d /usr/local/searx
32+ sudo -H chown searx:searx -R /usr/local/searx
33+
34+Install dependencies in a virtualenv:
35+
36+.. code:: sh
37+
38+ cd /usr/local/searx
39+ sudo -H -u searx -i
40+
41+.. code:: sh
42+
43+ (searx)$ virtualenv searx-ve
44+ (searx)$ . ./searx-ve/bin/activate
45+ (searx)$ ./manage.sh update_packages
46+
47+Configuration
48+==============
49+
50+.. code:: sh
51+
52+ sed -i -e "s/ultrasecretkey/`openssl rand -hex 16`/g" searx/settings.yml
53+
54+Edit searx/settings.yml if necessary.
55+
56+Check
57+=====
58+
59+Start searx:
60+
61+.. code:: sh
62+
63+ python searx/webapp.py
64+
65+Go to http://localhost:8888
66+
67+If everything works fine, disable the debug option in settings.yml:
68+
69+.. code:: sh
70+
71+ sed -i -e "s/debug : True/debug : False/g" searx/settings.yml
72+
73+At this point searx is not demonized ; uwsgi allows this.
74+
75+You can exit the virtualenv and the searx user bash (enter exit command
76+twice).
77+
78+uwsgi
79+=====
80+
81+Install packages:
82+
83+.. code:: sh
84+
85+ sudo -H apt-get install \
86+ uwsgi uwsgi-plugin-python
87+
88+Create the configuration file ``/etc/uwsgi/apps-available/searx.ini`` with this
89+content:
90+
91+.. code:: ini
92+
93+ [uwsgi]
94+ # Who will run the code
95+ uid = searx
96+ gid = searx
97+
98+ # disable logging for privacy
99+ disable-logging = true
100+
101+ # Number of workers (usually CPU count)
102+ workers = 4
103+
104+ # The right granted on the created socket
105+ chmod-socket = 666
106+
107+ # Plugin to use and interpretor config
108+ single-interpreter = true
109+ master = true
110+ plugin = python
111+ lazy-apps = true
112+ enable-threads = true
113+
114+ # Module to import
115+ module = searx.webapp
116+
117+ # Virtualenv and python path
118+ virtualenv = /usr/local/searx/searx-ve/
119+ pythonpath = /usr/local/searx/
120+ chdir = /usr/local/searx/searx/
121+
122+Activate the uwsgi application and restart:
123+
124+.. code:: sh
125+
126+ cd /etc/uwsgi/apps-enabled
127+ ln -s ../apps-available/searx.ini
128+ /etc/init.d/uwsgi restart
129+
130+Web server
131+==========
132+
133+with nginx
134+----------
135+
136+If nginx is not installed (uwsgi will not work with the package
137+nginx-light):
138+
139+.. code:: sh
140+
141+ sudo -H apt-get install nginx
142+
143+Hosted at /
144+~~~~~~~~~~~
145+
146+Create the configuration file ``/etc/nginx/sites-available/searx`` with this
147+content:
148+
149+.. code:: nginx
150+
151+ server {
152+ listen 80;
153+ server_name searx.example.com;
154+ root /usr/local/searx;
155+
156+ location / {
157+ include uwsgi_params;
158+ uwsgi_pass unix:/run/uwsgi/app/searx/socket;
159+ }
160+ }
161+
162+Create a symlink to sites-enabled:
163+
164+.. code:: sh
165+
166+ sudo -H ln -s /etc/nginx/sites-available/searx /etc/nginx/sites-enabled/searx
167+
168+Restart service:
169+
170+.. code:: sh
171+
172+ sudo -H service nginx restart
173+ sudo -H service uwsgi restart
174+
175+from subdirectory URL (/searx)
176+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
177+
178+Add this configuration in the server config file
179+``/etc/nginx/sites-enabled/default``:
180+
181+.. code:: nginx
182+
183+ location = /searx { rewrite ^ /searx/; }
184+ location /searx {
185+ try_files $uri @searx;
186+ }
187+ location @searx {
188+ uwsgi_param SCRIPT_NAME /searx;
189+ include uwsgi_params;
190+ uwsgi_modifier1 30;
191+ uwsgi_pass unix:/run/uwsgi/app/searx/socket;
192+ }
193+
194+
195+**OR** using reverse proxy (Please, note that reverse proxy advised to be used
196+in case of single-user or low-traffic instances.)
197+
198+.. code:: nginx
199+
200+ location /searx {
201+ proxy_pass http://127.0.0.1:8888;
202+ proxy_set_header Host $host;
203+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
204+ proxy_set_header X-Scheme $scheme;
205+ proxy_set_header X-Script-Name /searx;
206+ proxy_buffering off;
207+ }
208+
209+
210+Enable ``base_url`` in ``searx/settings.yml``
211+
212+.. code:: yaml
213+
214+ base_url : http://your.domain.tld/searx/
215+
216+Restart service:
217+
218+.. code:: sh
219+
220+ sudo -H service nginx restart
221+ sudo -H service uwsgi restart
222+
223+disable logs
224+^^^^^^^^^^^^
225+
226+for better privacy you can disable nginx logs about searx.
227+
228+how to proceed: below ``uwsgi_pass`` in ``/etc/nginx/sites-available/default``
229+add:
230+
231+.. code:: nginx
232+
233+ access_log /dev/null;
234+ error_log /dev/null;
235+
236+Restart service:
237+
238+.. code:: sh
239+
240+ sudo -H service nginx restart
241+
242+with apache
243+-----------
244+
245+Add wsgi mod:
246+
247+.. code:: sh
248+
249+ sudo -H apt-get install libapache2-mod-uwsgi
250+ sudo -H a2enmod uwsgi
251+
252+Add this configuration in the file ``/etc/apache2/apache2.conf``:
253+
254+.. code:: apache
255+
256+ <Location />
257+ Options FollowSymLinks Indexes
258+ SetHandler uwsgi-handler
259+ uWSGISocket /run/uwsgi/app/searx/socket
260+ </Location>
261+
262+Note that if your instance of searx is not at the root, you should change
263+``<Location />`` by the location of your instance, like ``<Location /searx>``.
264+
265+Restart Apache:
266+
267+.. code:: sh
268+
269+ sudo -H /etc/init.d/apache2 restart
270+
271+disable logs
272+~~~~~~~~~~~~
273+
274+For better privacy you can disable Apache logs.
275+
276+.. warning::
277+
278+ You can only disable logs for the whole (virtual) server not for a specific
279+ path.
280+
281+Go back to ``/etc/apache2/apache2.conf`` and above ``<Location />`` add:
282+
283+.. code:: apache
284+
285+ CustomLog /dev/null combined
286+
287+Restart Apache:
288+
289+.. code:: sh
290+
291+ sudo -H /etc/init.d/apache2 restart
292+
293+How to update
294+=============
295+
296+.. code:: sh
297+
298+ cd /usr/local/searx
299+ sudo -H -u searx -i
300+
301+.. code:: sh
302+
303+ (searx)$ . ./searx-ve/bin/activate
304+ (searx)$ git stash
305+ (searx)$ git pull origin master
306+ (searx)$ git stash apply
307+ (searx)$ ./manage.sh update_packages
308+
309+.. code:: sh
310+
311+ sudo -H service uwsgi restart
312+
313+Docker
314+======
315+
316+Make sure you have installed Docker. For instance, you can deploy searx like this:
317+
318+.. code:: sh
319+
320+ docker pull wonderfall/searx
321+ docker run -d --name searx -p $PORT:8888 wonderfall/searx
322+
323+Go to ``http://localhost:$PORT``.
324+
325+See https://hub.docker.com/r/wonderfall/searx/ for more informations. It's also
326+possible to build searx from the embedded Dockerfile.
327+
328+.. code:: sh
329+
330+ git clone https://github.com/asciimoo/searx.git
331+ cd searx
332+ docker build -t whatever/searx .
333+
334+References
335+==========
336+
337+* https://about.okhin.fr/posts/Searx/ with some additions
338+
339+* How to: `Setup searx in a couple of hours with a free SSL certificate
340+ <https://www.reddit.com/r/privacytoolsIO/comments/366kvn/how_to_setup_your_own_privacy_respecting_search/>`__
341+
docs/admin/morty.rstnew file+26
@@ -0,0 +1,26 @@
1+=========================
2+How to setup result proxy
3+=========================
4+
5+.. _morty: https://github.com/asciimoo/morty
6+.. _morty's README: https://github.com/asciimoo/morty
7+
8+By default searx can only act as an image proxy for result images, but it is
9+possible to proxify all the result URLs with an external service, morty_.
10+
11+To use this feature, morty has to be installed and activated in searx's
12+``settings.yml``.
13+
14+Add the following snippet to your ``settings.yml`` and restart searx:
15+
16+.. code:: yaml
17+
18+ result_proxy:
19+ url : http://127.0.0.1:3000/
20+ key : your_morty_proxy_key
21+
22+``url``
23+ Is the address of the running morty service.
24+
25+``key``
26+ Is an optional argument, see `morty's README`_ for more information.
docs/admin/plugins.rstnew file+39
@@ -0,0 +1,39 @@
1+.. _plugins generic:
2+
3+===============
4+Plugins builtin
5+===============
6+
7+.. sidebar:: Further reading ..
8+
9+ - :ref:`dev plugin`
10+
11+Configuration defaults (at built time):
12+
13+:DO: Default on
14+
15+.. _configured plugins:
16+
17+.. jinja:: webapp
18+
19+ .. flat-table:: Plugins configured at built time (defaults)
20+ :header-rows: 1
21+ :stub-columns: 1
22+ :widths: 3 1 9
23+
24+ * - Name
25+ - DO
26+ - Description
27+
28+ JS & CSS dependencies
29+
30+ {% for plgin in plugins %}
31+
32+ * - {{plgin.name}}
33+ - {{(plgin.default_on and "y") or ""}}
34+ - {{plgin.description}}
35+
36+ {% for dep in (plgin.js_dependencies + plgin.css_dependencies) %}
37+ | ``{{dep}}`` {% endfor %}
38+
39+ {% endfor %}
docs/blog/admin.rstnew file+43
@@ -0,0 +1,43 @@
1+=============================================================
2+Searx admin interface
3+=============================================================
4+
5+.. _searx-admin: https://github.com/kvch/searx-admin#searx-admin
6+.. _NLnet Foundation: https://nlnet.nl/
7+
8+ manage your instance from your browser
9+
10+.. sidebar:: Installation
11+
12+ Installation guide can be found in the repository of searx-admin_.
13+
14+One of the biggest advantages of searx is being extremely customizable. But at
15+first it can be daunting to newcomers. A barrier of taking advantage of this
16+feature is our ugly settings file which is sometimes hard to understand and
17+edit.
18+
19+To make self-hosting searx more accessible a new tool is introduced, called
20+``searx-admin``. It is a web application which is capable of managing your
21+instance and manipulating its settings via a web UI. It aims to replace editing
22+of ``settings.yml`` for less experienced administrators or people who prefer
23+graphical admin interfaces.
24+
25+.. figure:: searx-admin-engines.png
26+ :alt: Screenshot of engine list
27+
28+ Configuration page of engines
29+
30+Since ``searx-admin`` acts as a supervisor for searx, we have decided to
31+implement it as a standalone tool instead of part of searx. Another reason for
32+making it a standalone tool is that the codebase and dependencies of searx
33+should not grow because of a fully optional feature, which does not affect
34+existing instances.
35+
36+
37+Acknowledgements
38+================
39+
40+This development was sponsored by `NLnet Foundation`_.
41+
42+| Happy hacking.
43+| kvch // 2017.08.22 21:25
docs/blog/index.rstnew file+10
@@ -0,0 +1,10 @@
1+====
2+Blog
3+====
4+
5+.. toctree::
6+ :maxdepth: 1
7+
8+ python3
9+ admin
10+ intro-offline
docs/blog/intro-offline.rstnew file+77
@@ -0,0 +1,77 @@
1+===============================
2+Preparation for offline engines
3+===============================
4+
5+Offline engines
6+===============
7+
8+To extend the functionality of searx, offline engines are going to be
9+introduced. An offline engine is an engine which does not need Internet
10+connection to perform a search and does not use HTTP to communicate.
11+
12+Offline engines can be configured as online engines, by adding those to the
13+`engines` list of :origin:`settings.yml <searx/settings.yml>`. Thus, searx
14+finds the engine file and imports it.
15+
16+Example skeleton for the new engines:
17+
18+.. code:: python
19+
20+ from subprocess import PIPE, Popen
21+
22+ categories = ['general']
23+ offline = True
24+
25+ def init(settings):
26+ pass
27+
28+ def search(query, params):
29+ process = Popen(['ls', query], stdout=PIPE)
30+ return_code = process.wait()
31+ if return_code != 0:
32+ raise RuntimeError('non-zero return code', return_code)
33+
34+ results = []
35+ line = process.stdout.readline()
36+ while line:
37+ result = parse_line(line)
38+ results.append(results)
39+
40+ line = process.stdout.readline()
41+
42+ return results
43+
44+
45+Development progress
46+====================
47+
48+First, a proposal has been created as a Github issue. Then it was moved to the
49+wiki as a design document. You can read it here: :wiki:`Offline-engines`.
50+
51+In this development step, searx core was prepared to accept and perform offline
52+searches. Offline search requests are scheduled together with regular offline
53+requests.
54+
55+As offline searches can return arbitrary results depending on the engine, the
56+current result templates were insufficient to present such results. Thus, a new
57+template is introduced which is caplable of presenting arbitrary key value pairs
58+as a table. You can check out the pull request for more details see
59+:pull:`1700`.
60+
61+Next steps
62+==========
63+
64+Today, it is possible to create/run an offline engine. However, it is going to be publicly available for everyone who knows the searx instance. So the next step is to introduce token based access for engines. This way administrators are able to limit the access to private engines.
65+
66+Acknowledgement
67+===============
68+
69+This development was sponsored by `Search and Discovery Fund`_ of `NLnet Foundation`_ .
70+
71+.. _Search and Discovery Fund: https://nlnet.nl/discovery
72+.. _NLnet Foundation: https://nlnet.nl/
73+
74+
75+| Happy hacking.
76+| kvch // 2019.10.21 17:03
77+
docs/blog/python3.rstnew file+68
@@ -0,0 +1,68 @@
1+============================
2+Introducing Python 3 support
3+============================
4+
5+.. _Python 2.7 clock: https://pythonclock.org/
6+
7+.. sidebar:: Python 2.7 to 3 upgrade
8+
9+ This chapter exists of historical reasons. Python 2.7 release schedule ends
10+ (`Python 2.7 clock`_) after 11 years Python 3 exists
11+
12+As most operation systems are coming with Python3 installed by default. So it is
13+time for searx to support Python3. But don't worry support of Python2.7 won't be
14+dropped.
15+
16+.. image:: searxpy3.png
17+ :scale: 50 %
18+ :alt: hurray
19+ :align: center
20+
21+
22+How to run searx using Python 3
23+===============================
24+
25+Please make sure that you run at least Python 3.5.
26+
27+To run searx, first a Python3 virtualenv should be created. After entering the
28+virtualenv, dependencies must be installed. Then run searx with python3 instead
29+of the usual python command.
30+
31+.. code:: sh
32+
33+ virtualenv -p python3 venv3
34+ source venv3/bin/activate
35+ pip3 install -r requirements.txt
36+ python3 searx/webapp.py
37+
38+
39+If you want to run searx using Python2.7, you don't have to do anything
40+differently as before.
41+
42+Fun facts
43+=========
44+
45+- 115 files were changed when implementing the support for both Python versions.
46+
47+- All of the dependencies was compatible except for the robotframework used for
48+ browser tests. Thus, these tests were migrated to splinter. So from now on
49+ both versions are being tested on Travis and can be tested locally.
50+
51+If you found bugs
52+=================
53+
54+Please open an issue on `GitHub`_. Make sure that you mention your Python
55+version in your issue, so we can investigate it properly.
56+
57+.. _GitHub: https://github.com/asciimoo/searx/issues
58+
59+Acknowledgment
60+==============
61+
62+This development was sponsored by `NLnet Foundation`_.
63+
64+.. _NLnet Foundation: https://nlnet.nl/
65+
66+
67+| Happy hacking.
68+| kvch // 2017.05.13 22:57
docs/blog/searx-admin-engines.pngnew file

Binary file not shown.

docs/blog/searxpy3.pngnew file

Binary file not shown.

docs/conf.pynew file+114
@@ -0,0 +1,114 @@
1+# -*- coding: utf-8 -*-
2+
3+import sys, os
4+from searx.version import VERSION_STRING
5+from pallets_sphinx_themes import ProjectLink
6+
7+GIT_URL = os.environ.get("GIT_URL", "https://github.com/asciimoo/searx")
8+SEARX_URL = os.environ.get("SEARX_URL", "https://searx.me")
9+DOCS_URL = os.environ.get("DOCS_URL", "https://asciimoo.github.io/searx/")
10+
11+# Project --------------------------------------------------------------
12+
13+project = u'searx'
14+copyright = u'2015-2019, Adam Tauber, Noémi Ványi'
15+author = u'Adam Tauber'
16+release, version = VERSION_STRING, VERSION_STRING
17+highlight_language = 'none'
18+
19+# General --------------------------------------------------------------
20+
21+master_doc = "index"
22+source_suffix = '.rst'
23+numfig = True
24+
25+from searx import webapp
26+jinja_contexts = {
27+ 'webapp': dict(**webapp.__dict__)
28+}
29+
30+# usage:: lorem :patch:`f373169` ipsum
31+extlinks = {}
32+
33+# upstream links
34+extlinks['wiki'] = ('https://github.com/asciimoo/searx/wiki/%s', ' ')
35+extlinks['pull'] = ('https://github.com/asciimoo/searx/pull/%s', 'PR ')
36+
37+# links to custom brand
38+extlinks['origin'] = (GIT_URL + '/blob/master/%s', 'git://')
39+extlinks['patch'] = (GIT_URL + '/commit/%s', '#')
40+extlinks['search'] = (SEARX_URL + '/%s', '#')
41+extlinks['docs'] = (DOCS_URL + '/%s', 'docs: ')
42+extlinks['pypi'] = ('https://pypi.org/project/%s', 'PyPi: ')
43+extlinks['man'] = ('https://manpages.debian.org/jump?q=%s', '')
44+#extlinks['role'] = (
45+# 'https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-%s', '')
46+extlinks['duref'] = (
47+ 'http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#%s', '')
48+extlinks['durole'] = (
49+ 'http://docutils.sourceforge.net/docs/ref/rst/roles.html#%s', '')
50+extlinks['dudir'] = (
51+ 'http://docutils.sourceforge.net/docs/ref/rst/directives.html#%s', '')
52+extlinks['ctan'] = (
53+ 'https://ctan.org/pkg/%s', 'CTAN: ')
54+
55+extensions = [
56+ 'sphinx.ext.imgmath',
57+ 'sphinx.ext.extlinks',
58+ 'sphinx.ext.viewcode',
59+ "sphinx.ext.autodoc",
60+ "sphinx.ext.intersphinx",
61+ "pallets_sphinx_themes",
62+ "sphinx_issues", # https://github.com/sloria/sphinx-issues/blob/master/README.rst
63+ "sphinxcontrib.jinja", # https://github.com/tardyp/sphinx-jinja
64+ 'linuxdoc.rstFlatTable', # Implementation of the 'flat-table' reST-directive.
65+ 'linuxdoc.kfigure', # Sphinx extension which implements scalable image handling.
66+ "sphinx_tabs.tabs", # https://github.com/djungelorm/sphinx-tabs
67+]
68+
69+intersphinx_mapping = {
70+ "python": ("https://docs.python.org/3/", None),
71+ "flask": ("https://flask.palletsprojects.com/", None),
72+ # "werkzeug": ("https://werkzeug.palletsprojects.com/", None),
73+ "jinja": ("https://jinja.palletsprojects.com/", None),
74+ "linuxdoc" : ("https://return42.github.io/linuxdoc/", None),
75+ "sphinx" : ("https://www.sphinx-doc.org/en/master/", None),
76+}
77+
78+issues_github_path = "asciimoo/searx"
79+
80+# HTML -----------------------------------------------------------------
81+
82+sys.path.append(os.path.abspath('_themes'))
83+html_theme_path = ['_themes']
84+html_theme = "searx"
85+
86+# sphinx.ext.imgmath setup
87+html_math_renderer = 'imgmath'
88+imgmath_image_format = 'svg'
89+imgmath_font_size = 14
90+# sphinx.ext.imgmath setup END
91+
92+html_theme_options = {"index_sidebar_logo": True}
93+html_context = {
94+ "project_links": [
95+ ProjectLink("Source", GIT_URL),
96+ ProjectLink("Wiki", "https://github.com/asciimoo/searx/wiki"),
97+ ProjectLink("Public instances", "https://github.com/asciimoo/searx/wiki/Searx-instances"),
98+ ProjectLink("Twitter", "https://twitter.com/Searx_engine"),
99+ ]
100+}
101+html_sidebars = {
102+ "**": ["project.html", "relations.html", "searchbox.html"],
103+}
104+singlehtml_sidebars = {"index": ["project.html", "localtoc.html"]}
105+html_static_path = ["static"]
106+html_logo = "static/img/searx_logo_small.png"
107+html_title = "Searx Documentation ({})".format("Searx-{}.tex".format(VERSION_STRING))
108+html_show_sourcelink = False
109+
110+# LaTeX ----------------------------------------------------------------
111+
112+latex_documents = [
113+ (master_doc, "searx-{}.tex".format(VERSION_STRING), html_title, author, "manual")
114+]
docs/dev/contribution_guide.rstnew file+180
@@ -0,0 +1,180 @@
1+.. _how to contribute:
2+
3+=================
4+How to contribute
5+=================
6+
7+Prime directives: Privacy, Hackability
8+======================================
9+
10+Searx has two prime directives, **privacy-by-design and hackability** . The
11+hackability comes in three levels:
12+
13+- support of search engines
14+- plugins to alter search behaviour
15+- hacking searx itself
16+
17+Note the lack of "world domination" among the directives. Searx has no
18+intention of wide mass-adoption, rounded corners, etc. The prime directive
19+"privacy" deserves a separate chapter, as it's quite uncommon unfortunately.
20+
21+Privacy-by-design
22+-----------------
23+
24+Searx was born out of the need for a **privacy-respecting** search tool which
25+can be extended easily to maximize both, its search and its privacy protecting
26+capabilities.
27+
28+A few widely used features work differently or turned off by default or not
29+implemented at all **as a consequence of privacy-by-design**.
30+
31+If a feature reduces the privacy preserving aspects of searx, it should be
32+switched off by default or should not implemented at all. There are plenty of
33+search engines already providing such features. If a feature reduces the
34+protection of searx, users must be informed about the effect of choosing to
35+enable it. Features that protect privacy but differ from the expectations of
36+the user should also be explained.
37+
38+Also, if you think that something works weird with searx, it's might be because
39+of the tool you use is designed in a way to interfere with the privacy respect.
40+Submitting a bugreport to the vendor of the tool that misbehaves might be a good
41+feedback to reconsider the disrespect to its customers (e.g. ``GET`` vs ``POST``
42+requests in various browsers).
43+
44+Remember the other prime directive of searx is to be hackable, so if the above
45+privacy concerns do not fancy you, simply fork it.
46+
47+ *Happy hacking.*
48+
49+Code
50+====
51+
52+.. _PEP8: https://www.python.org/dev/peps/pep-0008/
53+.. _Conventional Commits: https://www.conventionalcommits.org/
54+.. _Git Commit Good Practice: https://wiki.openstack.org/wiki/GitCommitMessages
55+.. _Structural split of changes:
56+ https://wiki.openstack.org/wiki/GitCommitMessages#Structural_split_of_changes
57+.. _gitmoji: https://gitmoji.carloscuesta.me/
58+.. _Semantic PR: https://github.com/zeke/semantic-pull-requests
59+
60+.. sidebar:: Create good commits!
61+
62+ - `Structural split of changes`_
63+ - `Conventional Commits`_
64+ - `Git Commit Good Practice`_
65+ - some like to use: gitmoji_
66+ - not yet active: `Semantic PR`_
67+
68+In order to submit a patch, please follow the steps below:
69+
70+- Follow coding conventions.
71+
72+ - PEP8_ standards apply, except the convention of line length
73+ - Maximum line length is 120 characters
74+
75+- The cardinal rule for creating good commits is to ensure there is only one
76+ *logical change* per commit / read `Structural split of changes`_
77+
78+- Check if your code breaks existing tests. If so, update the tests or fix your
79+ code.
80+
81+- If your code can be unit-tested, add unit tests.
82+
83+- Add yourself to the :origin:`AUTHORS.rst` file.
84+
85+- Choose meaning full commit messages, read `Conventional Commits`_
86+
87+ .. code::
88+
89+ <type>[optional scope]: <description>
90+
91+ [optional body]
92+
93+ [optional footer(s)]
94+
95+- Create a pull request.
96+
97+For more help on getting started with searx development, see :ref:`devquickstart`.
98+
99+
100+Translation
101+===========
102+
103+Translation currently takes place on :ref:`transifex <translation>`.
104+
105+.. caution::
106+
107+ Please, do not update translation files in the repo.
108+
109+
110+.. _contrib docs:
111+
112+Documentation
113+=============
114+
115+.. _Sphinx: http://www.sphinx-doc.org
116+.. _reST: http://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html
117+
118+.. sidebar:: The reST sources
119+
120+ has been moved from ``gh-branch`` into ``master`` (:origin:`docs`).
121+
122+The documentation is built using Sphinx_. So in order to be able to generate
123+the required files, you have to install it on your system. Much easier, use
124+our :ref:`makefile`.
125+
126+Here is an example which makes a complete rebuild:
127+
128+.. code:: sh
129+
130+ $ make docs-clean docs
131+ ...
132+ The HTML pages are in dist/docs.
133+
134+.. _make docs-live:
135+
136+live build
137+----------
138+
139+.. sidebar:: docs-clean
140+
141+ It is recommended to assert a complete rebuild before deploying (use
142+ ``docs-clean``).
143+
144+Live build is like WYSIWYG. If you want to edit the documentation, its
145+recommended to use. The Makefile target ``docs-live`` builds the docs, opens
146+URL in your favorite browser and rebuilds every time a reST file has been
147+changed.
148+
149+.. code:: sh
150+
151+ $ make docs-live
152+ ...
153+ The HTML pages are in dist/docs.
154+ ... Serving on http://0.0.0.0:8080
155+ ... Start watching changes
156+
157+
158+.. _deploy on github.io:
159+
160+deploy on github.io
161+-------------------
162+
163+To deploy documentation at :docs:`github.io <.>` use Makefile target
164+:ref:`make gh-pages`, which will builds the documentation, clones searx into a sub
165+folder ``gh-pages``, cleans it, copies the doc build into and runs all the
166+needed git add, commit and push:
167+
168+.. code:: sh
169+
170+ $ make docs-clean gh-pages
171+ ...
172+ SPHINX docs --> file://<...>/dist/docs
173+ The HTML pages are in dist/docs.
174+ ...
175+ Cloning into 'gh-pages' ...
176+ ...
177+ cd gh-pages; git checkout gh-pages >/dev/null
178+ Switched to a new branch 'gh-pages'
179+ ...
180+ doc available at --> https://asciimoo.github.io/searx
docs/dev/csv_table.txtnew file+6
@@ -0,0 +1,6 @@
1+stub col row 1, column, "loremLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
2+eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
3+voluptua."
4+stub col row 1, "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita
5+kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.", column
6+stub col row 1, column, column
docs/dev/engine_overview.rstnew file+267
@@ -0,0 +1,267 @@
1+
2+.. _engines-dev:
3+
4+===============
5+Engine overview
6+===============
7+
8+.. _metasearch-engine: https://en.wikipedia.org/wiki/Metasearch_engine
9+
10+searx is a metasearch-engine_, so it uses different search engines to provide
11+better results.
12+
13+Because there is no general search API which could be used for every search
14+engine, an adapter has to be built between searx and the external search
15+engines. Adapters are stored under the folder :origin:`searx/engines`.
16+
17+.. contents::
18+ :depth: 3
19+ :backlinks: entry
20+
21+general engine configuration
22+============================
23+
24+It is required to tell searx the type of results the engine provides. The
25+arguments can be set in the engine file or in the settings file
26+(normally ``settings.yml``). The arguments in the settings file override
27+the ones in the engine file.
28+
29+It does not matter if an option is stored in the engine file or in the
30+settings. However, the standard way is the following:
31+
32+.. _engine file:
33+
34+engine file
35+-----------
36+
37+======================= =========== ===========================================
38+argument type information
39+======================= =========== ===========================================
40+categories list pages, in which the engine is working
41+paging boolean support multible pages
42+language_support boolean support language choosing
43+time_range_support boolean support search time range
44+offline boolean engine runs offline
45+======================= =========== ===========================================
46+
47+.. _engine settings:
48+
49+settings.yml
50+------------
51+
52+======================= =========== ===========================================
53+argument type information
54+======================= =========== ===========================================
55+name string name of search-engine
56+engine string name of searx-engine
57+ (filename without ``.py``)
58+shortcut string shortcut of search-engine
59+timeout string specific timeout for search-engine
60+======================= =========== ===========================================
61+
62+
63+overrides
64+---------
65+
66+A few of the options have default values in the engine, but are often
67+overwritten by the settings. If ``None`` is assigned to an option in the engine
68+file, it has to be redefined in the settings, otherwise searx will not start
69+with that engine.
70+
71+The naming of overrides is arbitrary. But the recommended overrides are the
72+following:
73+
74+======================= =========== ===========================================
75+argument type information
76+======================= =========== ===========================================
77+base_url string base-url, can be overwritten to use same
78+ engine on other URL
79+number_of_results int maximum number of results per request
80+language string ISO code of language and country like en_US
81+api_key string api-key if required by engine
82+======================= =========== ===========================================
83+
84+example code
85+------------
86+
87+.. code:: python
88+
89+ # engine dependent config
90+ categories = ['general']
91+ paging = True
92+ language_support = True
93+
94+
95+making a request
96+================
97+
98+To perform a search an URL have to be specified. In addition to specifying an
99+URL, arguments can be passed to the query.
100+
101+passed arguments
102+----------------
103+
104+These arguments can be used to construct the search query. Furthermore,
105+parameters with default value can be redefined for special purposes.
106+
107+====================== ============ ========================================================================
108+argument type default-value, information
109+====================== ============ ========================================================================
110+url string ``''``
111+method string ``'GET'``
112+headers set ``{}``
113+data set ``{}``
114+cookies set ``{}``
115+verify boolean ``True``
116+headers.User-Agent string a random User-Agent
117+category string current category, like ``'general'``
118+started datetime current date-time
119+pageno int current pagenumber
120+language string specific language code like ``'en_US'``, or ``'all'`` if unspecified
121+====================== ============ ========================================================================
122+
123+parsed arguments
124+----------------
125+
126+The function ``def request(query, params):`` always returns the ``params``
127+variable. Inside searx, the following paramters can be used to specify a search
128+request:
129+
130+============ =========== =========================================================
131+argument type information
132+============ =========== =========================================================
133+url string requested url
134+method string HTTP request method
135+headers set HTTP header information
136+data set HTTP data information (parsed if ``method != 'GET'``)
137+cookies set HTTP cookies
138+verify boolean Performing SSL-Validity check
139+============ =========== =========================================================
140+
141+
142+example code
143+------------
144+
145+.. code:: python
146+
147+ # search-url
148+ base_url = 'https://example.com/'
149+ search_string = 'search?{query}&page={page}'
150+
151+ # do search-request
152+ def request(query, params):
153+ search_path = search_string.format(
154+ query=urlencode({'q': query}),
155+ page=params['pageno'])
156+
157+ params['url'] = base_url + search_path
158+
159+ return params
160+
161+
162+returned results
163+================
164+
165+Searx is able to return results of different media-types. Currently the
166+following media-types are supported:
167+
168+- default_
169+- images_
170+- videos_
171+- torrent_
172+- map_
173+
174+To set another media-type as default, the parameter ``template`` must be set to
175+the desired type.
176+
177+default
178+-------
179+
180+========================= =====================================================
181+result-parameter information
182+========================= =====================================================
183+url string, url of the result
184+title string, title of the result
185+content string, general result-text
186+publishedDate :py:class:`datetime.datetime`, time of publish
187+========================= =====================================================
188+
189+images
190+------
191+
192+To use this template, the parameter:
193+
194+========================= =====================================================
195+result-parameter information
196+========================= =====================================================
197+template is set to ``images.html``
198+url string, url to the result site
199+title string, title of the result *(partly implemented)*
200+content *(partly implemented)*
201+publishedDate :py:class:`datetime.datetime`,
202+ time of publish *(partly implemented)*
203+img\_src string, url to the result image
204+thumbnail\_src string, url to a small-preview image
205+========================= =====================================================
206+
207+videos
208+------
209+
210+========================= =====================================================
211+result-parameter information
212+========================= =====================================================
213+template is set to ``videos.html``
214+url string, url of the result
215+title string, title of the result
216+content *(not implemented yet)*
217+publishedDate :py:class:`datetime.datetime`, time of publish
218+thumbnail string, url to a small-preview image
219+========================= =====================================================
220+
221+torrent
222+-------
223+
224+.. _magnetlink: https://en.wikipedia.org/wiki/Magnet_URI_scheme
225+
226+========================= =====================================================
227+result-parameter information
228+========================= =====================================================
229+template is set to ``torrent.html``
230+url string, url of the result
231+title string, title of the result
232+content string, general result-text
233+publishedDate :py:class:`datetime.datetime`,
234+ time of publish *(not implemented yet)*
235+seed int, number of seeder
236+leech int, number of leecher
237+filesize int, size of file in bytes
238+files int, number of files
239+magnetlink string, magnetlink_ of the result
240+torrentfile string, torrentfile of the result
241+========================= =====================================================
242+
243+
244+map
245+---
246+
247+========================= =====================================================
248+result-parameter information
249+========================= =====================================================
250+url string, url of the result
251+title string, title of the result
252+content string, general result-text
253+publishedDate :py:class:`datetime.datetime`, time of publish
254+latitude latitude of result (in decimal format)
255+longitude longitude of result (in decimal format)
256+boundingbox boundingbox of result (array of 4. values
257+ ``[lat-min, lat-max, lon-min, lon-max]``)
258+geojson geojson of result (http://geojson.org)
259+osm.type type of osm-object (if OSM-Result)
260+osm.id id of osm-object (if OSM-Result)
261+address.name name of object
262+address.road street name of object
263+address.house_number house number of object
264+address.locality city, place of object
265+address.postcode postcode of object
266+address.country country of object
267+========================= =====================================================
docs/dev/hello.dotnew file+3
@@ -0,0 +1,3 @@
1+graph G {
2+ Hello -- World
3+}
docs/dev/index.rstnew file+15
@@ -0,0 +1,15 @@
1+=======================
2+Developer documentation
3+=======================
4+
5+.. toctree::
6+ :maxdepth: 1
7+
8+ quickstart
9+ contribution_guide
10+ engine_overview
11+ search_api
12+ plugins
13+ translation
14+ makefile
15+ reST
docs/dev/makefile.rstnew file+221
@@ -0,0 +1,221 @@
1+.. _makefile:
2+
3+================
4+Makefile Targets
5+================
6+
7+.. _gnu-make: https://www.gnu.org/software/make/manual/make.html#Introduction
8+
9+.. sidebar:: build environment
10+
11+ Before looking deeper at the targets, first read about :ref:`makefile setup`
12+ and :ref:`make pyenv`.
13+
14+With the aim to simplify development cycles, started with :pull:`1756` a
15+``Makefile`` based boilerplate was added. If you are not familiar with
16+Makefiles, we recommend to read gnu-make_ introduction.
17+
18+The usage is simple, just type ``make {target-name}`` to *build* a target.
19+Calling the ``help`` target gives a first overview::
20+
21+ $ make help
22+ test - run developer tests
23+ docs - build documentation
24+ docs-live - autobuild HTML documentation while editing
25+ run - run developer instance
26+ install - developer install (./local)
27+ uninstall - uninstall (./local)
28+ gh-pages - build docs & deploy on gh-pages branch
29+ clean - drop builds and environments
30+ ...
31+
32+.. contents:: Contents
33+ :depth: 2
34+ :local:
35+ :backlinks: entry
36+
37+
38+.. _makefile setup:
39+
40+Setup
41+=====
42+
43+.. _git stash: https://git-scm.com/docs/git-stash
44+
45+The main setup is done in the :origin:`Makefile`::
46+
47+ export GIT_URL=https://github.com/asciimoo/searx
48+ export SEARX_URL=https://searx.me
49+ export DOCS_URL=https://asciimoo.github.io/searx
50+
51+.. sidebar:: fork & upstream
52+
53+ Commit changes in your (local) branch, fork or whatever, but do not push them
54+ upstream / `git stash`_ is your friend.
55+
56+:GIT_URL: Changes this, to point to your searx fork.
57+
58+:SEARX_URL: Changes this, to point to your searx instance.
59+
60+:DOCS_URL: If you host your own (branded) documentation, change this URL.
61+
62+.. _make pyenv:
63+
64+Python environment
65+==================
66+
67+.. sidebar:: activate environment
68+
69+ ``source ./local/py3/bin/activate``
70+
71+With Makefile we do no longer need to build up the virualenv manually (as
72+described in the :ref:`devquickstart` guide). Jump into your git working tree
73+and release a ``make pyenv``:
74+
75+.. code:: sh
76+
77+ $ cd ~/searx-clone
78+ $ make pyenv
79+ PYENV usage: source ./local/py3/bin/activate
80+ ...
81+
82+With target ``pyenv`` a development environment (aka virtualenv) was build up in
83+``./local/py3/``. To make a *developer install* of searx (:origin:`setup.py`)
84+into this environment, use make target ``install``:
85+
86+.. code:: sh
87+
88+ $ make install
89+ PYENV usage: source ./local/py3/bin/activate
90+ PYENV using virtualenv from ./local/py3
91+ PYENV install .
92+
93+You have never to think about intermediate targets like ``pyenv`` or
94+``install``, the ``Makefile`` chains them as requisites. Just run your main
95+target.
96+
97+.. sidebar:: drop environment
98+
99+ To get rid of the existing environment before re-build use :ref:`clean target
100+ <make clean>` first.
101+
102+If you think, something goes wrong with your ./local environment or you change
103+the :origin:`setup.py` file (or the requirements listed in
104+:origin:`requirements-dev.txt` and :origin:`requirements.txt`), you have to call
105+:ref:`make clean`.
106+
107+
108+.. _make run:
109+
110+``make run``
111+============
112+
113+To get up a running a developer instance simply call ``make run``. This enables
114+*debug* option in :origin:`searx/settings.yml`, starts a ``./searx/webapp.py``
115+instance, disables *debug* option again and opens the URL in your favorite WEB
116+browser (:man:`xdg-open`):
117+
118+.. code:: sh
119+
120+ $ make run
121+ PYENV usage: source ./local/py3/bin/activate
122+ PYENV install .
123+ ./local/py3/bin/python ./searx/webapp.py
124+ ...
125+ INFO:werkzeug: * Running on http://127.0.0.1:8888/ (Press CTRL+C to quit)
126+ ...
127+
128+.. _make clean:
129+
130+``make clean``
131+==============
132+
133+Drop all intermediate files, all builds, but keep sources untouched. Includes
134+target ``pyclean`` which drops ./local environment. Before calling ``make
135+clean`` stop all processes using :ref:`make pyenv`.
136+
137+.. code:: sh
138+
139+ $ make clean
140+ CLEAN pyclean
141+ CLEAN clean
142+
143+.. _make docs:
144+
145+``make docs docs-live docs-clean``
146+==================================
147+
148+We describe the usage of the ``doc*`` targets in the :ref:`How to contribute /
149+Documentation <contrib docs>` section. If you want to edit the documentation
150+read our :ref:`make docs-live` section. If you are working in your own brand,
151+adjust your :ref:`Makefile setup <makefile setup>`.
152+
153+
154+.. _make gh-pages:
155+
156+``make gh-pages``
157+=================
158+
159+To deploy on github.io first adjust your :ref:`Makefile setup <makefile
160+setup>`. For any further read :ref:`deploy on github.io`.
161+
162+.. _make test:
163+
164+``make test``
165+=============
166+
167+Runs a series of tests: ``test.pep8``, ``test.unit``, ``test.robot`` and does
168+additional :ref:`pylint checks <make pylint>`. You can run tests selective,
169+e.g.:
170+
171+.. code:: sh
172+
173+ $ make test.pep8 test.unit
174+ . ./local/py3/bin/activate; ./manage.sh pep8_check
175+ [!] Running pep8 check
176+ . ./local/py3/bin/activate; ./manage.sh unit_tests
177+ [!] Running unit tests
178+
179+.. _make pylint:
180+
181+``make pylint``
182+===============
183+
184+.. _Pylint: https://www.pylint.org/
185+
186+Before commiting its recommend to do some (more) linting. Pylint_ is known as
187+one of the best source-code, bug and quality checker for the Python programming
188+language. Pylint_ is not yet a quality gate within our searx project (like
189+:ref:`test.pep8 <make test>` it is), but Pylint_ can help to improve code
190+quality anyway. The pylint profile we use at searx project is found in
191+project's root folder :origin:`.pylintrc`.
192+
193+Code quality is a ongoing process. Don't try to fix all messages from Pylint,
194+run Pylint and check if your changed lines are bringing up new messages. If so,
195+fix it. By this, code quality gets incremental better and if there comes the
196+day, the linting is balanced out, we might decide to add Pylint as a quality
197+gate.
198+
199+
200+``make pybuild``
201+================
202+
203+.. _PyPi: https://pypi.org/
204+.. _twine: https://twine.readthedocs.io/en/latest/
205+
206+Build Python packages in ``./dist/py``.
207+
208+.. code:: sh
209+
210+ $ make pybuild
211+ ...
212+ BUILD pybuild
213+ running sdist
214+ running egg_info
215+ ...
216+ $ ls ./dist/py/
217+ searx-0.15.0-py3-none-any.whl searx-0.15.0.tar.gz
218+
219+To upload packages to PyPi_, there is also a ``upload-pypi`` target. It needs
220+twine_ to be installed. Since you are not the owner of :pypi:`searx` you will
221+never need the latter.
docs/dev/plugins.rstnew file+54
@@ -0,0 +1,54 @@
1+.. _dev plugin:
2+
3+=======
4+Plugins
5+=======
6+
7+.. sidebar:: Further reading ..
8+
9+ - :ref:`plugins generic`
10+
11+Plugins can extend or replace functionality of various components of searx.
12+
13+Example plugin
14+==============
15+
16+.. code:: python
17+
18+ name = 'Example plugin'
19+ description = 'This plugin extends the suggestions with the word "example"'
20+ default_on = False # disabled by default
21+
22+ js_dependencies = tuple() # optional, list of static js files
23+ css_dependencies = tuple() # optional, list of static css files
24+
25+
26+ # attach callback to the post search hook
27+ # request: flask request object
28+ # ctx: the whole local context of the post search hook
29+ def post_search(request, ctx):
30+ ctx['search'].suggestions.add('example')
31+ return True
32+
33+Plugin entry points
34+===================
35+
36+Entry points (hooks) define when a plugin runs. Right now only three hooks are
37+implemented. So feel free to implement a hook if it fits the behaviour of your
38+plugin.
39+
40+Pre search hook
41+---------------
42+
43+Runs BEFORE the search request. Function to implement: ``pre_search``
44+
45+Post search hook
46+----------------
47+
48+Runs AFTER the search request. Function to implement: ``post_search``
49+
50+Result hook
51+-----------
52+
53+Runs when a new result is added to the result list. Function to implement:
54+``on_result``
docs/dev/quickstart.rstnew file+132
@@ -0,0 +1,132 @@
1+.. _devquickstart:
2+
3+======================
4+Development Quickstart
5+======================
6+
7+.. sidebar:: :ref:`makefile`
8+
9+ For additional developer purpose there are :ref:`makefile`.
10+
11+This quickstart guide gets your environment set up with searx. Furthermore, it
12+gives a short introduction to the ``manage.sh`` script.
13+
14+How to setup your development environment
15+=========================================
16+
17+.. sidebar:: :ref:`make pyenv <make pyenv>`
18+
19+ Alternatively use the :ref:`make pyenv`.
20+
21+First, clone the source code of searx to the desired folder. In this case the
22+source is cloned to ``~/myprojects/searx``. Then create and activate the
23+searx-ve virtualenv and install the required packages using ``manage.sh``.
24+
25+.. code:: sh
26+
27+ cd ~/myprojects
28+ git clone https://github.com/asciimoo/searx.git
29+ cd searx
30+ virtualenv searx-ve
31+ . ./searx-ve/bin/activate
32+ ./manage.sh update_dev_packages
33+
34+
35+How to run tests
36+================
37+
38+.. sidebar:: :ref:`make test.unit <make test>`
39+
40+ Alternatively use the ``test.pep8``, ``test.unit``, ``test.robot`` targets.
41+
42+Tests can be run using the ``manage.sh`` script. Following tests and checks are
43+available:
44+
45+- Unit tests
46+- Selenium tests
47+- PEP8 validation
48+- Unit test coverage check
49+
50+For example unit tests are run with the command below:
51+
52+.. code:: sh
53+
54+ ./manage.sh unit_tests
55+
56+For further test options, please consult the help of the ``manage.sh`` script or
57+read :ref:`make test`.
58+
59+
60+How to compile styles and javascript
61+====================================
62+
63+.. _less: http://lesscss.org/
64+.. _NodeJS: https://nodejs.org
65+
66+How to build styles
67+-------------------
68+
69+Less_ is required to build the styles of searx. Less_ can be installed using
70+either NodeJS_ or Apt.
71+
72+.. code:: sh
73+
74+ sudo -H apt-get install nodejs
75+ sudo -H npm install -g less
76+
77+OR
78+
79+.. code:: sh
80+
81+ sudo -H apt-get install node-less
82+
83+After satisfying the requirements styles can be build using ``manage.sh``
84+
85+.. code:: sh
86+
87+ ./manage.sh styles
88+
89+
90+How to build the source of the oscar theme
91+==========================================
92+
93+.. _grunt: https://gruntjs.com/
94+
95+Grunt_ must be installed in order to build the javascript sources. It depends on
96+NodeJS, so first Node has to be installed.
97+
98+.. code:: sh
99+
100+ sudo -H apt-get install nodejs
101+ sudo -H npm install -g grunt-cli
102+
103+After installing grunt, the files can be built using the following command:
104+
105+.. code:: sh
106+
107+ ./manage.sh grunt_build
108+
109+
110+Tips for debugging/development
111+==============================
112+
113+.. sidebar:: :ref:`make run`
114+
115+ Makefile target ``run`` already enables debug option for your developer
116+ session / see :ref:`make run`.
117+
118+Turn on debug logging
119+ Whether you are working on a new engine or trying to eliminate a bug, it is
120+ always a good idea to turn on debug logging. When debug logging is enabled a
121+ stack trace appears, instead of the cryptic ``Internal Server Error``
122+ message. It can be turned on by setting ``debug: False`` to ``debug: True`` in
123+ :origin:`settings.yml <searx/settings.yml>`.
124+
125+.. sidebar:: :ref:`make test`
126+
127+ Alternatively use the :ref:`make test` targets.
128+
129+Run ``./manage.sh tests`` before creating a PR.
130+ Failing build on Travis is common because of PEP8 checks. So a new commit
131+ must be created containing these format fixes. This phase can be skipped if
132+ ``./manage.sh tests`` is run locally before creating a PR.
docs/dev/reST.rstnew file+1428
@@ -0,0 +1,1428 @@
1+.. _reST primer:
2+
3+===========
4+reST primer
5+===========
6+
7+.. sidebar:: KISS_ and readability_
8+
9+ Instead of defining more and more roles, we at searx encourage our
10+ contributors to follow principles like KISS_ and readability_.
11+
12+We at searx are using reStructuredText (aka reST_) markup for all kind of
13+documentation, with the builders from the Sphinx_ project a HTML output is
14+generated and deployed at :docs:`github.io <.>`. For build prerequisites read
15+:ref:`docs build`.
16+
17+The source files of Searx's documentation are located at :origin:`docs`. Sphinx
18+assumes source files to be encoded in UTF-8 by defaul. Run :ref:`make docs-live
19+<make docs-live>` to build HTML while editing.
20+
21+.. sidebar:: Further reading
22+
23+ - Sphinx-Primer_
24+ - `Sphinx markup constructs`_
25+ - reST_, docutils_, `docutils FAQ`_
26+ - Sphinx_, `sphinx-doc FAQ`_
27+ - `sphinx config`_, doctree_
28+ - `sphinx cross references`_
29+ - linuxdoc_
30+ - intersphinx_
31+ - sphinx-jinja_
32+ - `Sphinx's autodoc`_
33+ - `Sphinx's Python domain`_, `Sphinx's C domain`_
34+ - SVG_, ImageMagick_
35+ - DOT_, `Graphviz's dot`_, Graphviz_
36+
37+
38+.. contents:: Contents
39+ :depth: 3
40+ :local:
41+ :backlinks: entry
42+
43+Sphinx_ and reST_ have their place in the python ecosystem. Over that reST is
44+used in popular projects, e.g the Linux kernel documentation `[kernel doc]`_.
45+
46+.. _[kernel doc]: https://www.kernel.org/doc/html/latest/doc-guide/sphinx.html
47+
48+.. sidebar:: Content matters
49+
50+ The readability_ of the reST sources has its value, therefore we recommend to
51+ make sparse usage of reST markup / .. content matters!
52+
53+**reST** is a plaintext markup language, its markup is *mostly* intuitive and
54+you will not need to learn much to produce well formed articles with. I use the
55+word *mostly*: like everything in live, reST has its advantages and
56+disadvantages, some markups feel a bit grumpy (especially if you are used to
57+other plaintext markups).
58+
59+Soft skills
60+===========
61+
62+Before going any deeper into the markup let's face on some **soft skills** a
63+trained author brings with, to reach a well feedback from readers:
64+
65+- Documentation is dedicated to an audience and answers questions from the
66+ audience point of view.
67+- Don't detail things which are general knowledge from the audience point of
68+ view.
69+- Limit the subject, use cross links for any further reading.
70+
71+To be more concrete what a *point of view* means. In the (:origin:`docs`)
72+folder we have three sections (and the *blog* folder), each dedicate to a
73+different group of audience.
74+
75+User's POV: :origin:`docs/user`
76+ A typical user knows about search engines and might have heard about
77+ meta crawlers and privacy.
78+
79+Admin's POV: :origin:`docs/admin`
80+ A typical Admin knows about setting up services on a linux system, but he does
81+ not know all the pros and cons of a searx setup.
82+
83+Developer's POV: :origin:`docs/dev`
84+ Depending on the readability_ of code, a typical developer is able to read and
85+ understand source code. Describe what a item aims to do (e.g. a function).
86+ If the chronological order matters, describe it. Name the *out-of-limits
87+ conditions* and all the side effects a external developer will not know.
88+
89+.. _reST inline markup:
90+
91+Basic inline markup
92+===================
93+
94+.. sidebar:: Inline markup
95+
96+ - :ref:`reST roles`
97+ - :ref:`reST smart ref`
98+
99+Basic inline markup is done with asterisks and backquotes. If asterisks or
100+backquotes appear in running text and could be confused with inline markup
101+delimiters, they have to be escaped with a backslash (``\*pointer``).
102+
103+.. table:: basic inline markup
104+ :widths: 4 3 7
105+
106+ ================================================ ==================== ========================
107+ description rendered markup
108+ ================================================ ==================== ========================
109+ one asterisk for emphasis *italics* ``*italics*``
110+ two asterisks for strong emphasis **boldface** ``**boldface**``
111+ backquotes for code samples and literals ``foo()`` ````foo()````
112+ quote asterisks or backquotes \*foo is a pointer ``\*foo is a pointer``
113+ ================================================ ==================== ========================
114+
115+.. _reST basic structure:
116+
117+Basic article structure
118+=======================
119+
120+The basic structure of an article makes use of heading adornments to markup
121+chapter, sections and subsections.
122+
123+.. _reST template:
124+
125+reST template
126+-------------
127+
128+reST template for an simple article:
129+
130+.. code:: reST
131+
132+ .. _doc refname:
133+
134+ ==============
135+ Document title
136+ ==============
137+
138+ Lorem ipsum dolor sit amet, consectetur adipisici elit .. Further read
139+ :ref:`chapter refname`.
140+
141+ .. _chapter refname:
142+
143+ Chapter
144+ =======
145+
146+ Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
147+ aliquid ex ea commodi consequat ...
148+
149+ .. _section refname:
150+
151+ Section
152+ -------
153+
154+ lorem ..
155+
156+ .. _subsection refname:
157+
158+ Subsection
159+ ~~~~~~~~~~
160+
161+ lorem ..
162+
163+
164+Headings
165+--------
166+
167+#. title - with overline for document title:
168+
169+ .. code:: reST
170+
171+ ==============
172+ Document title
173+ ==============
174+
175+
176+#. chapter - with anchor named ``anchor name``:
177+
178+ .. code:: reST
179+
180+ .. _anchor name:
181+
182+ Chapter
183+ =======
184+
185+#. section
186+
187+ .. code:: reST
188+
189+ Section
190+ -------
191+
192+#. subsection
193+
194+ .. code:: reST
195+
196+ Subsection
197+ ~~~~~~~~~~
198+
199+
200+
201+Anchors & Links
202+===============
203+
204+.. _reST anchor:
205+
206+Anchors
207+-------
208+
209+.. _ref role:
210+ https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-ref
211+
212+To refer a point in the documentation a anchor is needed. The :ref:`reST
213+template <reST template>` shows an example where a chapter titled *"Chapters"*
214+gets an anchor named ``chapter title``. Another example from *this* document,
215+where the anchor named ``reST anchor``:
216+
217+.. code:: reST
218+
219+ .. _reST anchor:
220+
221+ Anchors
222+ -------
223+
224+ To refer a point in the documentation a anchor is needed ...
225+
226+To refer anchors use the `ref role`_ markup:
227+
228+.. code:: reST
229+
230+ Visit chapter :ref:`reST anchor`. Or set hyperlink text manualy :ref:`foo
231+ bar <reST anchor>`.
232+
233+.. admonition:: ``:ref:`` role
234+ :class: rst-example
235+
236+ Visist chapter :ref:`reST anchor`. Or set hyperlink text manualy :ref:`foo
237+ bar <reST anchor>`.
238+
239+.. _reST ordinary ref:
240+
241+Link ordinary URL
242+-----------------
243+
244+If you need to reference external URLs use *named* hyperlinks to maintain
245+readability of reST sources. Here is a example taken from *this* article:
246+
247+.. code:: reST
248+
249+ .. _Sphinx Field Lists:
250+ https://www.sphinx-doc.org/en/master/usage/restructuredtext/field-lists.html
251+
252+ With the *named* hyperlink `Sphinx Field Lists`_, the raw text is much more
253+ readable.
254+
255+ And this shows the alternative (less readable) hyperlink markup `Sphinx Field
256+ Lists
257+ <https://www.sphinx-doc.org/en/master/usage/restructuredtext/field-lists.html>`__.
258+
259+.. admonition:: Named hyperlink
260+ :class: rst-example
261+
262+ With the *named* hyperlink `Sphinx Field Lists`_, the raw text is much more
263+ readable.
264+
265+ And this shows the alternative (less readable) hyperlink markup `Sphinx Field
266+ Lists
267+ <https://www.sphinx-doc.org/en/master/usage/restructuredtext/field-lists.html>`__.
268+
269+
270+.. _reST smart ref:
271+
272+Smart refs
273+----------
274+
275+With the power of sphinx.ext.extlinks_ and intersphinx_ referencing external
276+content becomes smart.
277+
278+.. table:: smart refs with sphinx.ext.extlinks_ and intersphinx_
279+ :widths: 4 3 7
280+
281+ ========================== ================================== ====================================
282+ refer ... rendered example markup
283+ ========================== ================================== ====================================
284+ :rst:role:`rfc` :rfc:`822` ``:rfc:`822```
285+ :rst:role:`pep` :pep:`8` ``:pep:`8```
286+ sphinx.ext.extlinks_
287+ --------------------------------------------------------------------------------------------------
288+ project's wiki article :wiki:`Searx-instances` ``:wiki:`Searx-instances```
289+ to docs public URL :docs:`dev/reST.html` ``:docs:`dev/reST.html```
290+ files & folders origin :origin:`docs/dev/reST.rst` ``:origin:`docs/dev/reST.rst```
291+ pull request :pull:`1756` ``:pull:`1756```
292+ patch :patch:`af2cae6` ``:patch:`af2cae6```
293+ PyPi package :pypi:`searx` ``:pypi:`searx```
294+ manual page man :man:`bash` ``:man:`bash```
295+ intersphinx_
296+ --------------------------------------------------------------------------------------------------
297+ external anchor :ref:`python:and` ``:ref:`python:and```
298+ external doc anchor :doc:`jinja:templates` ``:doc:`jinja:templates```
299+ python code object :py:obj:`datetime.datetime` ``:py:obj:`datetime.datetime```
300+ flask code object :py:obj:`flask.Flask` ``:py:obj:`flask.Flask```
301+ ========================== ================================== ====================================
302+
303+
304+Intersphinx is configured in :origin:`docs/conf.py`:
305+
306+.. code:: python
307+
308+ intersphinx_mapping = {
309+ "python": ("https://docs.python.org/3/", None),
310+ "flask": ("https://flask.palletsprojects.com/", None),
311+ "jinja": ("https://jinja.palletsprojects.com/", None),
312+ "linuxdoc" : ("https://return42.github.io/linuxdoc/", None),
313+ "sphinx" : ("https://www.sphinx-doc.org/en/master/", None),
314+ }
315+
316+
317+To list all anchors of the inventory (e.g. ``python``) use:
318+
319+.. code:: sh
320+
321+ $ python -m sphinx.ext.intersphinx https://docs.python.org/3/objects.inv
322+
323+Literal blocks
324+==============
325+
326+The simplest form of :duref:`literal-blocks` is a indented block introduced by
327+two colons (``::``). For highlighting use :dudir:`highlight` or :ref:`reST
328+code` directive. To include literals from external files use directive
329+:dudir:`literalinclude`.
330+
331+.. _reST literal:
332+
333+``::``
334+------
335+
336+.. code:: reST
337+
338+ ::
339+
340+ Literal block
341+
342+ Lorem ipsum dolor::
343+
344+ Literal block
345+
346+ Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
347+ eirmod tempor invidunt ut labore ::
348+
349+ Literal block
350+
351+.. admonition:: Literal block
352+ :class: rst-example
353+
354+ ::
355+
356+ Literal block
357+
358+ Lorem ipsum dolor::
359+
360+ Literal block
361+
362+ Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
363+ eirmod tempor invidunt ut labore ::
364+
365+ Literal block
366+
367+
368+.. _reST code:
369+
370+``code-block``
371+--------------
372+
373+.. _pygments: https://pygments.org/languages/
374+
375+.. sidebar:: Syntax highlighting
376+
377+ is handled by pygments_.
378+
379+The :rst:dir:`code-block` directive is a variant of the :dudir:`code` directive
380+with additional options. To learn more about code literals visit
381+:ref:`sphinx:code-examples`.
382+
383+.. code-block:: reST
384+
385+ The URL ``/stats`` handle is shown in :ref:`stats-handle`
386+
387+ .. code-block:: Python
388+ :caption: python code block
389+ :name: stats-handle
390+
391+ @app.route('/stats', methods=['GET'])
392+ def stats():
393+ """Render engine statistics page."""
394+ stats = get_engines_stats()
395+ return render(
396+ 'stats.html'
397+ , stats = stats )
398+
399+.. code-block:: reST
400+
401+.. admonition:: Code block
402+ :class: rst-example
403+
404+ The URL ``/stats`` handle is shown in :ref:`stats-handle`
405+
406+ .. code-block:: Python
407+ :caption: python code block
408+ :name: stats-handle
409+
410+ @app.route('/stats', methods=['GET'])
411+ def stats():
412+ """Render engine statistics page."""
413+ stats = get_engines_stats()
414+ return render(
415+ 'stats.html'
416+ , stats = stats )
417+
418+Unicode substitution
419+====================
420+
421+The :dudir:`unicode directive <unicode-character-codes>` converts Unicode
422+character codes (numerical values) to characters. This directive can only be
423+used within a substitution definition.
424+
425+.. code-block:: reST
426+
427+ .. |copy| unicode:: 0xA9 .. copyright sign
428+ .. |(TM)| unicode:: U+2122
429+
430+ Trademark |(TM)| and copyright |copy| glyphs.
431+
432+.. admonition:: Unicode
433+ :class: rst-example
434+
435+ .. |copy| unicode:: 0xA9 .. copyright sign
436+ .. |(TM)| unicode:: U+2122
437+
438+ Trademark |(TM)| and copyright |copy| glyphs.
439+
440+
441+.. _reST roles:
442+
443+Roles
444+=====
445+
446+.. sidebar:: Further reading
447+
448+ - `Sphinx Roles`_
449+ - :doc:`sphinx:usage/restructuredtext/domains`
450+
451+
452+A *custom interpreted text role* (:duref:`ref <roles>`) is an inline piece of
453+explicit markup. It signifies that that the enclosed text should be interpreted
454+in a specific way.
455+
456+The general markup is one of:
457+
458+.. code:: reST
459+
460+ :rolename:`ref-name`
461+ :rolename:`ref text <ref-name>`
462+
463+.. table:: smart refs with sphinx.ext.extlinks_ and intersphinx_
464+ :widths: 4 3 7
465+
466+ ========================== ================================== ====================================
467+ role rendered example markup
468+ ========================== ================================== ====================================
469+ :rst:role:`guilabel` :guilabel:`&Cancel` ``:guilabel:`&Cancel```
470+ :rst:role:`kbd` :kbd:`C-x C-f` ``:kbd:`C-x C-f```
471+ :rst:role:`menuselection` :menuselection:`Open --> File` ``:menuselection:`Open --> File```
472+ :rst:role:`download` :download:`this file <reST.rst>` ``:download:`this file <reST.rst>```
473+ math_ :math:`a^2 + b^2 = c^2` ``:math:`a^2 + b^2 = c^2```
474+ :rst:role:`ref` :ref:`svg image example` ``:ref:`svg image example```
475+ :rst:role:`command` :command:`ls -la` ``:command:`ls -la```
476+ :durole:`emphasis` :emphasis:`italic` ``:emphasis:`italic```
477+ :durole:`strong` :strong:`bold` ``:strong:`bold```
478+ :durole:`literal` :literal:`foo()` ``:literal:`foo()```
479+ :durole:`subscript` H\ :sub:`2`\ O ``H\ :sub:`2`\ O``
480+ :durole:`superscript` E = mc\ :sup:`2` ``E = mc\ :sup:`2```
481+ :durole:`title-reference` :title:`Time` ``:title:`Time```
482+ ========================== ================================== ====================================
483+
484+Figures & Images
485+================
486+
487+.. sidebar:: Image processing
488+
489+ With the directives from :ref:`linuxdoc <linuxdoc:kfigure>` the build process
490+ is flexible. To get best results in the generated output format, install
491+ ImageMagick_ and Graphviz_.
492+
493+Searx's sphinx setup includes: :ref:`linuxdoc:kfigure`. Scaleable here means;
494+scaleable in sense of the build process. Normally in absence of a converter
495+tool, the build process will break. From the authors POV it’s annoying to care
496+about the build process when handling with images, especially since he has no
497+access to the build process. With :ref:`linuxdoc:kfigure` the build process
498+continues and scales output quality in dependence of installed image processors.
499+
500+If you want to add an image, you should use the ``kernel-figure`` (inheritance
501+of :dudir:`figure`) and ``kernel-image`` (inheritance of :dudir:`image`)
502+directives. E.g. to insert a figure with a scaleable image format use SVG
503+(:ref:`svg image example`):
504+
505+.. code:: reST
506+
507+ .. _svg image example:
508+
509+ .. kernel-figure:: svg_image.svg
510+ :alt: SVG image example
511+
512+ Simple SVG image
513+
514+ To refer the figure, a caption block is needed: :ref:`svg image example`.
515+
516+.. _svg image example:
517+
518+.. kernel-figure:: svg_image.svg
519+ :alt: SVG image example
520+
521+ Simple SVG image.
522+
523+To refer the figure, a caption block is needed: :ref:`svg image example`.
524+
525+DOT files (aka Graphviz)
526+------------------------
527+
528+With :ref:`linuxdoc:kernel-figure` reST support for **DOT** formatted files is
529+given.
530+
531+- `Graphviz's dot`_
532+- DOT_
533+- Graphviz_
534+
535+A simple example is shown in :ref:`dot file example`:
536+
537+.. code:: reST
538+
539+ .. _dot file example:
540+
541+ .. kernel-figure:: hello.dot
542+ :alt: hello world
543+
544+ DOT's hello world example
545+
546+.. admonition:: hello.dot
547+ :class: rst-example
548+
549+ .. _dot file example:
550+
551+ .. kernel-figure:: hello.dot
552+ :alt: hello world
553+
554+ DOT's hello world example
555+
556+``kernel-render`` DOT
557+---------------------
558+
559+Embed *render* markups (or languages) like Graphviz's **DOT** is provided by the
560+:ref:`linuxdoc:kernel-render` directive. A simple example of embedded DOT_ is
561+shown in figure :ref:`dot render example`:
562+
563+.. code:: reST
564+
565+ .. _dot render example:
566+
567+ .. kernel-render:: DOT
568+ :alt: digraph
569+ :caption: Embedded DOT (Graphviz) code
570+
571+ digraph foo {
572+ "bar" -> "baz";
573+ }
574+
575+ Attribute ``caption`` is needed, if you want to refer the figure: :ref:`dot
576+ render example`.
577+
578+Please note :ref:`build tools <linuxdoc:kfigure_build_tools>`. If Graphviz_ is
579+installed, you will see an vector image. If not, the raw markup is inserted as
580+*literal-block*.
581+
582+.. admonition:: kernel-render DOT
583+ :class: rst-example
584+
585+ .. _dot render example:
586+
587+ .. kernel-render:: DOT
588+ :alt: digraph
589+ :caption: Embedded DOT (Graphviz) code
590+
591+ digraph foo {
592+ "bar" -> "baz";
593+ }
594+
595+ Attribute ``caption`` is needed, if you want to refer the figure: :ref:`dot
596+ render example`.
597+
598+``kernel-render`` SVG
599+---------------------
600+
601+A simple example of embedded SVG_ is shown in figure :ref:`svg render example`:
602+
603+.. code:: reST
604+
605+ .. _svg render example:
606+
607+ .. kernel-render:: SVG
608+ :caption: Embedded **SVG** markup
609+ :alt: so-nw-arrow
610+..
611+
612+ .. code:: xml
613+
614+ <?xml version="1.0" encoding="UTF-8"?>
615+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1"
616+ baseProfile="full" width="70px" height="40px"
617+ viewBox="0 0 700 400"
618+ >
619+ <line x1="180" y1="370"
620+ x2="500" y2="50"
621+ stroke="black" stroke-width="15px"
622+ />
623+ <polygon points="585 0 525 25 585 50"
624+ transform="rotate(135 525 25)"
625+ />
626+ </svg>
627+
628+.. admonition:: kernel-render SVG
629+ :class: rst-example
630+
631+ .. _svg render example:
632+
633+ .. kernel-render:: SVG
634+ :caption: Embedded **SVG** markup
635+ :alt: so-nw-arrow
636+
637+ <?xml version="1.0" encoding="UTF-8"?>
638+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1"
639+ baseProfile="full" width="70px" height="40px"
640+ viewBox="0 0 700 400"
641+ >
642+ <line x1="180" y1="370"
643+ x2="500" y2="50"
644+ stroke="black" stroke-width="15px"
645+ />
646+ <polygon points="585 0 525 25 585 50"
647+ transform="rotate(135 525 25)"
648+ />
649+ </svg>
650+
651+
652+
653+
654+.. _reST lists:
655+
656+List markups
657+============
658+
659+Bullet list
660+-----------
661+
662+List markup (:duref:`ref <bullet-lists>`) is simple:
663+
664+.. code:: reST
665+
666+ - This is a bulleted list.
667+
668+ 1. Nested lists are possible, but be aware that they must be separated from
669+ the parent list items by blank line
670+ 2. Second item of nested list
671+
672+ - It has two items, the second
673+ item uses two lines.
674+
675+ #. This is a numbered list.
676+ #. It has two items too.
677+
678+.. admonition:: bullet list
679+ :class: rst-example
680+
681+ - This is a bulleted list.
682+
683+ 1. Nested lists are possible, but be aware that they must be separated from
684+ the parent list items by blank line
685+ 2. Second item of nested list
686+
687+ - It has two items, the second
688+ item uses two lines.
689+
690+ #. This is a numbered list.
691+ #. It has two items too.
692+
693+
694+Horizontal list
695+---------------
696+
697+The :rst:dir:`.. hlist:: <hlist>` transforms a bullet list into a more compact
698+list.
699+
700+.. code:: reST
701+
702+ .. hlist::
703+
704+ - first list item
705+ - second list item
706+ - third list item
707+ ...
708+
709+.. admonition:: hlist
710+ :class: rst-example
711+
712+ .. hlist::
713+
714+ - first list item
715+ - second list item
716+ - third list item
717+ - next list item
718+ - next list item xxxx
719+ - next list item yyyy
720+ - next list item zzzz
721+
722+
723+Definition list
724+---------------
725+
726+.. sidebar:: Note ..
727+
728+ - the term cannot have more than one line of text
729+
730+ - there is **no blank line between term and definition block** // this
731+ distinguishes definition lists (:duref:`ref <definition-lists>`) from block
732+ quotes (:duref:`ref <block-quotes>`).
733+
734+Each definition list (:duref:`ref <definition-lists>`) item contains a term,
735+optional classifiers and a definition. A term is a simple one-line word or
736+phrase. Optional classifiers may follow the term on the same line, each after
737+an inline ' : ' (**space, colon, space**). A definition is a block indented
738+relative to the term, and may contain multiple paragraphs and other body
739+elements. There may be no blank line between a term line and a definition block
740+(*this distinguishes definition lists from block quotes*). Blank lines are
741+required before the first and after the last definition list item, but are
742+optional in-between.
743+
744+Definition lists are created as follows:
745+
746+.. code:: reST
747+
748+ term 1 (up to a line of text)
749+ Definition 1.
750+
751+ See the typo : this line is not a term!
752+
753+ And this is not term's definition. **There is a blank line** in between
754+ the line above and this paragraph. That's why this paragraph is taken as
755+ **block quote** (:duref:`ref <block-quotes>`) and not as term's definition!
756+
757+ term 2
758+ Definition 2, paragraph 1.
759+
760+ Definition 2, paragraph 2.
761+
762+ term 3 : classifier
763+ Definition 3.
764+
765+ term 4 : classifier one : classifier two
766+ Definition 4.
767+
768+.. admonition:: definition list
769+ :class: rst-example
770+
771+ term 1 (up to a line of text)
772+ Definition 1.
773+
774+ See the typo : this line is not a term!
775+
776+ And this is not term's definition. **There is a blank line** in between
777+ the line above and this paragraph. That's why this paragraph is taken as
778+ **block quote** (:duref:`ref <block-quotes>`) and not as term's definition!
779+
780+
781+ term 2
782+ Definition 2, paragraph 1.
783+
784+ Definition 2, paragraph 2.
785+
786+ term 3 : classifier
787+ Definition 3.
788+
789+ term 4 : classifier one : classifier two
790+
791+
792+Quoted paragraphs
793+-----------------
794+
795+Quoted paragraphs (:duref:`ref <block-quotes>`) are created by just indenting
796+them more than the surrounding paragraphs. Line blocks (:duref:`ref
797+<line-blocks>`) are a way of preserving line breaks:
798+
799+.. code:: reST
800+
801+ normal paragraph ...
802+ lorem ipsum.
803+
804+ Quoted paragraph ...
805+ lorem ipsum.
806+
807+ | These lines are
808+ | broken exactly like in
809+ | the source file.
810+
811+
812+.. admonition:: Quoted paragraph and line block
813+ :class: rst-example
814+
815+ normal paragraph ...
816+ lorem ipsum.
817+
818+ Quoted paragraph ...
819+ lorem ipsum.
820+
821+ | These lines are
822+ | broken exactly like in
823+ | the source file.
824+
825+
826+.. _reST field list:
827+
828+Field Lists
829+-----------
830+
831+.. _Sphinx Field Lists:
832+ https://www.sphinx-doc.org/en/master/usage/restructuredtext/field-lists.html
833+
834+.. sidebar:: bibliographic fields
835+
836+ First lines fields are bibliographic fields, see `Sphinx Field Lists`_.
837+
838+Field lists are used as part of an extension syntax, such as options for
839+directives, or database-like records meant for further processing. Field lists
840+are mappings from field names to field bodies. They marked up like this:
841+
842+.. code:: reST
843+
844+ :fieldname: Field content
845+ :foo: first paragraph in field foo
846+
847+ second paragraph in field foo
848+
849+ :bar: Field content
850+
851+.. admonition:: Field List
852+ :class: rst-example
853+
854+ :fieldname: Field content
855+ :foo: first paragraph in field foo
856+
857+ second paragraph in field foo
858+
859+ :bar: Field content
860+
861+
862+They are commonly used in Python documentation:
863+
864+.. code:: python
865+
866+ def my_function(my_arg, my_other_arg):
867+ """A function just for me.
868+
869+ :param my_arg: The first of my arguments.
870+ :param my_other_arg: The second of my arguments.
871+
872+ :returns: A message (just for me, of course).
873+ """
874+
875+Further list blocks
876+-------------------
877+
878+- field lists (:duref:`ref <field-lists>`, with caveats noted in
879+ :ref:`reST field list`)
880+- option lists (:duref:`ref <option-lists>`)
881+- quoted literal blocks (:duref:`ref <quoted-literal-blocks>`)
882+- doctest blocks (:duref:`ref <doctest-blocks>`)
883+
884+
885+Admonitions
886+===========
887+
888+Sidebar
889+-------
890+
891+Sidebar is an eye catcher, often used for admonitions pointing further stuff or
892+site effects. Here is the source of the sidebar :ref:`on top of this page <reST
893+primer>`.
894+
895+.. code:: reST
896+
897+ .. sidebar:: KISS_ and readability_
898+
899+ Instead of defining more and more roles, we at searx encourage our
900+ contributors to follow principles like KISS_ and readability_.
901+
902+Generic admonition
903+------------------
904+
905+The generic :dudir:`admonition <admonitions>` needs a title:
906+
907+.. code:: reST
908+
909+ .. admonition:: generic admonition title
910+
911+ lorem ipsum ..
912+
913+
914+.. admonition:: generic admonition title
915+
916+ lorem ipsum ..
917+
918+
919+Specific admonitions
920+--------------------
921+
922+Specific admonitions: :dudir:`hint`, :dudir:`note`, :dudir:`tip` :dudir:`attention`,
923+:dudir:`caution`, :dudir:`danger`, :dudir:`error`, , :dudir:`important`, and
924+:dudir:`warning` .
925+
926+.. code:: reST
927+
928+ .. hint::
929+
930+ lorem ipsum ..
931+
932+ .. note::
933+
934+ lorem ipsum ..
935+
936+ .. warning::
937+
938+ lorem ipsum ..
939+
940+
941+.. hint::
942+
943+ lorem ipsum ..
944+
945+.. note::
946+
947+ lorem ipsum ..
948+
949+.. tip::
950+
951+ lorem ipsum ..
952+
953+.. attention::
954+
955+ lorem ipsum ..
956+
957+.. caution::
958+
959+ lorem ipsum ..
960+
961+.. danger::
962+
963+ lorem ipsum ..
964+
965+.. important::
966+
967+ lorem ipsum ..
968+
969+.. error::
970+
971+ lorem ipsum ..
972+
973+.. warning::
974+
975+ lorem ipsum ..
976+
977+
978+Tables
979+======
980+
981+.. sidebar:: Nested tables
982+
983+ Nested tables are ugly! Not all builder support nested tables, don't use
984+ them!
985+
986+ASCII-art tables like :ref:`reST simple table` and :ref:`reST grid table` might
987+be comfortable for readers of the text-files, but they have huge disadvantages
988+in the creation and modifying. First, they are hard to edit. Think about
989+adding a row or a column to a ASCII-art table or adding a paragraph in a cell,
990+it is a nightmare on big tables.
991+
992+
993+.. sidebar:: List tables
994+
995+ For meaningful patch and diff use :ref:`reST flat table`.
996+
997+Second the diff of modifying ASCII-art tables is not meaningful, e.g. widening a
998+cell generates a diff in which also changes are included, which are only
999+ascribable to the ASCII-art. Anyway, if you prefer ASCII-art for any reason,
1000+here are some helpers:
1001+
1002+* `Emacs Table Mode`_
1003+* `Online Tables Generator`_
1004+
1005+.. _reST simple table:
1006+
1007+Simple tables
1008+-------------
1009+
1010+:duref:`Simple tables <simple-tables>` allow *colspan* but not *rowspan*. If
1011+your table need some metadata (e.g. a title) you need to add the ``.. table::
1012+directive`` :dudir:`(ref) <table>` in front and place the table in its body:
1013+
1014+.. code:: reST
1015+
1016+ .. table:: foo gate truth table
1017+ :widths: grid
1018+ :align: left
1019+
1020+ ====== ====== ======
1021+ Inputs Output
1022+ ------------- ------
1023+ A B A or B
1024+ ====== ====== ======
1025+ False
1026+ --------------------
1027+ True
1028+ --------------------
1029+ True False True
1030+ (foo)
1031+ ------ ------ ------
1032+ False True
1033+ (foo)
1034+ ====== =============
1035+
1036+.. admonition:: Simple ASCII table
1037+ :class: rst-example
1038+
1039+ .. table:: foo gate truth table
1040+ :widths: grid
1041+ :align: left
1042+
1043+ ====== ====== ======
1044+ Inputs Output
1045+ ------------- ------
1046+ A B A or B
1047+ ====== ====== ======
1048+ False
1049+ --------------------
1050+ True
1051+ --------------------
1052+ True False True
1053+ (foo)
1054+ ------ ------ ------
1055+ False True
1056+ (foo)
1057+ ====== =============
1058+
1059+
1060+
1061+.. _reST grid table:
1062+
1063+Grid tables
1064+-----------
1065+
1066+:duref:`Grid tables <grid-tables>` allow colspan *colspan* and *rowspan*:
1067+
1068+.. code:: reST
1069+
1070+ .. table:: grid table example
1071+ :widths: 1 1 5
1072+
1073+ +------------+------------+-----------+
1074+ | Header 1 | Header 2 | Header 3 |
1075+ +============+============+===========+
1076+ | body row 1 | column 2 | column 3 |
1077+ +------------+------------+-----------+
1078+ | body row 2 | Cells may span columns.|
1079+ +------------+------------+-----------+
1080+ | body row 3 | Cells may | - Cells |
1081+ +------------+ span rows. | - contain |
1082+ | body row 4 | | - blocks. |
1083+ +------------+------------+-----------+
1084+
1085+.. admonition:: ASCII grid table
1086+ :class: rst-example
1087+
1088+ .. table:: grid table example
1089+ :widths: 1 1 5
1090+
1091+ +------------+------------+-----------+
1092+ | Header 1 | Header 2 | Header 3 |
1093+ +============+============+===========+
1094+ | body row 1 | column 2 | column 3 |
1095+ +------------+------------+-----------+
1096+ | body row 2 | Cells may span columns.|
1097+ +------------+------------+-----------+
1098+ | body row 3 | Cells may | - Cells |
1099+ +------------+ span rows. | - contain |
1100+ | body row 4 | | - blocks. |
1101+ +------------+------------+-----------+
1102+
1103+
1104+.. _reST flat table:
1105+
1106+flat-table
1107+----------
1108+
1109+The ``flat-table`` is a further developed variant of the :ref:`list tables
1110+<linuxdoc:list-table-directives>`. It is a double-stage list similar to the
1111+:dudir:`list-table` with some additional features:
1112+
1113+column-span: ``cspan``
1114+ with the role ``cspan`` a cell can be extended through additional columns
1115+
1116+row-span: ``rspan``
1117+ with the role ``rspan`` a cell can be extended through additional rows
1118+
1119+auto-span:
1120+ spans rightmost cell of a table row over the missing cells on the right side
1121+ of that table-row. With Option ``:fill-cells:`` this behavior can changed
1122+ from *auto span* to *auto fill*, which automatically inserts (empty) cells
1123+ instead of spanning the last cell.
1124+
1125+options:
1126+ :header-rows: [int] count of header rows
1127+ :stub-columns: [int] count of stub columns
1128+ :widths: [[int] [int] ... ] widths of columns
1129+ :fill-cells: instead of auto-span missing cells, insert missing cells
1130+
1131+roles:
1132+ :cspan: [int] additional columns (*morecols*)
1133+ :rspan: [int] additional rows (*morerows*)
1134+
1135+The example below shows how to use this markup. The first level of the staged
1136+list is the *table-row*. In the *table-row* there is only one markup allowed,
1137+the list of the cells in this *table-row*. Exception are *comments* ( ``..`` )
1138+and *targets* (e.g. a ref to :ref:`row 2 of table's body <row body 2>`).
1139+
1140+.. code:: reST
1141+
1142+ .. flat-table:: ``flat-table`` example
1143+ :header-rows: 2
1144+ :stub-columns: 1
1145+ :widths: 1 1 1 1 2
1146+
1147+ * - :rspan:`1` head / stub
1148+ - :cspan:`3` head 1.1-4
1149+
1150+ * - head 2.1
1151+ - head 2.2
1152+ - head 2.3
1153+ - head 2.4
1154+
1155+ * .. row body 1 / this is a comment
1156+
1157+ - row 1
1158+ - :rspan:`2` cell 1-3.1
1159+ - cell 1.2
1160+ - cell 1.3
1161+ - cell 1.4
1162+
1163+ * .. Comments and targets are allowed on *table-row* stage.
1164+ .. _`row body 2`:
1165+
1166+ - row 2
1167+ - cell 2.2
1168+ - :rspan:`1` :cspan:`1`
1169+ cell 2.3 with a span over
1170+
1171+ * col 3-4 &
1172+ * row 2-3
1173+
1174+ * - row 3
1175+ - cell 3.2
1176+
1177+ * - row 4
1178+ - cell 4.1
1179+ - cell 4.2
1180+ - cell 4.3
1181+ - cell 4.4
1182+
1183+ * - row 5
1184+ - cell 5.1 with automatic span to rigth end
1185+
1186+ * - row 6
1187+ - cell 6.1
1188+ - ..
1189+
1190+
1191+.. admonition:: List table
1192+ :class: rst-example
1193+
1194+ .. flat-table:: ``flat-table`` example
1195+ :header-rows: 2
1196+ :stub-columns: 1
1197+ :widths: 1 1 1 1 2
1198+
1199+ * - :rspan:`1` head / stub
1200+ - :cspan:`3` head 1.1-4
1201+
1202+ * - head 2.1
1203+ - head 2.2
1204+ - head 2.3
1205+ - head 2.4
1206+
1207+ * .. row body 1 / this is a comment
1208+
1209+ - row 1
1210+ - :rspan:`2` cell 1-3.1
1211+ - cell 1.2
1212+ - cell 1.3
1213+ - cell 1.4
1214+
1215+ * .. Comments and targets are allowed on *table-row* stage.
1216+ .. _`row body 2`:
1217+
1218+ - row 2
1219+ - cell 2.2
1220+ - :rspan:`1` :cspan:`1`
1221+ cell 2.3 with a span over
1222+
1223+ * col 3-4 &
1224+ * row 2-3
1225+
1226+ * - row 3
1227+ - cell 3.2
1228+
1229+ * - row 4
1230+ - cell 4.1
1231+ - cell 4.2
1232+ - cell 4.3
1233+ - cell 4.4
1234+
1235+ * - row 5
1236+ - cell 5.1 with automatic span to rigth end
1237+
1238+ * - row 6
1239+ - cell 6.1
1240+ - ..
1241+
1242+
1243+CSV table
1244+---------
1245+
1246+CSV table might be the choice if you want to include CSV-data from a outstanding
1247+(build) process into your documentation.
1248+
1249+.. code:: reST
1250+
1251+ .. csv-table:: CSV table example
1252+ :header: .. , Column 1, Column 2
1253+ :widths: 2 5 5
1254+ :stub-columns: 1
1255+ :file: csv_table.txt
1256+
1257+Content of file ``csv_table.txt``:
1258+
1259+.. literalinclude:: csv_table.txt
1260+
1261+.. admonition:: CSV table
1262+ :class: rst-example
1263+
1264+ .. csv-table:: CSV table example
1265+ :header: .. , Column 1, Column 2
1266+ :widths: 3 5 5
1267+ :stub-columns: 1
1268+ :file: csv_table.txt
1269+
1270+Templating
1271+==========
1272+
1273+.. sidebar:: Build environment
1274+
1275+ All *generic-doc* tasks are running in the :ref:`build environment <make
1276+ pyenv>`.
1277+
1278+Templating is suitable for documentation which is created generic at the build
1279+time. The sphinx-jinja_ extension evaluates jinja_ templates in the :ref:`build
1280+environment <make pyenv>` (with searx modules installed). We use this e.g. to
1281+build chapter: :ref:`engines generic`. Below the jinja directive from the
1282+:origin:`docs/admin/engines.rst` is shown:
1283+
1284+.. literalinclude:: ../admin/engines.rst
1285+ :language: reST
1286+ :start-after: .. _configured engines:
1287+
1288+The context for the template is selected in the line ``.. jinja:: webapp``. In
1289+sphinx's build configuration (:origin:`docs/conf.py`) the ``webapp`` context
1290+points to the name space of the python module: ``webapp``.
1291+
1292+.. code:: py
1293+
1294+ from searx import webapp
1295+ jinja_contexts = {
1296+ 'webapp': dict(**webapp.__dict__)
1297+ }
1298+
1299+
1300+Tabbed views
1301+============
1302+
1303+.. _sphinx-tabs: https://github.com/djungelorm/sphinx-tabs
1304+.. _basic-tabs: https://github.com/djungelorm/sphinx-tabs#basic-tabs
1305+.. _group-tabs: https://github.com/djungelorm/sphinx-tabs#group-tabs
1306+.. _code-tabs: https://github.com/djungelorm/sphinx-tabs#code-tabs
1307+
1308+With `sphinx-tabs`_ extension we have *tabbed views*. To provide installation
1309+instructions with one tab per distribution we use the `group-tabs`_ directive,
1310+others are basic-tabs_ and code-tabs_. Below a *group-tab* example from
1311+:ref:`docs build` is shown:
1312+
1313+.. literalinclude:: ../admin/buildhosts.rst
1314+ :language: reST
1315+ :start-after: .. _system requirements:
1316+ :end-before: .. _system requirements END:
1317+
1318+
1319+.. _math:
1320+
1321+Math equations
1322+==============
1323+
1324+.. _Mathematics: https://en.wikibooks.org/wiki/LaTeX/Mathematics
1325+.. _amsmath user guide:
1326+ http://vesta.informatik.rwth-aachen.de/ftp/pub/mirror/ctan/macros/latex/required/amsmath/amsldoc.pdf
1327+
1328+.. sidebar:: About LaTeX
1329+
1330+ - `amsmath user guide`_
1331+ - Mathematics_
1332+ - :ref:`docs build`
1333+
1334+The input language for mathematics is LaTeX markup using the :ctan:`amsmath`
1335+package.
1336+
1337+To embed LaTeX markup in reST documents, use role :rst:role:`:math: <math>` for
1338+inline and directive :rst:dir:`.. math:: <math>` for block markup.
1339+
1340+.. code:: reST
1341+
1342+ In :math:numref:`schroedinger general` the time-dependent Schrödinger equation
1343+ is shown.
1344+
1345+ .. math::
1346+ :label: schroedinger general
1347+
1348+ \mathrm{i}\hbar\dfrac{\partial}{\partial t} |\,\psi (t) \rangle =
1349+ \hat{H} |\,\psi (t) \rangle.
1350+
1351+.. admonition:: LaTeX math equation
1352+ :class: rst-example
1353+
1354+ In :math:numref:`schroedinger general` the time-dependent Schrödinger equation
1355+ is shown.
1356+
1357+ .. math::
1358+ :label: schroedinger general
1359+
1360+ \mathrm{i}\hbar\dfrac{\partial}{\partial t} |\,\psi (t) \rangle =
1361+ \hat{H} |\,\psi (t) \rangle.
1362+
1363+
1364+The next example shows the difference of ``\tfrac`` (*textstyle*) and ``\dfrac``
1365+(*displaystyle*) used in a inline markup or another fraction.
1366+
1367+.. code:: reST
1368+
1369+ ``\tfrac`` **inline example** :math:`\tfrac{\tfrac{1}{x}+\tfrac{1}{y}}{y-z}`
1370+ ``\dfrac`` **inline example** :math:`\dfrac{\dfrac{1}{x}+\dfrac{1}{y}}{y-z}`
1371+
1372+.. admonition:: Line spacing
1373+ :class: rst-example
1374+
1375+ Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
1376+ eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
1377+ voluptua. ...
1378+ ``\tfrac`` **inline example** :math:`\tfrac{\tfrac{1}{x}+\tfrac{1}{y}}{y-z}`
1379+ At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd
1380+ gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
1381+
1382+ Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
1383+ eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
1384+ voluptua. ...
1385+ ``\tfrac`` **inline example** :math:`\dfrac{\dfrac{1}{x}+\dfrac{1}{y}}{y-z}`
1386+ At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd
1387+ gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
1388+
1389+
1390+.. _KISS: https://en.wikipedia.org/wiki/KISS_principle
1391+
1392+.. _readability: https://docs.python-guide.org/writing/style/
1393+.. _Sphinx-Primer:
1394+ http://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html
1395+.. _reST: https://docutils.sourceforge.io/rst.html
1396+.. _Sphinx Roles:
1397+ https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html
1398+.. _Sphinx: http://www.sphinx-doc.org
1399+.. _`sphinx-doc FAQ`: http://www.sphinx-doc.org/en/stable/faq.html
1400+.. _Sphinx markup constructs:
1401+ http://www.sphinx-doc.org/en/stable/markup/index.html
1402+.. _`sphinx cross references`:
1403+ http://www.sphinx-doc.org/en/stable/markup/inline.html#cross-referencing-arbitrary-locations
1404+.. _sphinx.ext.extlinks:
1405+ https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html
1406+.. _intersphinx: http://www.sphinx-doc.org/en/stable/ext/intersphinx.html
1407+.. _sphinx config: http://www.sphinx-doc.org/en/stable/config.html
1408+.. _Sphinx's autodoc: http://www.sphinx-doc.org/en/stable/ext/autodoc.html
1409+.. _Sphinx's Python domain:
1410+ http://www.sphinx-doc.org/en/stable/domains.html#the-python-domain
1411+.. _Sphinx's C domain:
1412+ http://www.sphinx-doc.org/en/stable/domains.html#cross-referencing-c-constructs
1413+.. _doctree:
1414+ http://www.sphinx-doc.org/en/master/extdev/tutorial.html?highlight=doctree#build-phases
1415+.. _docutils: http://docutils.sourceforge.net/docs/index.html
1416+.. _docutils FAQ: http://docutils.sourceforge.net/FAQ.html
1417+.. _linuxdoc: https://return42.github.io/linuxdoc
1418+.. _jinja: https://jinja.palletsprojects.com/
1419+.. _sphinx-jinja: https://github.com/tardyp/sphinx-jinja
1420+.. _SVG: https://www.w3.org/TR/SVG11/expanded-toc.html
1421+.. _DOT: https://graphviz.gitlab.io/_pages/doc/info/lang.html
1422+.. _`Graphviz's dot`: https://graphviz.gitlab.io/_pages/pdf/dotguide.pdf
1423+.. _Graphviz: https://graphviz.gitlab.io
1424+.. _ImageMagick: https://www.imagemagick.org
1425+
1426+.. _`Emacs Table Mode`: https://www.emacswiki.org/emacs/TableMode
1427+.. _`Online Tables Generator`: http://www.tablesgenerator.com/text_tables
1428+.. _`OASIS XML Exchange Table Model`: https://www.oasis-open.org/specs/tm9901.html
docs/dev/search_api.rstnew file+119
@@ -0,0 +1,119 @@
1+==========
2+Search API
3+==========
4+
5+The search supports both ``GET`` and ``POST``.
6+
7+Furthermore, two enpoints ``/`` and ``/search`` are available for querying.
8+
9+
10+``GET /``
11+
12+``GET /search``
13+
14+Parameters
15+==========
16+
17+.. sidebar:: Further reading ..
18+
19+ - :ref:`engines generic`
20+ - :ref:`configured engines`
21+ - :ref:`engine settings`
22+ - :ref:`engine file`
23+
24+``q`` : required
25+ The search query. This string is passed to external search services. Thus,
26+ searx supports syntax of each search service. For example, ``site:github.com
27+ searx`` is a valid query for Google. However, if simply the query above is
28+ passed to any search engine which does not filter its results based on this
29+ syntax, you might not get the results you wanted.
30+
31+ See more at :ref:`search-syntax`
32+
33+``categories`` : optional
34+ Comma separated list, specifies the active search categories
35+
36+``engines``: optional
37+ Comma separated list, specifies the active search engines.
38+
39+``lang``: default ``all``
40+ Code of the language.
41+
42+``pageno``: default ``1``
43+ Search page number.
44+
45+``time_range``: optional
46+ [ ``day``, ``month``, ``year`` ]
47+
48+ Time range of search for engines which support it. See if an engine supports
49+ time range search in the preferences page of an instance.
50+
51+``format``: optional
52+ [ ``json``, ``csv``, ``rss`` ]
53+
54+ Output format of results.
55+
56+``results_on_new_tab``: default ``0``
57+ [ ``0``, ``1`` ]
58+
59+ Open search results on new tab.
60+
61+``image_proxy``: default ``False``
62+ [ ``True``, ``False`` ]
63+
64+ Proxy image results through searx.
65+
66+``autocomplete``: default *empty*
67+ [ ``google``, ``dbpedia``, ``duckduckgo``, ``startpage``, ``wikipedia`` ]
68+
69+ Service which completes words as you type.
70+
71+``safesearch``: default ``None``
72+ [ ``0``, ``1``, ``None`` ]
73+
74+ Filter search results of engines which support safe search. See if an engine
75+ supports safe search in the preferences page of an instance.
76+
77+``theme``: default ``oscar``
78+ [ ``oscar``, ``simple``, ``legacy``, ``pix-art``, ``courgette`` ]
79+
80+ Theme of instance.
81+
82+ Please note, available themes depend on an instance. It is possible that an
83+ instance administrator deleted, created or renamed themes on his/her instance.
84+ See the available options in the preferences page of the instance.
85+
86+``oscar-style``: default ``logicodev``
87+ [ ``pointhi``, ``logicodev`` ]
88+
89+ Style of Oscar theme. It is only parsed if the theme of an instance is
90+ ``oscar``.
91+
92+ Please note, available styles depend on an instance. It is possible that an
93+ instance administrator deleted, created or renamed styles on his/her
94+ instance. See the available options in the preferences page of the instance.
95+
96+``enabled_plugins``: optional
97+ List of enabled plugins.
98+
99+ :default: ``HTTPS_rewrite``, ``Self_Informations``,
100+ ``Search_on_category_select``, ``Tracker_URL_remover``
101+
102+ :values: [ ``DOAI_rewrite``, ``HTTPS_rewrite``, ``Infinite_scroll``,
103+ ``Vim-like_hotkeys``, ``Self_Informations``, ``Tracker_URL_remover``,
104+ ``Search_on_category_select`` ]
105+
106+``disabled_plugins``: optional
107+ List of disabled plugins.
108+
109+ :default: ``DOAI_rewrite``, ``Infinite_scroll``, ``Vim-like_hotkeys``
110+ :values: ``DOAI_rewrite``, ``HTTPS_rewrite``, ``Infinite_scroll``,
111+ ``Vim-like_hotkeys``, ``Self_Informations``, ``Tracker_URL_remover``,
112+ ``Search_on_category_select``
113+
114+``enabled_engines``: optional : *all* :origin:`engines <searx/engines>`
115+ List of enabled engines.
116+
117+``disabled_engines``: optional : *all* :origin:`engines <searx/engines>`
118+ List of disabled engines.
119+
docs/dev/svg_image.svgnew file+10
@@ -0,0 +1,10 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!-- originate: https://commons.wikimedia.org/wiki/File:Variable_Resistor.svg -->
3+<svg xmlns="http://www.w3.org/2000/svg"
4+ version="1.1" baseProfile="full"
5+ width="70px" height="40px" viewBox="0 0 700 400">
6+ <line x1="0" y1="200" x2="700" y2="200" stroke="black" stroke-width="20px"/>
7+ <rect x="100" y="100" width="500" height="200" fill="white" stroke="black" stroke-width="20px"/>
8+ <line x1="180" y1="370" x2="500" y2="50" stroke="black" stroke-width="15px"/>
9+ <polygon points="585 0 525 25 585 50" transform="rotate(135 525 25)"/>
10+</svg>
docs/dev/translation.rstnew file+71
@@ -0,0 +1,71 @@
1+.. _translation:
2+
3+===========
4+Translation
5+===========
6+
7+.. _searx@transifex: https://www.transifex.com/asciimoo/searx/
8+
9+Translation currently takes place on `searx@transifex`_
10+
11+Requirements
12+============
13+
14+* Transifex account
15+* Installed CLI tool of Transifex
16+
17+Init Transifex project
18+======================
19+
20+After installing ``transifex`` using pip, run the following command to
21+initialize the project.
22+
23+.. code:: sh
24+
25+ tx init # Transifex instance: https://www.transifex.com/asciimoo/searx/
26+
27+
28+After ``$HOME/.transifexrc`` is created, get a Transifex API key and insert it
29+into the configuration file.
30+
31+Create a configuration file for ``tx`` named ``$HOME/.tx/config``.
32+
33+.. code:: ini
34+
35+ [main]
36+ host = https://www.transifex.com
37+ [searx.messagespo]
38+ file_filter = searx/translations/<lang>/LC_MESSAGES/messages.po
39+ source_file = messages.pot
40+ source_lang = en
41+ type = PO
42+
43+
44+Then run ``tx set``:
45+
46+.. code:: shell
47+
48+ tx set --auto-local -r searx.messagespo 'searx/translations/<lang>/LC_MESSAGES/messages.po' \
49+ --source-lang en --type PO --source-file messages.pot --execute
50+
51+
52+Update translations
53+===================
54+
55+To retrieve the latest translations, pull it from Transifex.
56+
57+.. code:: sh
58+
59+ tx pull -a
60+
61+Then check the new languages. If strings translated are not enough, delete those
62+folders, because those should not be compiled. Call the command below to compile
63+the ``.po`` files.
64+
65+.. code:: shell
66+
67+ pybabel compile -d searx/translations
68+
69+
70+After the compilation is finished commit the ``.po`` and ``.mo`` files and
71+create a PR.
docs/index.rstnew file+32
@@ -0,0 +1,32 @@
1+================
2+Welcome to searx
3+================
4+
5+Search without being tracked.
6+
7+.. sidebar:: Features
8+
9+ - Self hosted
10+ - No user tracking
11+ - No user profiling
12+ - About 70 supported search engines
13+ - Easy integration with any search engine
14+ - Cookies are not used by default
15+ - Secure, encrypted connections (HTTPS/SSL)
16+ - Hosted by organizations, such as *La Quadrature du Net*, which promote
17+ digital rights
18+
19+Searx is a free internet metasearch engine which aggregates results from more
20+than 70 search services. Users are neither tracked nor profiled. Additionally,
21+searx can be used over Tor for online anonymity.
22+
23+Get started with searx by using one of the :wiki:`Searx-instances`. If you
24+don't trust anyone, you can set up your own, see :ref:`installation`.
25+
26+.. toctree::
27+ :maxdepth: 2
28+
29+ user/index
30+ admin/index
31+ dev/index
32+ blog/index
docs/static/img/searx_logo_small.pngnew file

Binary file not shown.

docs/user/index.rstnew file+9
@@ -0,0 +1,9 @@
1+==================
2+User documentation
3+==================
4+
5+.. toctree::
6+ :maxdepth: 1
7+
8+ search_syntax
9+ own-instance
docs/user/own-instance.rstnew file+77
@@ -0,0 +1,77 @@
1+===========================
2+Why use a private instance?
3+===========================
4+
5+"Is it worth to run my own instance?" is a common question among searx users.
6+Before answering this question, see what options a searx user has.
7+
8+Public instances are open to everyone who has access to its URL. Usually, these
9+are operated by unknown parties (from the users' point of view). Private
10+instances can be used by a select group of people. It is for example a searx of
11+group of friends or a company which can be accessed through VPN. Also it can be
12+single user one which runs on the user's laptop.
13+
14+To gain more insight on how these instances work let's dive into how searx
15+protects its users.
16+
17+How does searx protect privacy?
18+===============================
19+
20+Searx protects the privacy of its users in multiple ways regardless of the type
21+of the instance (private, public). Removal of private data from search requests
22+comes in three forms:
23+
24+ 1. removal of private data from requests going to search services
25+ 2. not forwarding anything from a third party services through search services
26+ (e.g. advertisement)
27+ 3. removal of private data from requests going to the result pages
28+
29+Removing private data means not sending cookies to external search engines and
30+generating a random browser profile for every request. Thus, it does not matter
31+if a public or private instance handles the request, because it is anonymized in
32+both cases. IP addresses will be the IP of the instance. But searx can be
33+configured to use proxy or Tor. `Result proxy
34+<https://github.com/asciimoo/morty>`__ is supported, too.
35+
36+Searx does not serve ads or tracking content unlike most search services. So
37+private data is not forwarded to third parties who might monetize it. Besides
38+protecting users from search services, both referring page and search query are
39+hidden from visited result pages.
40+
41+
42+What are the consequences of using public instances?
43+----------------------------------------------------
44+
45+If someone uses a public instance, he/she has to trust the administrator of that
46+instance. This means that the user of the public instance does not know whether
47+his/her requests are logged, aggregated and sent or sold to a third party.
48+
49+Also, public instances without proper protection are more vulnerable to abusing
50+the search service, In this case the external service in exchange returns
51+CAPTCHAs or bans the IP of the instance. Thus, search requests return less
52+results.
53+
54+I see. What about private instances?
55+------------------------------------
56+
57+If users run their own instances, everything is in their control: the source
58+code, logging settings and private data. Unknown instance administrators do not
59+have to be trusted.
60+
61+Furthermore, as the default settings of their instance is editable, there is no
62+need to use cookies to tailor searx to their needs. So preferences will not be
63+reset to defaults when clearing browser cookies. As settings are stored on
64+their computer, it will not be accessible to others as long as their computer is
65+not compromised.
66+
67+Conclusion
68+==========
69+
70+Always use an instance which is operated by people you trust. The privacy
71+features of searx are available to users no matter what kind of instance they
72+use.
73+
74+If someone is on the go or just wants to try searx for the first time public
75+instances are the best choices. Additionally, public instance are making a
76+world a better place, because those who cannot or do not want to run an
77+instance, have access to a privacy respecting search service.
docs/user/search_syntax.rstnew file+42
@@ -0,0 +1,42 @@
1+
2+.. _search-syntax:
3+
4+=============
5+Search syntax
6+=============
7+
8+Searx allows you to modify the default categories, engines and search language
9+via the search query.
10+
11+Prefix ``!``
12+ to set Category/engine
13+
14+Prefix: ``:``
15+ to set language
16+
17+Prefix: ``?``
18+ to add engines and categories to the currently selected categories
19+
20+Abbrevations of the engines and languages are also accepted. Engine/category
21+modifiers are chainable and inclusive (e.g. with :search:`!it !ddg !wp qwer
22+<?q=%21it%20%21ddg%20%21wp%20qwer>` search in IT category **and** duckduckgo
23+**and** wikipedia for ``qwer``).
24+
25+See the :search:`/preferences page <preferences>` for the list of engines,
26+categories and languages.
27+
28+Examples
29+========
30+
31+Search in wikipedia for ``qwer``:
32+
33+- :search:`!wp qwer <?q=%21wp%20qwer>` or
34+- :search:`!wikipedia qwer :search:<?q=%21wikipedia%20qwer>`
35+
36+Image search:
37+
38+- :search:`!images Cthulhu <?q=%21images%20Cthulhu>`
39+
40+Custom language in wikipedia:
41+
42+- :search:`:hu !wp hackerspace <?q=%3Ahu%20%21wp%20hackerspace>`
manage.sh+11−3
@@ -18,12 +18,12 @@ ACTION="$1"
18update_packages() {
18update_packages() {
19 pip install --upgrade pip
19 pip install --upgrade pip
20 pip install --upgrade setuptools
20 pip install --upgrade setuptools
21− pip install -r "$BASE_DIR/requirements.txt"
21+ pip install -Ur "$BASE_DIR/requirements.txt"
22}
22}
23
23
24update_dev_packages() {
24update_dev_packages() {
25 update_packages
25 update_packages
26− pip install -r "$BASE_DIR/requirements-dev.txt"
26+ pip install -Ur "$BASE_DIR/requirements-dev.txt"
27}
27}
28
28
29install_geckodriver() {
29install_geckodriver() {
@@ -70,6 +70,11 @@ locales() {
70 pybabel compile -d "$SEARX_DIR/translations"
70 pybabel compile -d "$SEARX_DIR/translations"
71}
71}
72
72
73+update_useragents() {
74+ echo '[!] Updating user agent versions'
75+ python utils/fetch_firefox_version.py
76+}
77+
73pep8_check() {
78pep8_check() {
74 echo '[!] Running pep8 check'
79 echo '[!] Running pep8 check'
75 # ignored rules:
80 # ignored rules:
@@ -152,6 +157,8 @@ styles() {
152}
157}
153
158
154grunt_build() {
159grunt_build() {
160+ npm_path_setup
161+
155 echo '[!] Grunt build : oscar theme'
162 echo '[!] Grunt build : oscar theme'
156 grunt --gruntfile "$SEARX_DIR/static/themes/oscar/gruntfile.js"
163 grunt --gruntfile "$SEARX_DIR/static/themes/oscar/gruntfile.js"
157 echo '[!] Grunt build : simple theme'
164 echo '[!] Grunt build : simple theme'
@@ -243,7 +250,8 @@ Commands
243 update_packages - Check & update production dependency changes
250 update_packages - Check & update production dependency changes
244 update_dev_packages - Check & update development and production dependency changes
251 update_dev_packages - Check & update development and production dependency changes
245 install_geckodriver - Download & install geckodriver if not already installed (required for robot_tests)
252 install_geckodriver - Download & install geckodriver if not already installed (required for robot_tests)
246− npm_packages - Download & install npm dependencies (source manage.sh to update the PATH)
253+ npm_packages - Download & install npm dependencies
254+ update_useragents - Update useragents.json with the most recent versions of Firefox
247
255
248 Build
256 Build
249 -----
257 -----
requirements-dev.txt+6
@@ -1,3 +1,6 @@
1+pallets-sphinx-themes
2+Sphinx
3+sphinx-issues
1mock==2.0.0
4mock==2.0.0
2nose2[coverage_plugin]
5nose2[coverage_plugin]
3cov-core==1.15.0
6cov-core==1.15.0
@@ -8,3 +11,6 @@ transifex-client==0.12.2
8unittest2==1.1.0
11unittest2==1.1.0
9zope.testrunner==4.5.1
12zope.testrunner==4.5.1
10selenium==3.141.0
13selenium==3.141.0
14+linuxdoc @ git+http://github.com/return42/linuxdoc.git
15+sphinx-jinja
16+sphinx-tabs
searx/data/useragents.json+8−7
@@ -1,14 +1,15 @@
1{
1{
2− "ua": "Mozilla/5.0 ({os}; rv:{version}) Gecko/20100101 Firefox/{version}",
3 "versions": [
2 "versions": [
4− "61.0.1",
3+ "70.0.1",
5− "61.0",
4+ "70.0",
5+ "69.0.3",
6− "60.0.2",
6+ "69.0.2",
7− "60.0.1",
7+ "69.0.1",
8− "60.0"
8+ "69.0"
9 ],
9 ],
10 "os": [
10 "os": [
11 "Windows NT 10; WOW64",
11 "Windows NT 10; WOW64",
12 "X11; Linux x86_64"
12 "X11; Linux x86_64"
13− ]
13+ ],
14+ "ua": "Mozilla/5.0 ({os}; rv:{version}) Gecko/20100101 Firefox/{version}"
14}
15}
searx/engines/__init__.py+15−12
@@ -27,7 +27,7 @@ from json import loads
27from requests import get
27from requests import get
28from searx import settings
28from searx import settings
29from searx import logger
29from searx import logger
30−from searx.utils import load_module, match_language
30+from searx.utils import load_module, match_language, get_engine_from_settings
31
31
32
32
33logger = logger.getChild('engines')
33logger = logger.getChild('engines')
@@ -53,7 +53,8 @@ engine_default_args = {'paging': False,
53 'disabled': False,
53 'disabled': False,
54 'suspend_end_time': 0,
54 'suspend_end_time': 0,
55 'continuous_errors': 0,
55 'continuous_errors': 0,
56− 'time_range_support': False}
56+ 'time_range_support': False,
57+ 'offline': False}
57
58
58
59
59def load_engine(engine_data):
60def load_engine(engine_data):
@@ -128,14 +129,16 @@ def load_engine(engine_data):
128 engine.stats = {
129 engine.stats = {
129 'result_count': 0,
130 'result_count': 0,
130 'search_count': 0,
131 'search_count': 0,
131− 'page_load_time': 0,
132− 'page_load_count': 0,
133 'engine_time': 0,
132 'engine_time': 0,
134 'engine_time_count': 0,
133 'engine_time_count': 0,
135 'score_count': 0,
134 'score_count': 0,
136 'errors': 0
135 'errors': 0
137 }
136 }
138
137
138+ if not engine.offline:
139+ engine.stats['page_load_time'] = 0
140+ engine.stats['page_load_count'] = 0
141+
139 for category_name in engine.categories:
142 for category_name in engine.categories:
140 categories.setdefault(category_name, []).append(engine)
143 categories.setdefault(category_name, []).append(engine)
141
144
@@ -173,11 +176,6 @@ def get_engines_stats():
173 results_num = \
176 results_num = \
174 engine.stats['result_count'] / float(engine.stats['search_count'])
177 engine.stats['result_count'] / float(engine.stats['search_count'])
175
178
176− if engine.stats['page_load_count'] != 0:
177− load_times = engine.stats['page_load_time'] / float(engine.stats['page_load_count']) # noqa
178− else:
179− load_times = 0
180−
181 if engine.stats['engine_time_count'] != 0:
179 if engine.stats['engine_time_count'] != 0:
182 this_engine_time = engine.stats['engine_time'] / float(engine.stats['engine_time_count']) # noqa
180 this_engine_time = engine.stats['engine_time'] / float(engine.stats['engine_time_count']) # noqa
183 else:
181 else:
@@ -189,14 +187,19 @@ def get_engines_stats():
189 else:
187 else:
190 score = score_per_result = 0.0
188 score = score_per_result = 0.0
191
189
190+ if not engine.offline:
191+ load_times = 0
192+ if engine.stats['page_load_count'] != 0:
193+ load_times = engine.stats['page_load_time'] / float(engine.stats['page_load_count']) # noqa
192− max_pageload = max(load_times, max_pageload)
194+ max_pageload = max(load_times, max_pageload)
195+ pageloads.append({'avg': load_times, 'name': engine.name})
196+
193 max_engine_times = max(this_engine_time, max_engine_times)
197 max_engine_times = max(this_engine_time, max_engine_times)
194 max_results = max(results_num, max_results)
198 max_results = max(results_num, max_results)
195 max_score = max(score, max_score)
199 max_score = max(score, max_score)
196 max_score_per_result = max(score_per_result, max_score_per_result)
200 max_score_per_result = max(score_per_result, max_score_per_result)
197 max_errors = max(max_errors, engine.stats['errors'])
201 max_errors = max(max_errors, engine.stats['errors'])
198
202
199− pageloads.append({'avg': load_times, 'name': engine.name})
200 engine_times.append({'avg': this_engine_time, 'name': engine.name})
203 engine_times.append({'avg': this_engine_time, 'name': engine.name})
201 results.append({'avg': results_num, 'name': engine.name})
204 results.append({'avg': results_num, 'name': engine.name})
202 scores.append({'avg': score, 'name': engine.name})
205 scores.append({'avg': score, 'name': engine.name})
@@ -255,7 +258,7 @@ def initialize_engines(engine_list):
255 load_engines(engine_list)
258 load_engines(engine_list)
256
259
257 def engine_init(engine_name, init_fn):
260 def engine_init(engine_name, init_fn):
258− init_fn()
261+ init_fn(get_engine_from_settings(engine_name))
259 logger.debug('%s engine: Initialized', engine_name)
262 logger.debug('%s engine: Initialized', engine_name)
260
263
261 for engine_name, engine in engines.items():
264 for engine_name, engine in engines.items():
searx/engines/arxiv.py+2−1
@@ -17,6 +17,7 @@ from searx.url_utils import urlencode
17
17
18
18
19categories = ['science']
19categories = ['science']
20+paging = True
20
21
21base_url = 'http://export.arxiv.org/api/query?search_query=all:'\
22base_url = 'http://export.arxiv.org/api/query?search_query=all:'\
22 + '{query}&start={offset}&max_results={number_of_results}'
23 + '{query}&start={offset}&max_results={number_of_results}'
@@ -29,7 +30,7 @@ def request(query, params):
29 # basic search
30 # basic search
30 offset = (params['pageno'] - 1) * number_of_results
31 offset = (params['pageno'] - 1) * number_of_results
31
32
32− string_args = dict(query=query,
33+ string_args = dict(query=query.decode('utf-8'),
33 offset=offset,
34 offset=offset,
34 number_of_results=number_of_results)
35 number_of_results=number_of_results)
35
36
searx/engines/bing.py+37−20
@@ -13,10 +13,14 @@
13 @todo publishedDate
13 @todo publishedDate
14"""
14"""
15
15
16+import re
16from lxml import html
17from lxml import html
18+from searx import logger, utils
17from searx.engines.xpath import extract_text
19from searx.engines.xpath import extract_text
18from searx.url_utils import urlencode
20from searx.url_utils import urlencode
19−from searx.utils import match_language, gen_useragent
21+from searx.utils import match_language, gen_useragent, eval_xpath
22+
23+logger = logger.getChild('bing engine')
20
24
21# engine dependent config
25# engine dependent config
22categories = ['general']
26categories = ['general']
@@ -30,9 +34,13 @@ base_url = 'https://www.bing.com/'
30search_string = 'search?{query}&first={offset}'
34search_string = 'search?{query}&first={offset}'
31
35
32
36
37+def _get_offset_from_pageno(pageno):
38+ return (pageno - 1) * 10 + 1
39+
40+
33# do search-request
41# do search-request
34def request(query, params):
42def request(query, params):
35− offset = (params['pageno'] - 1) * 10 + 1
43+ offset = _get_offset_from_pageno(params.get('pageno', 0))
36
44
37 if params['language'] == 'all':
45 if params['language'] == 'all':
38 lang = 'EN'
46 lang = 'EN'
@@ -47,29 +55,21 @@ def request(query, params):
47
55
48 params['url'] = base_url + search_path
56 params['url'] = base_url + search_path
49
57
50− params['headers']['User-Agent'] = gen_useragent('Windows NT 6.3; WOW64')
51−
52 return params
58 return params
53
59
54
60
55# get response from search-request
61# get response from search-request
56def response(resp):
62def response(resp):
57 results = []
63 results = []
64+ result_len = 0
58
65
59 dom = html.fromstring(resp.text)
66 dom = html.fromstring(resp.text)
60−
61− try:
62− results.append({'number_of_results': int(dom.xpath('//span[@class="sb_count"]/text()')[0]
63− .split()[0].replace(',', ''))})
64− except:
65− pass
66−
67 # parse results
67 # parse results
68− for result in dom.xpath('//div[@class="sa_cc"]'):
68+ for result in eval_xpath(dom, '//div[@class="sa_cc"]'):
69− link = result.xpath('.//h3/a')[0]
69+ link = eval_xpath(result, './/h3/a')[0]
70 url = link.attrib.get('href')
70 url = link.attrib.get('href')
71 title = extract_text(link)
71 title = extract_text(link)
72− content = extract_text(result.xpath('.//p'))
72+ content = extract_text(eval_xpath(result, './/p'))
73
73
74 # append result
74 # append result
75 results.append({'url': url,
75 results.append({'url': url,
@@ -77,18 +77,35 @@ def response(resp):
77 'content': content})
77 'content': content})
78
78
79 # parse results again if nothing is found yet
79 # parse results again if nothing is found yet
80− for result in dom.xpath('//li[@class="b_algo"]'):
80+ for result in eval_xpath(dom, '//li[@class="b_algo"]'):
81− link = result.xpath('.//h2/a')[0]
81+ link = eval_xpath(result, './/h2/a')[0]
82 url = link.attrib.get('href')
82 url = link.attrib.get('href')
83 title = extract_text(link)
83 title = extract_text(link)
84− content = extract_text(result.xpath('.//p'))
84+ content = extract_text(eval_xpath(result, './/p'))
85
85
86 # append result
86 # append result
87 results.append({'url': url,
87 results.append({'url': url,
88 'title': title,
88 'title': title,
89 'content': content})
89 'content': content})
90
90
91+ try:
92+ result_len_container = "".join(eval_xpath(dom, '//span[@class="sb_count"]/text()'))
93+ result_len_container = utils.to_string(result_len_container)
94+ if "-" in result_len_container:
95+ # Remove the part "from-to" for paginated request ...
96+ result_len_container = result_len_container[result_len_container.find("-") * 2 + 2:]
97+
98+ result_len_container = re.sub('[^0-9]', '', result_len_container)
99+ if len(result_len_container) > 0:
100+ result_len = int(result_len_container)
101+ except Exception as e:
102+ logger.debug('result error :\n%s', e)
103+ pass
104+
105+ if _get_offset_from_pageno(resp.search_params.get("pageno", 0)) > result_len:
91− # return results
106+ return []
107+
108+ results.append({'number_of_results': result_len})
92 return results
109 return results
93
110
94
111
@@ -96,9 +113,9 @@ def response(resp):
96def _fetch_supported_languages(resp):
113def _fetch_supported_languages(resp):
97 supported_languages = []
114 supported_languages = []
98 dom = html.fromstring(resp.text)
115 dom = html.fromstring(resp.text)
99− options = dom.xpath('//div[@id="limit-languages"]//input')
116+ options = eval_xpath(dom, '//div[@id="limit-languages"]//input')
100 for option in options:
117 for option in options:
101− code = option.xpath('./@id')[0].replace('_', '-')
118+ code = eval_xpath(option, './@id')[0].replace('_', '-')
102 if code == 'nb':
119 if code == 'nb':
103 code = 'no'
120 code = 'no'
104 supported_languages.append(code)
121 supported_languages.append(code)
searx/engines/dailymotion.py+2−2
@@ -15,7 +15,7 @@
15from json import loads
15from json import loads
16from datetime import datetime
16from datetime import datetime
17from searx.url_utils import urlencode
17from searx.url_utils import urlencode
18−from searx.utils import match_language
18+from searx.utils import match_language, html_to_text
19
19
20# engine dependent config
20# engine dependent config
21categories = ['videos']
21categories = ['videos']
@@ -59,7 +59,7 @@ def response(resp):
59 for res in search_res['list']:
59 for res in search_res['list']:
60 title = res['title']
60 title = res['title']
61 url = res['url']
61 url = res['url']
62− content = res['description']
62+ content = html_to_text(res['description'])
63 thumbnail = res['thumbnail_360_url']
63 thumbnail = res['thumbnail_360_url']
64 publishedDate = datetime.fromtimestamp(res['created_time'], None)
64 publishedDate = datetime.fromtimestamp(res['created_time'], None)
65 embedded = embedded_url.format(videoid=res['id'])
65 embedded = embedded_url.format(videoid=res['id'])
searx/engines/deviantart.py+22−25
@@ -24,7 +24,7 @@ time_range_support = True
24
24
25# search-url
25# search-url
26base_url = 'https://www.deviantart.com/'
26base_url = 'https://www.deviantart.com/'
27−search_url = base_url + 'browse/all/?offset={offset}&{query}'
27+search_url = base_url + 'search?page={page}&{query}'
28time_range_url = '&order={range}'
28time_range_url = '&order={range}'
29
29
30time_range_dict = {'day': 11,
30time_range_dict = {'day': 11,
@@ -37,9 +37,7 @@ def request(query, params):
37 if params['time_range'] and params['time_range'] not in time_range_dict:
37 if params['time_range'] and params['time_range'] not in time_range_dict:
38 return params
38 return params
39
39
40− offset = (params['pageno'] - 1) * 24
41−
42− params['url'] = search_url.format(offset=offset,
40+ params['url'] = search_url.format(page=params['pageno'],
43 query=urlencode({'q': query}))
41 query=urlencode({'q': query}))
44 if params['time_range'] in time_range_dict:
42 if params['time_range'] in time_range_dict:
45 params['url'] += time_range_url.format(range=time_range_dict[params['time_range']])
43 params['url'] += time_range_url.format(range=time_range_dict[params['time_range']])
@@ -57,28 +55,27 @@ def response(resp):
57
55
58 dom = html.fromstring(resp.text)
56 dom = html.fromstring(resp.text)
59
57
60− regex = re.compile(r'\/200H\/')
61−
62 # parse results
58 # parse results
63− for result in dom.xpath('.//span[@class="thumb wide"]'):
59+ for row in dom.xpath('//div[contains(@data-hook, "content_row")]'):
60+ for result in row.xpath('./div'):
64− link = result.xpath('.//a[@class="torpedo-thumb-link"]')[0]
61+ link = result.xpath('.//a[@data-hook="deviation_link"]')[0]
65− url = link.attrib.get('href')
62+ url = link.attrib.get('href')
66− title = extract_text(result.xpath('.//span[@class="title"]'))
63+ title = link.attrib.get('title')
67− thumbnail_src = link.xpath('.//img')[0].attrib.get('src')
64+ thumbnail_src = result.xpath('.//img')[0].attrib.get('src')
68− img_src = regex.sub('/', thumbnail_src)
65+ img_src = thumbnail_src
69−
66+
70− # http to https, remove domain sharding
67+ # http to https, remove domain sharding
71− thumbnail_src = re.sub(r"https?://(th|fc)\d+.", "https://th01.", thumbnail_src)
68+ thumbnail_src = re.sub(r"https?://(th|fc)\d+.", "https://th01.", thumbnail_src)
72− thumbnail_src = re.sub(r"http://", "https://", thumbnail_src)
69+ thumbnail_src = re.sub(r"http://", "https://", thumbnail_src)
73−
70+
74− url = re.sub(r"http://(.*)\.deviantart\.com/", "https://\\1.deviantart.com/", url)
71+ url = re.sub(r"http://(.*)\.deviantart\.com/", "https://\\1.deviantart.com/", url)
75−
72+
76− # append result
73+ # append result
77− results.append({'url': url,
74+ results.append({'url': url,
78− 'title': title,
75+ 'title': title,
79− 'img_src': img_src,
76+ 'img_src': img_src,
80− 'thumbnail_src': thumbnail_src,
77+ 'thumbnail_src': thumbnail_src,
81− 'template': 'images.html'})
78+ 'template': 'images.html'})
82
79
83 # return results
80 # return results
84 return results
81 return results
searx/engines/dictzone.py+5−5
@@ -11,11 +11,11 @@
11
11
12import re
12import re
13from lxml import html
13from lxml import html
14−from searx.utils import is_valid_lang
14+from searx.utils import is_valid_lang, eval_xpath
15from searx.url_utils import urljoin
15from searx.url_utils import urljoin
16
16
17categories = ['general']
17categories = ['general']
18−url = u'http://dictzone.com/{from_lang}-{to_lang}-dictionary/{query}'
18+url = u'https://dictzone.com/{from_lang}-{to_lang}-dictionary/{query}'
19weight = 100
19weight = 100
20
20
21parser_re = re.compile(b'.*?([a-z]+)-([a-z]+) ([^ ]+)$', re.I)
21parser_re = re.compile(b'.*?([a-z]+)-([a-z]+) ([^ ]+)$', re.I)
@@ -47,14 +47,14 @@ def response(resp):
47
47
48 dom = html.fromstring(resp.text)
48 dom = html.fromstring(resp.text)
49
49
50− for k, result in enumerate(dom.xpath(results_xpath)[1:]):
50+ for k, result in enumerate(eval_xpath(dom, results_xpath)[1:]):
51 try:
51 try:
52− from_result, to_results_raw = result.xpath('./td')
52+ from_result, to_results_raw = eval_xpath(result, './td')
53 except:
53 except:
54 continue
54 continue
55
55
56 to_results = []
56 to_results = []
57− for to_result in to_results_raw.xpath('./p/a'):
57+ for to_result in eval_xpath(to_results_raw, './p/a'):
58 t = to_result.text_content()
58 t = to_result.text_content()
59 if t.strip():
59 if t.strip():
60 to_results.append(to_result.text_content())
60 to_results.append(to_result.text_content())
searx/engines/digg.py+12−24
@@ -15,7 +15,8 @@ import string
15from dateutil import parser
15from dateutil import parser
16from json import loads
16from json import loads
17from lxml import html
17from lxml import html
18−from searx.url_utils import quote_plus
18+from searx.url_utils import urlencode
19+from datetime import datetime
19
20
20# engine dependent config
21# engine dependent config
21categories = ['news', 'social media']
22categories = ['news', 'social media']
@@ -23,7 +24,7 @@ paging = True
23
24
24# search-url
25# search-url
25base_url = 'https://digg.com/'
26base_url = 'https://digg.com/'
26−search_url = base_url + 'api/search/{query}.json?position={position}&format=html'
27+search_url = base_url + 'api/search/?{query}&from={position}&size=20&format=html'
27
28
28# specific xpath variables
29# specific xpath variables
29results_xpath = '//article'
30results_xpath = '//article'
@@ -38,9 +39,9 @@ digg_cookie_chars = string.ascii_uppercase + string.ascii_lowercase +\
38
39
39# do search-request
40# do search-request
40def request(query, params):
41def request(query, params):
41− offset = (params['pageno'] - 1) * 10
42+ offset = (params['pageno'] - 1) * 20
42 params['url'] = search_url.format(position=offset,
43 params['url'] = search_url.format(position=offset,
43− query=quote_plus(query))
44+ query=urlencode({'q': query}))
44 params['cookies']['frontend.auid'] = ''.join(random.choice(
45 params['cookies']['frontend.auid'] = ''.join(random.choice(
45 digg_cookie_chars) for _ in range(22))
46 digg_cookie_chars) for _ in range(22))
46 return params
47 return params
@@ -52,30 +53,17 @@ def response(resp):
52
53
53 search_result = loads(resp.text)
54 search_result = loads(resp.text)
54
55
55− if 'html' not in search_result or search_result['html'] == '':
56− return results
57−
58− dom = html.fromstring(search_result['html'])
59−
60 # parse results
56 # parse results
61− for result in dom.xpath(results_xpath):
57+ for result in search_result['mapped']:
62− url = result.attrib.get('data-contenturl')
63− thumbnail = result.xpath('.//img')[0].attrib.get('src')
64− title = ''.join(result.xpath(title_xpath))
65− content = ''.join(result.xpath(content_xpath))
66− pubdate = result.xpath(pubdate_xpath)[0].attrib.get('datetime')
67− publishedDate = parser.parse(pubdate)
68−
69− # http to https
70− thumbnail = thumbnail.replace("http://static.digg.com", "https://static.digg.com")
71
58
59+ published = datetime.strptime(result['created']['ISO'], "%Y-%m-%d %H:%M:%S")
72 # append result
60 # append result
73− results.append({'url': url,
61+ results.append({'url': result['url'],
74− 'title': title,
62+ 'title': result['title'],
75− 'content': content,
63+ 'content': result['excerpt'],
76 'template': 'videos.html',
64 'template': 'videos.html',
77− 'publishedDate': publishedDate,
65+ 'publishedDate': published,
78− 'thumbnail': thumbnail})
66+ 'thumbnail': result['images']['thumbImage']})
79
67
80 # return results
68 # return results
81 return results
69 return results
searx/engines/doku.py+8−7
@@ -11,6 +11,7 @@
11
11
12from lxml.html import fromstring
12from lxml.html import fromstring
13from searx.engines.xpath import extract_text
13from searx.engines.xpath import extract_text
14+from searx.utils import eval_xpath
14from searx.url_utils import urlencode
15from searx.url_utils import urlencode
15
16
16# engine dependent config
17# engine dependent config
@@ -45,16 +46,16 @@ def response(resp):
45
46
46 # parse results
47 # parse results
47 # Quickhits
48 # Quickhits
48− for r in doc.xpath('//div[@class="search_quickresult"]/ul/li'):
49+ for r in eval_xpath(doc, '//div[@class="search_quickresult"]/ul/li'):
49 try:
50 try:
50− res_url = r.xpath('.//a[@class="wikilink1"]/@href')[-1]
51+ res_url = eval_xpath(r, './/a[@class="wikilink1"]/@href')[-1]
51 except:
52 except:
52 continue
53 continue
53
54
54 if not res_url:
55 if not res_url:
55 continue
56 continue
56
57
57− title = extract_text(r.xpath('.//a[@class="wikilink1"]/@title'))
58+ title = extract_text(eval_xpath(r, './/a[@class="wikilink1"]/@title'))
58
59
59 # append result
60 # append result
60 results.append({'title': title,
61 results.append({'title': title,
@@ -62,13 +63,13 @@ def response(resp):
62 'url': base_url + res_url})
63 'url': base_url + res_url})
63
64
64 # Search results
65 # Search results
65− for r in doc.xpath('//dl[@class="search_results"]/*'):
66+ for r in eval_xpath(doc, '//dl[@class="search_results"]/*'):
66 try:
67 try:
67 if r.tag == "dt":
68 if r.tag == "dt":
68− res_url = r.xpath('.//a[@class="wikilink1"]/@href')[-1]
69+ res_url = eval_xpath(r, './/a[@class="wikilink1"]/@href')[-1]
69− title = extract_text(r.xpath('.//a[@class="wikilink1"]/@title'))
70+ title = extract_text(eval_xpath(r, './/a[@class="wikilink1"]/@title'))
70 elif r.tag == "dd":
71 elif r.tag == "dd":
71− content = extract_text(r.xpath('.'))
72+ content = extract_text(eval_xpath(r, '.'))
72
73
73 # append result
74 # append result
74 results.append({'title': title,
75 results.append({'title': title,
searx/engines/duckduckgo.py+30−13
@@ -18,7 +18,7 @@ from json import loads
18from searx.engines.xpath import extract_text
18from searx.engines.xpath import extract_text
19from searx.poolrequests import get
19from searx.poolrequests import get
20from searx.url_utils import urlencode
20from searx.url_utils import urlencode
21−from searx.utils import match_language
21+from searx.utils import match_language, eval_xpath
22
22
23# engine dependent config
23# engine dependent config
24categories = ['general']
24categories = ['general']
@@ -65,21 +65,36 @@ def get_region_code(lang, lang_list=[]):
65
65
66
66
67def request(query, params):
67def request(query, params):
68− if params['time_range'] and params['time_range'] not in time_range_dict:
68+ if params['time_range'] not in (None, 'None', '') and params['time_range'] not in time_range_dict:
69 return params
69 return params
70
70
71 offset = (params['pageno'] - 1) * 30
71 offset = (params['pageno'] - 1) * 30
72
72
73 region_code = get_region_code(params['language'], supported_languages)
73 region_code = get_region_code(params['language'], supported_languages)
74− if region_code:
74+ params['url'] = 'https://duckduckgo.com/html/'
75− params['url'] = url.format(
75+ if params['pageno'] > 1:
76− query=urlencode({'q': query, 'kl': region_code}), offset=offset, dc_param=offset)
76+ params['method'] = 'POST'
77+ params['data']['q'] = query
78+ params['data']['s'] = offset
79+ params['data']['dc'] = 30
80+ params['data']['nextParams'] = ''
81+ params['data']['v'] = 'l'
82+ params['data']['o'] = 'json'
83+ params['data']['api'] = '/d.js'
84+ if params['time_range'] in time_range_dict:
85+ params['data']['df'] = time_range_dict[params['time_range']]
86+ if region_code:
87+ params['data']['kl'] = region_code
77 else:
88 else:
89+ if region_code:
78− params['url'] = url.format(
90+ params['url'] = url.format(
91+ query=urlencode({'q': query, 'kl': region_code}), offset=offset, dc_param=offset)
92+ else:
93+ params['url'] = url.format(
79− query=urlencode({'q': query}), offset=offset, dc_param=offset)
94+ query=urlencode({'q': query}), offset=offset, dc_param=offset)
80
95
81− if params['time_range'] in time_range_dict:
96+ if params['time_range'] in time_range_dict:
82− params['url'] += time_range_url.format(range=time_range_dict[params['time_range']])
97+ params['url'] += time_range_url.format(range=time_range_dict[params['time_range']])
83
98
84 return params
99 return params
85
100
@@ -91,17 +106,19 @@ def response(resp):
91 doc = fromstring(resp.text)
106 doc = fromstring(resp.text)
92
107
93 # parse results
108 # parse results
94− for r in doc.xpath(result_xpath):
109+ for i, r in enumerate(eval_xpath(doc, result_xpath)):
110+ if i >= 30:
111+ break
95 try:
112 try:
96− res_url = r.xpath(url_xpath)[-1]
113+ res_url = eval_xpath(r, url_xpath)[-1]
97 except:
114 except:
98 continue
115 continue
99
116
100 if not res_url:
117 if not res_url:
101 continue
118 continue
102
119
103− title = extract_text(r.xpath(title_xpath))
120+ title = extract_text(eval_xpath(r, title_xpath))
104− content = extract_text(r.xpath(content_xpath))
121+ content = extract_text(eval_xpath(r, content_xpath))
105
122
106 # append result
123 # append result
107 results.append({'title': title,
124 results.append({'title': title,
searx/engines/duckduckgo_definitions.py+16−3
@@ -1,3 +1,14 @@
1+"""
2+DuckDuckGo (definitions)
3+
4+- `Instant Answer API`_
5+- `DuckDuckGo query`_
6+
7+.. _Instant Answer API: https://duckduckgo.com/api
8+.. _DuckDuckGo query: https://api.duckduckgo.com/?q=DuckDuckGo&format=json&pretty=1
9+
10+"""
11+
1import json
12import json
2from lxml import html
13from lxml import html
3from re import compile
14from re import compile
@@ -25,7 +36,8 @@ def result_to_text(url, text, htmlResult):
25def request(query, params):
36def request(query, params):
26 params['url'] = url.format(query=urlencode({'q': query}))
37 params['url'] = url.format(query=urlencode({'q': query}))
27 language = match_language(params['language'], supported_languages, language_aliases)
38 language = match_language(params['language'], supported_languages, language_aliases)
28− params['headers']['Accept-Language'] = language.split('-')[0]
39+ language = language.split('-')[0]
40+ params['headers']['Accept-Language'] = language
29 return params
41 return params
30
42
31
43
@@ -43,8 +55,9 @@ def response(resp):
43
55
44 # add answer if there is one
56 # add answer if there is one
45 answer = search_res.get('Answer', '')
57 answer = search_res.get('Answer', '')
46− if answer != '':
58+ if answer:
59+ if search_res.get('AnswerType', '') not in ['calc']:
47− results.append({'answer': html_to_text(answer)})
60+ results.append({'answer': html_to_text(answer)})
48
61
49 # add infobox
62 # add infobox
50 if 'Definition' in search_res:
63 if 'Definition' in search_res:
searx/engines/duden.py+8−7
@@ -11,6 +11,7 @@
11from lxml import html, etree
11from lxml import html, etree
12import re
12import re
13from searx.engines.xpath import extract_text
13from searx.engines.xpath import extract_text
14+from searx.utils import eval_xpath
14from searx.url_utils import quote, urljoin
15from searx.url_utils import quote, urljoin
15from searx import logger
16from searx import logger
16
17
@@ -52,9 +53,9 @@ def response(resp):
52 dom = html.fromstring(resp.text)
53 dom = html.fromstring(resp.text)
53
54
54 try:
55 try:
55− number_of_results_string = re.sub('[^0-9]', '', dom.xpath(
56+ number_of_results_string =\
57+ re.sub('[^0-9]', '',
56− '//a[@class="active" and contains(@href,"/suchen/dudenonline")]/span/text()')[0]
58+ eval_xpath(dom, '//a[@class="active" and contains(@href,"/suchen/dudenonline")]/span/text()')[0])
57− )
58
59
59 results.append({'number_of_results': int(number_of_results_string)})
60 results.append({'number_of_results': int(number_of_results_string)})
60
61
@@ -62,12 +63,12 @@ def response(resp):
62 logger.debug("Couldn't read number of results.")
63 logger.debug("Couldn't read number of results.")
63 pass
64 pass
64
65
65− for result in dom.xpath('//section[not(contains(@class, "essay"))]'):
66+ for result in eval_xpath(dom, '//section[not(contains(@class, "essay"))]'):
66 try:
67 try:
67− url = result.xpath('.//h2/a')[0].get('href')
68+ url = eval_xpath(result, './/h2/a')[0].get('href')
68 url = urljoin(base_url, url)
69 url = urljoin(base_url, url)
69− title = result.xpath('string(.//h2/a)').strip()
70+ title = eval_xpath(result, 'string(.//h2/a)').strip()
70− content = extract_text(result.xpath('.//p'))
71+ content = extract_text(eval_xpath(result, './/p'))
71 # append result
72 # append result
72 results.append({'url': url,
73 results.append({'url': url,
73 'title': title,
74 'title': title,
searx/engines/fdroid.py+14−15
@@ -18,13 +18,13 @@ categories = ['files']
18paging = True
18paging = True
19
19
20# search-url
20# search-url
21−base_url = 'https://f-droid.org/'
21+base_url = 'https://search.f-droid.org/'
22−search_url = base_url + 'repository/browse/?{query}'
22+search_url = base_url + '?{query}'
23
23
24
24
25# do search-request
25# do search-request
26def request(query, params):
26def request(query, params):
27− query = urlencode({'fdfilter': query, 'fdpage': params['pageno']})
27+ query = urlencode({'q': query, 'page': params['pageno'], 'lang': ''})
28 params['url'] = search_url.format(query=query)
28 params['url'] = search_url.format(query=query)
29 return params
29 return params
30
30
@@ -35,17 +35,16 @@ def response(resp):
35
35
36 dom = html.fromstring(resp.text)
36 dom = html.fromstring(resp.text)
37
37
38− for app in dom.xpath('//div[@id="appheader"]'):
38+ for app in dom.xpath('//a[@class="package-header"]'):
39− url = app.xpath('./ancestor::a/@href')[0]
39+ app_url = app.xpath('./@href')[0]
40− title = app.xpath('./p/span/text()')[0]
40+ app_title = extract_text(app.xpath('./div/h4[@class="package-name"]/text()'))
41+ app_content = extract_text(app.xpath('./div/div/span[@class="package-summary"]')).strip() \
42+ + ' - ' + extract_text(app.xpath('./div/div/span[@class="package-license"]')).strip()
41− img_src = app.xpath('.//img/@src')[0]
43+ app_img_src = app.xpath('./img[@class="package-icon"]/@src')[0]
42−
44+
43− content = extract_text(app.xpath('./p')[0])
44− content = content.replace(title, '', 1).strip()
45−
46− results.append({'url': url,
45+ results.append({'url': app_url,
47− 'title': title,
46+ 'title': app_title,
48− 'content': content,
47+ 'content': app_content,
49− 'img_src': img_src})
48+ 'img_src': app_img_src})
50
49
51 return results
50 return results
searx/engines/flickr_noapi.py+6−6
@@ -16,7 +16,8 @@ from json import loads
16from time import time
16from time import time
17import re
17import re
18from searx.engines import logger
18from searx.engines import logger
19−from searx.url_utils import urlencode, unquote
19+from searx.url_utils import urlencode
20+from searx.utils import ecma_unescape, html_to_text
20
21
21logger = logger.getChild('flickr-noapi')
22logger = logger.getChild('flickr-noapi')
22
23
@@ -75,11 +76,10 @@ def response(resp):
75
76
76 for index in legend:
77 for index in legend:
77 photo = model_export['main'][index[0]][int(index[1])][index[2]][index[3]][int(index[4])]
78 photo = model_export['main'][index[0]][int(index[1])][index[2]][index[3]][int(index[4])]
78− author = unquote(photo.get('realname', ''))
79+ author = ecma_unescape(photo.get('realname', ''))
79− source = unquote(photo.get('username', '')) + ' @ Flickr'
80+ source = ecma_unescape(photo.get('username', '')) + ' @ Flickr'
80− title = unquote(photo.get('title', ''))
81+ title = ecma_unescape(photo.get('title', ''))
81− content = unquote(photo.get('description', ''))
82+ content = html_to_text(ecma_unescape(photo.get('description', '')))
82−
83 img_src = None
83 img_src = None
84 # From the biggest to the lowest format
84 # From the biggest to the lowest format
85 for image_size in image_sizes:
85 for image_size in image_sizes:
searx/engines/framalibre.py+4−1
@@ -10,7 +10,10 @@
10 @parse url, title, content, thumbnail, img_src
10 @parse url, title, content, thumbnail, img_src
11"""
11"""
12
12
13+try:
13−from cgi import escape
14+ from cgi import escape
15+except:
16+ from html import escape
14from lxml import html
17from lxml import html
15from searx.engines.xpath import extract_text
18from searx.engines.xpath import extract_text
16from searx.url_utils import urljoin, urlencode
19from searx.url_utils import urljoin, urlencode
searx/engines/gigablast.py+30−13
@@ -14,7 +14,9 @@ import random
14from json import loads
14from json import loads
15from time import time
15from time import time
16from lxml.html import fromstring
16from lxml.html import fromstring
17+from searx.poolrequests import get
17from searx.url_utils import urlencode
18from searx.url_utils import urlencode
19+from searx.utils import eval_xpath
18
20
19# engine dependent config
21# engine dependent config
20categories = ['general']
22categories = ['general']
@@ -30,13 +32,9 @@ search_string = 'search?{query}'\
30 '&c=main'\
32 '&c=main'\
31 '&s={offset}'\
33 '&s={offset}'\
32 '&format=json'\
34 '&format=json'\
33− '&qh=0'\
35+ '&langcountry={lang}'\
34− '&qlang={lang}'\
35 '&ff={safesearch}'\
36 '&ff={safesearch}'\
36− '&rxiec={rxieu}'\
37− '&ulse={ulse}'\
38− '&rand={rxikd}' # current unix timestamp
37+ '&rand={rxikd}'
39−
40# specific xpath variables
38# specific xpath variables
41results_xpath = '//response//result'
39results_xpath = '//response//result'
42url_xpath = './/url'
40url_xpath = './/url'
@@ -45,9 +43,26 @@ content_xpath = './/sum'
45
43
46supported_languages_url = 'https://gigablast.com/search?&rxikd=1'
44supported_languages_url = 'https://gigablast.com/search?&rxikd=1'
47
45
46+extra_param = '' # gigablast requires a random extra parameter
47+# which can be extracted from the source code of the search page
48+
49+
50+def parse_extra_param(text):
51+ global extra_param
52+ param_lines = [x for x in text.splitlines() if x.startswith('var url=') or x.startswith('url=url+')]
53+ extra_param = ''
54+ for l in param_lines:
55+ extra_param += l.split("'")[1]
56+ extra_param = extra_param.split('&')[-1]
57+
58+
59+def init(engine_settings=None):
60+ parse_extra_param(get('http://gigablast.com/search?c=main&qlangcountry=en-us&q=south&s=10').text)
61+
48
62
49# do search-request
63# do search-request
50def request(query, params):
64def request(query, params):
65+ print("EXTRAPARAM:", extra_param)
51 offset = (params['pageno'] - 1) * number_of_results
66 offset = (params['pageno'] - 1) * number_of_results
52
67
53 if params['language'] == 'all':
68 if params['language'] == 'all':
@@ -66,13 +81,11 @@ def request(query, params):
66 search_path = search_string.format(query=urlencode({'q': query}),
81 search_path = search_string.format(query=urlencode({'q': query}),
67 offset=offset,
82 offset=offset,
68 number_of_results=number_of_results,
83 number_of_results=number_of_results,
69− rxikd=int(time() * 1000),
70− rxieu=random.randint(1000000000, 9999999999),
71− ulse=random.randint(100000000, 999999999),
72 lang=language,
84 lang=language,
85+ rxikd=int(time() * 1000),
73 safesearch=safesearch)
86 safesearch=safesearch)
74
87
75− params['url'] = base_url + search_path
88+ params['url'] = base_url + search_path + '&' + extra_param
76
89
77 return params
90 return params
78
91
@@ -82,7 +95,11 @@ def response(resp):
82 results = []
95 results = []
83
96
84 # parse results
97 # parse results
98+ try:
85− response_json = loads(resp.text)
99+ response_json = loads(resp.text)
100+ except:
101+ parse_extra_param(resp.text)
102+ raise Exception('extra param expired, please reload')
86
103
87 for result in response_json['results']:
104 for result in response_json['results']:
88 # append result
105 # append result
@@ -98,9 +115,9 @@ def response(resp):
98def _fetch_supported_languages(resp):
115def _fetch_supported_languages(resp):
99 supported_languages = []
116 supported_languages = []
100 dom = fromstring(resp.text)
117 dom = fromstring(resp.text)
101− links = dom.xpath('//span[@id="menu2"]/a')
118+ links = eval_xpath(dom, '//span[@id="menu2"]/a')
102 for link in links:
119 for link in links:
103− href = link.xpath('./@href')[0].split('lang%3A')
120+ href = eval_xpath(link, './@href')[0].split('lang%3A')
104 if len(href) == 2:
121 if len(href) == 2:
105 code = href[1].split('_')
122 code = href[1].split('_')
106 if len(code) == 2:
123 if len(code) == 2:
searx/engines/google.py+23−29
@@ -14,7 +14,7 @@ from lxml import html, etree
14from searx.engines.xpath import extract_text, extract_url
14from searx.engines.xpath import extract_text, extract_url
15from searx import logger
15from searx import logger
16from searx.url_utils import urlencode, urlparse, parse_qsl
16from searx.url_utils import urlencode, urlparse, parse_qsl
17−from searx.utils import match_language
17+from searx.utils import match_language, eval_xpath
18
18
19logger = logger.getChild('google engine')
19logger = logger.getChild('google engine')
20
20
@@ -107,13 +107,12 @@ images_path = '/images'
107supported_languages_url = 'https://www.google.com/preferences?#languages'
107supported_languages_url = 'https://www.google.com/preferences?#languages'
108
108
109# specific xpath variables
109# specific xpath variables
110−results_xpath = '//div[@class="g"]'
110+results_xpath = '//div[contains(@class, "ZINbbc")]'
111−url_xpath = './/h3/a/@href'
111+url_xpath = './/div[@class="kCrYT"][1]/a/@href'
112−title_xpath = './/h3'
112+title_xpath = './/div[@class="kCrYT"][1]/a/div[1]'
113−content_xpath = './/span[@class="st"]'
113+content_xpath = './/div[@class="kCrYT"][2]//div[contains(@class, "BNeawe")]//div[contains(@class, "BNeawe")]'
114−content_misc_xpath = './/div[@class="f slp"]'
115−suggestion_xpath = '//p[@class="_Bmc"]'
114+suggestion_xpath = '//div[contains(@class, "ZINbbc")][last()]//div[@class="rVLSBd"]/a//div[contains(@class, "BNeawe")]'
116−spelling_suggestion_xpath = '//a[@class="spell"]'
115+spelling_suggestion_xpath = '//div[@id="scc"]//a'
117
116
118# map : detail location
117# map : detail location
119map_address_xpath = './/div[@class="s"]//table//td[2]/span/text()'
118map_address_xpath = './/div[@class="s"]//table//td[2]/span/text()'
@@ -156,7 +155,7 @@ def parse_url(url_string, google_hostname):
156
155
157# returns extract_text on the first result selected by the xpath or None
156# returns extract_text on the first result selected by the xpath or None
158def extract_text_from_dom(result, xpath):
157def extract_text_from_dom(result, xpath):
159− r = result.xpath(xpath)
158+ r = eval_xpath(result, xpath)
160 if len(r) > 0:
159 if len(r) > 0:
161 return extract_text(r[0])
160 return extract_text(r[0])
162 return None
161 return None
@@ -199,9 +198,6 @@ def request(query, params):
199 params['headers']['Accept-Language'] = language + ',' + language + '-' + country
198 params['headers']['Accept-Language'] = language + ',' + language + '-' + country
200 params['headers']['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
199 params['headers']['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
201
200
202− # Force Internet Explorer 12 user agent to avoid loading the new UI that Searx can't parse
203− params['headers']['User-Agent'] = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"
204−
205 params['google_hostname'] = google_hostname
201 params['google_hostname'] = google_hostname
206
202
207 return params
203 return params
@@ -226,21 +222,21 @@ def response(resp):
226 # convert the text to dom
222 # convert the text to dom
227 dom = html.fromstring(resp.text)
223 dom = html.fromstring(resp.text)
228
224
229− instant_answer = dom.xpath('//div[@id="_vBb"]//text()')
225+ instant_answer = eval_xpath(dom, '//div[@id="_vBb"]//text()')
230 if instant_answer:
226 if instant_answer:
231 results.append({'answer': u' '.join(instant_answer)})
227 results.append({'answer': u' '.join(instant_answer)})
232 try:
228 try:
233− results_num = int(dom.xpath('//div[@id="resultStats"]//text()')[0]
229+ results_num = int(eval_xpath(dom, '//div[@id="resultStats"]//text()')[0]
234 .split()[1].replace(',', ''))
230 .split()[1].replace(',', ''))
235 results.append({'number_of_results': results_num})
231 results.append({'number_of_results': results_num})
236 except:
232 except:
237 pass
233 pass
238
234
239 # parse results
235 # parse results
240− for result in dom.xpath(results_xpath):
236+ for result in eval_xpath(dom, results_xpath):
241 try:
237 try:
242− title = extract_text(result.xpath(title_xpath)[0])
238+ title = extract_text(eval_xpath(result, title_xpath)[0])
243− url = parse_url(extract_url(result.xpath(url_xpath), google_url), google_hostname)
239+ url = parse_url(extract_url(eval_xpath(result, url_xpath), google_url), google_hostname)
244 parsed_url = urlparse(url, google_hostname)
240 parsed_url = urlparse(url, google_hostname)
245
241
246 # map result
242 # map result
@@ -249,7 +245,7 @@ def response(resp):
249 continue
245 continue
250 # if parsed_url.path.startswith(maps_path) or parsed_url.netloc.startswith(map_hostname_start):
246 # if parsed_url.path.startswith(maps_path) or parsed_url.netloc.startswith(map_hostname_start):
251 # print "yooooo"*30
247 # print "yooooo"*30
252− # x = result.xpath(map_near)
248+ # x = eval_xpath(result, map_near)
253 # if len(x) > 0:
249 # if len(x) > 0:
254 # # map : near the location
250 # # map : near the location
255 # results = results + parse_map_near(parsed_url, x, google_hostname)
251 # results = results + parse_map_near(parsed_url, x, google_hostname)
@@ -273,9 +269,7 @@ def response(resp):
273 content = extract_text_from_dom(result, content_xpath)
269 content = extract_text_from_dom(result, content_xpath)
274 if content is None:
270 if content is None:
275 continue
271 continue
276− content_misc = extract_text_from_dom(result, content_misc_xpath)
272+
277− if content_misc is not None:
278− content = content_misc + "<br />" + content
279 # append result
273 # append result
280 results.append({'url': url,
274 results.append({'url': url,
281 'title': title,
275 'title': title,
@@ -286,11 +280,11 @@ def response(resp):
286 continue
280 continue
287
281
288 # parse suggestion
282 # parse suggestion
289− for suggestion in dom.xpath(suggestion_xpath):
283+ for suggestion in eval_xpath(dom, suggestion_xpath):
290 # append suggestion
284 # append suggestion
291 results.append({'suggestion': extract_text(suggestion)})
285 results.append({'suggestion': extract_text(suggestion)})
292
286
293− for correction in dom.xpath(spelling_suggestion_xpath):
287+ for correction in eval_xpath(dom, spelling_suggestion_xpath):
294 results.append({'correction': extract_text(correction)})
288 results.append({'correction': extract_text(correction)})
295
289
296 # return results
290 # return results
@@ -299,9 +293,9 @@ def response(resp):
299
293
300def parse_images(result, google_hostname):
294def parse_images(result, google_hostname):
301 results = []
295 results = []
302− for image in result.xpath(images_xpath):
296+ for image in eval_xpath(result, images_xpath):
303− url = parse_url(extract_text(image.xpath(image_url_xpath)[0]), google_hostname)
297+ url = parse_url(extract_text(eval_xpath(image, image_url_xpath)[0]), google_hostname)
304− img_src = extract_text(image.xpath(image_img_src_xpath)[0])
298+ img_src = extract_text(eval_xpath(image, image_img_src_xpath)[0])
305
299
306 # append result
300 # append result
307 results.append({'url': url,
301 results.append({'url': url,
@@ -388,10 +382,10 @@ def attributes_to_html(attributes):
388def _fetch_supported_languages(resp):
382def _fetch_supported_languages(resp):
389 supported_languages = {}
383 supported_languages = {}
390 dom = html.fromstring(resp.text)
384 dom = html.fromstring(resp.text)
391− options = dom.xpath('//*[@id="langSec"]//input[@name="lr"]')
385+ options = eval_xpath(dom, '//*[@id="langSec"]//input[@name="lr"]')
392 for option in options:
386 for option in options:
393− code = option.xpath('./@value')[0].split('_')[-1]
387+ code = eval_xpath(option, './@value')[0].split('_')[-1]
394− name = option.xpath('./@data-name')[0].title()
388+ name = eval_xpath(option, './@data-name')[0].title()
395 supported_languages[code] = {"name": name}
389 supported_languages[code] = {"name": name}
396
390
397 return supported_languages
391 return supported_languages
searx/engines/google_images.py+13−3
@@ -70,11 +70,21 @@ def response(resp):
70
70
71 try:
71 try:
72 metadata = loads(result)
72 metadata = loads(result)
73− img_format = "{0} {1}x{2}".format(metadata['ity'], str(metadata['ow']), str(metadata['oh']))
73+
74− source = "{0} ({1})".format(metadata['st'], metadata['isu'])
74+ img_format = metadata.get('ity', '')
75+ img_width = metadata.get('ow', '')
76+ img_height = metadata.get('oh', '')
77+ if img_width and img_height:
78+ img_format += " {0}x{1}".format(img_width, img_height)
79+
80+ source = metadata.get('st', '')
81+ source_url = metadata.get('isu', '')
82+ if source_url:
83+ source += " ({0})".format(source_url)
84+
75 results.append({'url': metadata['ru'],
85 results.append({'url': metadata['ru'],
76 'title': metadata['pt'],
86 'title': metadata['pt'],
77− 'content': metadata['s'],
87+ 'content': metadata.get('s', ''),
78 'source': source,
88 'source': source,
79 'img_format': img_format,
89 'img_format': img_format,
80 'thumbnail_src': metadata['tu'],
90 'thumbnail_src': metadata['tu'],
searx/engines/google_videos.py+11−9
@@ -75,15 +75,17 @@ def response(resp):
75
75
76 # get thumbnails
76 # get thumbnails
77 script = str(dom.xpath('//script[contains(., "_setImagesSrc")]')[0].text)
77 script = str(dom.xpath('//script[contains(., "_setImagesSrc")]')[0].text)
78− id = result.xpath('.//div[@class="s"]//img/@id')[0]
78+ ids = result.xpath('.//div[@class="s"]//img/@id')
79+ if len(ids) > 0:
80+ thumbnails_data = \
79− thumbnails_data = re.findall('s=\'(.*?)(?:\\\\[a-z,1-9,\\\\]+\'|\')\;var ii=\[(?:|[\'vidthumb\d+\',]+)\'' + id,
81+ re.findall('s=\'(.*?)(?:\\\\[a-z,1-9,\\\\]+\'|\')\;var ii=\[(?:|[\'vidthumb\d+\',]+)\'' + ids[0],
80− script)
82+ script)
81− tmp = []
83+ tmp = []
82− if len(thumbnails_data) != 0:
84+ if len(thumbnails_data) != 0:
83− tmp = re.findall('(data:image/jpeg;base64,[a-z,A-Z,0-9,/,\+]+)', thumbnails_data[0])
85+ tmp = re.findall('(data:image/jpeg;base64,[a-z,A-Z,0-9,/,\+]+)', thumbnails_data[0])
84− thumbnail = ''
86+ thumbnail = ''
85− if len(tmp) != 0:
87+ if len(tmp) != 0:
86− thumbnail = tmp[-1]
88+ thumbnail = tmp[-1]
87
89
88 # append result
90 # append result
89 results.append({'url': url,
91 results.append({'url': url,
searx/engines/invidious.pynew file+100
@@ -0,0 +1,100 @@
1+# Invidious (Videos)
2+#
3+# @website https://invidio.us/
4+# @provide-api yes (https://github.com/omarroth/invidious/wiki/API)
5+#
6+# @using-api yes
7+# @results JSON
8+# @stable yes
9+# @parse url, title, content, publishedDate, thumbnail, embedded
10+
11+from searx.url_utils import quote_plus
12+from dateutil import parser
13+import time
14+
15+# engine dependent config
16+categories = ["videos", "music"]
17+paging = True
18+language_support = True
19+time_range_support = True
20+
21+# search-url
22+base_url = "https://invidio.us/"
23+
24+
25+# do search-request
26+def request(query, params):
27+ time_range_dict = {
28+ "day": "today",
29+ "week": "week",
30+ "month": "month",
31+ "year": "year",
32+ }
33+ search_url = base_url + "api/v1/search?q={query}"
34+ params["url"] = search_url.format(
35+ query=quote_plus(query)
36+ ) + "&page={pageno}".format(pageno=params["pageno"])
37+
38+ if params["time_range"] in time_range_dict:
39+ params["url"] += "&date={timerange}".format(
40+ timerange=time_range_dict[params["time_range"]]
41+ )
42+
43+ if params["language"] != "all":
44+ lang = params["language"].split("-")
45+ if len(lang) == 2:
46+ params["url"] += "&range={lrange}".format(lrange=lang[1])
47+
48+ return params
49+
50+
51+# get response from search-request
52+def response(resp):
53+ results = []
54+
55+ search_results = resp.json()
56+ embedded_url = (
57+ '<iframe width="540" height="304" '
58+ + 'data-src="'
59+ + base_url
60+ + 'embed/{videoid}" '
61+ + 'frameborder="0" allowfullscreen></iframe>'
62+ )
63+
64+ base_invidious_url = base_url + "watch?v="
65+
66+ for result in search_results:
67+ rtype = result.get("type", None)
68+ if rtype == "video":
69+ videoid = result.get("videoId", None)
70+ if not videoid:
71+ continue
72+
73+ url = base_invidious_url + videoid
74+ embedded = embedded_url.format(videoid=videoid)
75+ thumbs = result.get("videoThumbnails", [])
76+ thumb = next(
77+ (th for th in thumbs if th["quality"] == "sddefault"), None
78+ )
79+ if thumb:
80+ thumbnail = thumb.get("url", "")
81+ else:
82+ thumbnail = ""
83+
84+ publishedDate = parser.parse(
85+ time.ctime(result.get("published", 0))
86+ )
87+
88+ results.append(
89+ {
90+ "url": url,
91+ "title": result.get("title", ""),
92+ "content": result.get("description", ""),
93+ "template": "videos.html",
94+ "publishedDate": publishedDate,
95+ "embedded": embedded,
96+ "thumbnail": thumbnail,
97+ }
98+ )
99+
100+ return results
searx/engines/openstreetmap.py+1−1
@@ -24,7 +24,7 @@ result_base_url = 'https://openstreetmap.org/{osm_type}/{osm_id}'
24
24
25# do search-request
25# do search-request
26def request(query, params):
26def request(query, params):
27− params['url'] = base_url + search_string.format(query=query)
27+ params['url'] = base_url + search_string.format(query=query.decode('utf-8'))
28
28
29 return params
29 return params
30
30
searx/engines/qwant.py+1
@@ -50,6 +50,7 @@ def request(query, params):
50 language = match_language(params['language'], supported_languages, language_aliases)
50 language = match_language(params['language'], supported_languages, language_aliases)
51 params['url'] += '&locale=' + language.replace('-', '_').lower()
51 params['url'] += '&locale=' + language.replace('-', '_').lower()
52
52
53+ params['headers']['User-Agent'] = 'Mozilla/5.0 (X11; Linux x86_64; rv:69.0) Gecko/20100101 Firefox/69.0'
53 return params
54 return params
54
55
55
56
searx/engines/seedpeer.pynew file+78
@@ -0,0 +1,78 @@
1+# Seedpeer (Videos, Music, Files)
2+#
3+# @website https://seedpeer.me
4+# @provide-api no (nothing found)
5+#
6+# @using-api no
7+# @results HTML (using search portal)
8+# @stable yes (HTML can change)
9+# @parse url, title, content, seed, leech, magnetlink
10+
11+from lxml import html
12+from json import loads
13+from operator import itemgetter
14+from searx.url_utils import quote, urljoin
15+from searx.engines.xpath import extract_text
16+
17+
18+url = 'https://seedpeer.me/'
19+search_url = url + 'search/{search_term}?page={page_no}'
20+torrent_file_url = url + 'torrent/{torrent_hash}'
21+
22+# specific xpath variables
23+script_xpath = '//script[@type="text/javascript"][not(@src)]'
24+torrent_xpath = '(//table)[2]/tbody/tr'
25+link_xpath = '(./td)[1]/a/@href'
26+age_xpath = '(./td)[2]'
27+size_xpath = '(./td)[3]'
28+
29+
30+# do search-request
31+def request(query, params):
32+ params['url'] = search_url.format(search_term=quote(query),
33+ page_no=params['pageno'])
34+ return params
35+
36+
37+# get response from search-request
38+def response(resp):
39+ results = []
40+ dom = html.fromstring(resp.text)
41+ result_rows = dom.xpath(torrent_xpath)
42+
43+ try:
44+ script_element = dom.xpath(script_xpath)[0]
45+ json_string = script_element.text[script_element.text.find('{'):]
46+ torrents_json = loads(json_string)
47+ except:
48+ return []
49+
50+ # parse results
51+ for torrent_row, torrent_json in zip(result_rows, torrents_json['data']['list']):
52+ title = torrent_json['name']
53+ seed = int(torrent_json['seeds'])
54+ leech = int(torrent_json['peers'])
55+ size = int(torrent_json['size'])
56+ torrent_hash = torrent_json['hash']
57+
58+ torrentfile = torrent_file_url.format(torrent_hash=torrent_hash)
59+ magnetlink = 'magnet:?xt=urn:btih:{}'.format(torrent_hash)
60+
61+ age = extract_text(torrent_row.xpath(age_xpath))
62+ link = torrent_row.xpath(link_xpath)[0]
63+
64+ href = urljoin(url, link)
65+
66+ # append result
67+ results.append({'url': href,
68+ 'title': title,
69+ 'content': age,
70+ 'seed': seed,
71+ 'leech': leech,
72+ 'filesize': size,
73+ 'torrentfile': torrentfile,
74+ 'magnetlink': magnetlink,
75+ 'template': 'torrent.html'})
76+
77+ # return results sorted by seeder
78+ return sorted(results, key=itemgetter('seed'), reverse=True)
searx/engines/soundcloud.py+4−2
@@ -51,7 +51,9 @@ def get_client_id():
51
51
52 if response.ok:
52 if response.ok:
53 tree = html.fromstring(response.content)
53 tree = html.fromstring(response.content)
54+ # script_tags has been moved from /assets/app/ to /assets/ path. I
55+ # found client_id in https://a-v2.sndcdn.com/assets/49-a0c01933-3.js
54− script_tags = tree.xpath("//script[contains(@src, '/assets/app')]")
56+ script_tags = tree.xpath("//script[contains(@src, '/assets/')]")
55 app_js_urls = [script_tag.get('src') for script_tag in script_tags if script_tag is not None]
57 app_js_urls = [script_tag.get('src') for script_tag in script_tags if script_tag is not None]
56
58
57 # extracts valid app_js urls from soundcloud.com content
59 # extracts valid app_js urls from soundcloud.com content
@@ -66,7 +68,7 @@ def get_client_id():
66 return ""
68 return ""
67
69
68
70
69−def init():
71+def init(engine_settings=None):
70 global guest_client_id
72 global guest_client_id
71 # api-key
73 # api-key
72 guest_client_id = get_client_id()
74 guest_client_id = get_client_id()
searx/engines/startpage.py+23−12
@@ -15,6 +15,8 @@ from dateutil import parser
15from datetime import datetime, timedelta
15from datetime import datetime, timedelta
16import re
16import re
17from searx.engines.xpath import extract_text
17from searx.engines.xpath import extract_text
18+from searx.languages import language_codes
19+from searx.utils import eval_xpath
18
20
19# engine dependent config
21# engine dependent config
20categories = ['general']
22categories = ['general']
@@ -22,7 +24,7 @@ categories = ['general']
22# (probably the parameter qid), require
24# (probably the parameter qid), require
23# storing of qid's between mulitble search-calls
25# storing of qid's between mulitble search-calls
24
26
25−# paging = False
27+paging = True
26language_support = True
28language_support = True
27
29
28# search-url
30# search-url
@@ -32,23 +34,32 @@ search_url = base_url + 'do/search'
32# specific xpath variables
34# specific xpath variables
33# ads xpath //div[@id="results"]/div[@id="sponsored"]//div[@class="result"]
35# ads xpath //div[@id="results"]/div[@id="sponsored"]//div[@class="result"]
34# not ads: div[@class="result"] are the direct childs of div[@id="results"]
36# not ads: div[@class="result"] are the direct childs of div[@id="results"]
35−results_xpath = '//li[contains(@class, "search-result") and contains(@class, "search-item")]'
37+results_xpath = '//div[@class="w-gl__result"]'
36−link_xpath = './/h3/a'
38+link_xpath = './/a[@class="w-gl__result-title"]'
37−content_xpath = './p[@class="search-item__body"]'
39+content_xpath = './/p[@class="w-gl__description"]'
38
40
39
41
40# do search-request
42# do search-request
41def request(query, params):
43def request(query, params):
42− offset = (params['pageno'] - 1) * 10
43
44
44 params['url'] = search_url
45 params['url'] = search_url
45 params['method'] = 'POST'
46 params['method'] = 'POST'
46− params['data'] = {'query': query,
47+ params['data'] = {
47− 'startat': offset}
48+ 'query': query,
49+ 'page': params['pageno'],
50+ 'cat': 'web',
51+ 'cmd': 'process_search',
52+ 'engine0': 'v1all',
53+ }
48
54
49 # set language if specified
55 # set language if specified
50 if params['language'] != 'all':
56 if params['language'] != 'all':
51− params['data']['with_language'] = ('lang_' + params['language'].split('-')[0])
57+ language = 'english'
58+ for lc, _, _, lang in language_codes:
59+ if lc == params['language']:
60+ language = lang
61+ params['data']['language'] = language
62+ params['data']['lui'] = language
52
63
53 return params
64 return params
54
65
@@ -60,8 +71,8 @@ def response(resp):
60 dom = html.fromstring(resp.text)
71 dom = html.fromstring(resp.text)
61
72
62 # parse results
73 # parse results
63− for result in dom.xpath(results_xpath):
74+ for result in eval_xpath(dom, results_xpath):
64− links = result.xpath(link_xpath)
75+ links = eval_xpath(result, link_xpath)
65 if not links:
76 if not links:
66 continue
77 continue
67 link = links[0]
78 link = links[0]
@@ -77,8 +88,8 @@ def response(resp):
77
88
78 title = extract_text(link)
89 title = extract_text(link)
79
90
80− if result.xpath(content_xpath):
91+ if eval_xpath(result, content_xpath):
81− content = extract_text(result.xpath(content_xpath))
92+ content = extract_text(eval_xpath(result, content_xpath))
82 else:
93 else:
83 content = ''
94 content = ''
84
95
searx/engines/wikidata.py+1−17
@@ -16,7 +16,7 @@ from searx.poolrequests import get
16from searx.engines.xpath import extract_text
16from searx.engines.xpath import extract_text
17from searx.engines.wikipedia import _fetch_supported_languages, supported_languages_url
17from searx.engines.wikipedia import _fetch_supported_languages, supported_languages_url
18from searx.url_utils import urlencode
18from searx.url_utils import urlencode
19−from searx.utils import match_language
19+from searx.utils import match_language, eval_xpath
20
20
21from json import loads
21from json import loads
22from lxml.html import fromstring
22from lxml.html import fromstring
@@ -57,22 +57,6 @@ language_fallback_xpath = '//sup[contains(@class,"wb-language-fallback-indicator
57calendar_name_xpath = './/sup[contains(@class,"wb-calendar-name")]'
57calendar_name_xpath = './/sup[contains(@class,"wb-calendar-name")]'
58media_xpath = value_xpath + '//div[contains(@class,"commons-media-caption")]//a'
58media_xpath = value_xpath + '//div[contains(@class,"commons-media-caption")]//a'
59
59
60−# xpath_cache
61−xpath_cache = {}
62−
63−
64−def get_xpath(xpath_str):
65− result = xpath_cache.get(xpath_str, None)
66− if not result:
67− result = etree.XPath(xpath_str)
68− xpath_cache[xpath_str] = result
69− return result
70−
71−
72−def eval_xpath(element, xpath_str):
73− xpath = get_xpath(xpath_str)
74− return xpath(element)
75−
76
60
77def get_id_cache(result):
61def get_id_cache(result):
78 id_cache = {}
62 id_cache = {}
searx/engines/wikipedia.py+7−2
@@ -21,7 +21,8 @@ search_url = base_url + u'w/api.php?'\
21 'action=query'\
21 'action=query'\
22 '&format=json'\
22 '&format=json'\
23 '&{query}'\
23 '&{query}'\
24− '&prop=extracts|pageimages'\
24+ '&prop=extracts|pageimages|pageprops'\
25+ '&ppprop=disambiguation'\
25 '&exintro'\
26 '&exintro'\
26 '&explaintext'\
27 '&explaintext'\
27 '&pithumbsize=300'\
28 '&pithumbsize=300'\
@@ -79,12 +80,15 @@ def response(resp):
79
80
80 # wikipedia article's unique id
81 # wikipedia article's unique id
81 # first valid id is assumed to be the requested article
82 # first valid id is assumed to be the requested article
83+ if 'pages' not in search_result['query']:
84+ return results
85+
82 for article_id in search_result['query']['pages']:
86 for article_id in search_result['query']['pages']:
83 page = search_result['query']['pages'][article_id]
87 page = search_result['query']['pages'][article_id]
84 if int(article_id) > 0:
88 if int(article_id) > 0:
85 break
89 break
86
90
87− if int(article_id) < 0:
91+ if int(article_id) < 0 or 'disambiguation' in page.get('pageprops', {}):
88 return []
92 return []
89
93
90 title = page.get('title')
94 title = page.get('title')
@@ -96,6 +100,7 @@ def response(resp):
96 extract = page.get('extract')
100 extract = page.get('extract')
97
101
98 summary = extract_first_paragraph(extract, title, image)
102 summary = extract_first_paragraph(extract, title, image)
103+ summary = summary.replace('() ', '')
99
104
100 # link to wikipedia article
105 # link to wikipedia article
101 wikipedia_link = base_url.format(language=url_lang(resp.search_params['language'])) \
106 wikipedia_link = base_url.format(language=url_lang(resp.search_params['language'])) \
searx/engines/wolframalpha_noapi.py+1−1
@@ -55,7 +55,7 @@ def obtain_token():
55 return token
55 return token
56
56
57
57
58−def init():
58+def init(engine_settings=None):
59 obtain_token()
59 obtain_token()
60
60
61
61
searx/engines/www1x.py+6−29
@@ -11,8 +11,8 @@
11"""
11"""
12
12
13from lxml import html
13from lxml import html
14−import re
15from searx.url_utils import urlencode, urljoin
14from searx.url_utils import urlencode, urljoin
15+from searx.engines.xpath import extract_text
16
16
17# engine dependent config
17# engine dependent config
18categories = ['images']
18categories = ['images']
@@ -34,41 +34,18 @@ def request(query, params):
34def response(resp):
34def response(resp):
35 results = []
35 results = []
36
36
37− # get links from result-text
37+ dom = html.fromstring(resp.text)
38− regex = re.compile('(</a>|<a)')
38+ for res in dom.xpath('//div[@class="List-item MainListing"]'):
39− results_parts = re.split(regex, resp.text)
40−
41− cur_element = ''
42−
43− # iterate over link parts
44− for result_part in results_parts:
45 # processed start and end of link
39 # processed start and end of link
46− if result_part == '<a':
47− cur_element = result_part
48− continue
49− elif result_part != '</a>':
50− cur_element += result_part
51− continue
52−
53− cur_element += result_part
54−
55− # fix xml-error
56− cur_element = cur_element.replace('"></a>', '"/></a>')
57−
58− dom = html.fromstring(cur_element)
59− link = dom.xpath('//a')[0]
40+ link = res.xpath('//a')[0]
60
41
61 url = urljoin(base_url, link.attrib.get('href'))
42 url = urljoin(base_url, link.attrib.get('href'))
62− title = link.attrib.get('title', '')
43+ title = extract_text(link)
63
44
64− thumbnail_src = urljoin(base_url, link.xpath('.//img')[0].attrib['src'])
45+ thumbnail_src = urljoin(base_url, res.xpath('.//img')[0].attrib['src'])
65 # TODO: get image with higher resolution
46 # TODO: get image with higher resolution
66 img_src = thumbnail_src
47 img_src = thumbnail_src
67
48
68− # check if url is showing to a photo
69− if '/photo/' not in url:
70− continue
71−
72 # append result
49 # append result
73 results.append({'url': url,
50 results.append({'url': url,
74 'title': title,
51 'title': title,
searx/engines/xpath.py+10−10
@@ -1,6 +1,6 @@
1from lxml import html
1from lxml import html
2from lxml.etree import _ElementStringResult, _ElementUnicodeResult
2from lxml.etree import _ElementStringResult, _ElementUnicodeResult
3−from searx.utils import html_to_text
3+from searx.utils import html_to_text, eval_xpath
4from searx.url_utils import unquote, urlencode, urljoin, urlparse
4from searx.url_utils import unquote, urlencode, urljoin, urlparse
5
5
6search_url = None
6search_url = None
@@ -104,15 +104,15 @@ def response(resp):
104 results = []
104 results = []
105 dom = html.fromstring(resp.text)
105 dom = html.fromstring(resp.text)
106 if results_xpath:
106 if results_xpath:
107− for result in dom.xpath(results_xpath):
107+ for result in eval_xpath(dom, results_xpath):
108− url = extract_url(result.xpath(url_xpath), search_url)
108+ url = extract_url(eval_xpath(result, url_xpath), search_url)
109− title = extract_text(result.xpath(title_xpath))
109+ title = extract_text(eval_xpath(result, title_xpath))
110− content = extract_text(result.xpath(content_xpath))
110+ content = extract_text(eval_xpath(result, content_xpath))
111 tmp_result = {'url': url, 'title': title, 'content': content}
111 tmp_result = {'url': url, 'title': title, 'content': content}
112
112
113 # add thumbnail if available
113 # add thumbnail if available
114 if thumbnail_xpath:
114 if thumbnail_xpath:
115− thumbnail_xpath_result = result.xpath(thumbnail_xpath)
115+ thumbnail_xpath_result = eval_xpath(result, thumbnail_xpath)
116 if len(thumbnail_xpath_result) > 0:
116 if len(thumbnail_xpath_result) > 0:
117 tmp_result['img_src'] = extract_url(thumbnail_xpath_result, search_url)
117 tmp_result['img_src'] = extract_url(thumbnail_xpath_result, search_url)
118
118
@@ -120,14 +120,14 @@ def response(resp):
120 else:
120 else:
121 for url, title, content in zip(
121 for url, title, content in zip(
122 (extract_url(x, search_url) for
122 (extract_url(x, search_url) for
123− x in dom.xpath(url_xpath)),
123+ x in eval_xpath(dom, url_xpath)),
124− map(extract_text, dom.xpath(title_xpath)),
124+ map(extract_text, eval_xpath(dom, title_xpath)),
125− map(extract_text, dom.xpath(content_xpath))
125+ map(extract_text, eval_xpath(dom, content_xpath))
126 ):
126 ):
127 results.append({'url': url, 'title': title, 'content': content})
127 results.append({'url': url, 'title': title, 'content': content})
128
128
129 if not suggestion_xpath:
129 if not suggestion_xpath:
130 return results
130 return results
131− for suggestion in dom.xpath(suggestion_xpath):
131+ for suggestion in eval_xpath(dom, suggestion_xpath):
132 results.append({'suggestion': extract_text(suggestion)})
132 results.append({'suggestion': extract_text(suggestion)})
133 return results
133 return results
searx/engines/yahoo.py+9−9
@@ -14,7 +14,7 @@
14from lxml import html
14from lxml import html
15from searx.engines.xpath import extract_text, extract_url
15from searx.engines.xpath import extract_text, extract_url
16from searx.url_utils import unquote, urlencode
16from searx.url_utils import unquote, urlencode
17−from searx.utils import match_language
17+from searx.utils import match_language, eval_xpath
18
18
19# engine dependent config
19# engine dependent config
20categories = ['general']
20categories = ['general']
@@ -109,21 +109,21 @@ def response(resp):
109 dom = html.fromstring(resp.text)
109 dom = html.fromstring(resp.text)
110
110
111 try:
111 try:
112− results_num = int(dom.xpath('//div[@class="compPagination"]/span[last()]/text()')[0]
112+ results_num = int(eval_xpath(dom, '//div[@class="compPagination"]/span[last()]/text()')[0]
113 .split()[0].replace(',', ''))
113 .split()[0].replace(',', ''))
114 results.append({'number_of_results': results_num})
114 results.append({'number_of_results': results_num})
115 except:
115 except:
116 pass
116 pass
117
117
118 # parse results
118 # parse results
119− for result in dom.xpath(results_xpath):
119+ for result in eval_xpath(dom, results_xpath):
120 try:
120 try:
121− url = parse_url(extract_url(result.xpath(url_xpath), search_url))
121+ url = parse_url(extract_url(eval_xpath(result, url_xpath), search_url))
122− title = extract_text(result.xpath(title_xpath)[0])
122+ title = extract_text(eval_xpath(result, title_xpath)[0])
123 except:
123 except:
124 continue
124 continue
125
125
126− content = extract_text(result.xpath(content_xpath)[0])
126+ content = extract_text(eval_xpath(result, content_xpath)[0])
127
127
128 # append result
128 # append result
129 results.append({'url': url,
129 results.append({'url': url,
@@ -131,7 +131,7 @@ def response(resp):
131 'content': content})
131 'content': content})
132
132
133 # if no suggestion found, return results
133 # if no suggestion found, return results
134− suggestions = dom.xpath(suggestion_xpath)
134+ suggestions = eval_xpath(dom, suggestion_xpath)
135 if not suggestions:
135 if not suggestions:
136 return results
136 return results
137
137
@@ -148,9 +148,9 @@ def response(resp):
148def _fetch_supported_languages(resp):
148def _fetch_supported_languages(resp):
149 supported_languages = []
149 supported_languages = []
150 dom = html.fromstring(resp.text)
150 dom = html.fromstring(resp.text)
151− options = dom.xpath('//div[@id="yschlang"]/span/label/input')
151+ options = eval_xpath(dom, '//div[@id="yschlang"]/span/label/input')
152 for option in options:
152 for option in options:
153− code_parts = option.xpath('./@value')[0][5:].split('_')
153+ code_parts = eval_xpath(option, './@value')[0][5:].split('_')
154 if len(code_parts) == 2:
154 if len(code_parts) == 2:
155 code = code_parts[0] + '-' + code_parts[1].upper()
155 code = code_parts[0] + '-' + code_parts[1].upper()
156 else:
156 else:
searx/engines/youtube_noapi.py+9−6
@@ -67,12 +67,8 @@ def response(resp):
67 if videoid is not None:
67 if videoid is not None:
68 url = base_youtube_url + videoid
68 url = base_youtube_url + videoid
69 thumbnail = 'https://i.ytimg.com/vi/' + videoid + '/hqdefault.jpg'
69 thumbnail = 'https://i.ytimg.com/vi/' + videoid + '/hqdefault.jpg'
70− title = video.get('title', {}).get('simpleText', videoid)
70+ title = get_text_from_json(video.get('title', {}))
71− description_snippet = video.get('descriptionSnippet', {})
71+ content = get_text_from_json(video.get('descriptionSnippet', {}))
72− if 'runs' in description_snippet:
73− content = reduce(lambda a, b: a + b.get('text', ''), description_snippet.get('runs'), '')
74− else:
75− content = description_snippet.get('simpleText', '')
76 embedded = embedded_url.format(videoid=videoid)
72 embedded = embedded_url.format(videoid=videoid)
77
73
78 # append result
74 # append result
@@ -85,3 +81,10 @@ def response(resp):
85
81
86 # return results
82 # return results
87 return results
83 return results
84+
85+
86+def get_text_from_json(element):
87+ if 'runs' in element:
88+ return reduce(lambda a, b: a + b.get('text', ''), element.get('runs'), '')
89+ else:
90+ return element.get('simpleText', '')
searx/exceptions.py+1
@@ -28,5 +28,6 @@ class SearxParameterException(SearxException):
28 else:
28 else:
29 message = 'Invalid value "' + value + '" for parameter ' + name
29 message = 'Invalid value "' + value + '" for parameter ' + name
30 super(SearxParameterException, self).__init__(message)
30 super(SearxParameterException, self).__init__(message)
31+ self.message = message
31 self.parameter_name = name
32 self.parameter_name = name
32 self.parameter_value = value
33 self.parameter_value = value
searx/plugins/https_rewrite.py+3
@@ -225,6 +225,9 @@ def https_url_rewrite(result):
225
225
226
226
227def on_result(request, search, result):
227def on_result(request, search, result):
228+ if 'parsed_url' not in result:
229+ return True
230+
228 if result['parsed_url'].scheme == 'http':
231 if result['parsed_url'].scheme == 'http':
229 https_url_rewrite(result)
232 https_url_rewrite(result)
230 return True
233 return True
searx/plugins/oa_doi_rewrite.py+3
@@ -35,6 +35,9 @@ def get_doi_resolver(args, preference_doi_resolver):
35
35
36
36
37def on_result(request, search, result):
37def on_result(request, search, result):
38+ if 'parsed_url' not in result:
39+ return True
40+
38 doi = extract_doi(result['parsed_url'])
41 doi = extract_doi(result['parsed_url'])
39 if doi and len(doi) < 50:
42 if doi and len(doi) < 50:
40 for suffix in ('/', '.pdf', '/full', '/meta', '/abstract'):
43 for suffix in ('/', '.pdf', '/full', '/meta', '/abstract'):
searx/plugins/tracker_url_remover.py+17−10
@@ -17,10 +17,10 @@ along with searx. If not, see < http://www.gnu.org/licenses/ >.
17
17
18from flask_babel import gettext
18from flask_babel import gettext
19import re
19import re
20−from searx.url_utils import urlunparse
20+from searx.url_utils import urlunparse, parse_qsl, urlencode
21
21
22−regexes = {re.compile(r'utm_[^&]+&?'),
22+regexes = {re.compile(r'utm_[^&]+'),
23− re.compile(r'(wkey|wemail)[^&]+&?'),
23+ re.compile(r'(wkey|wemail)[^&]*'),
24 re.compile(r'&$')}
24 re.compile(r'&$')}
25
25
26name = gettext('Tracker URL remover')
26name = gettext('Tracker URL remover')
@@ -30,16 +30,23 @@ preference_section = 'privacy'
30
30
31
31
32def on_result(request, search, result):
32def on_result(request, search, result):
33+ if 'parsed_url' not in result:
34+ return True
35+
33 query = result['parsed_url'].query
36 query = result['parsed_url'].query
34
37
35 if query == "":
38 if query == "":
36 return True
39 return True
37−
40+ parsed_query = parse_qsl(query)
41+
42+ changes = 0
43+ for i, (param_name, _) in enumerate(list(parsed_query)):
38− for reg in regexes:
44+ for reg in regexes:
39− query = reg.sub('', query)
45+ if reg.match(param_name):
40−
46+ parsed_query.pop(i - changes)
41− if query != result['parsed_url'].query:
47+ changes += 1
42− result['parsed_url'] = result['parsed_url']._replace(query=query)
48+ result['parsed_url'] = result['parsed_url']._replace(query=urlencode(parsed_query))
43− result['url'] = urlunparse(result['parsed_url'])
49+ result['url'] = urlunparse(result['parsed_url'])
50+ break
44
51
45 return True
52 return True
searx/query.py+19−2
@@ -43,6 +43,7 @@ class RawTextQuery(object):
43 self.query_parts = []
43 self.query_parts = []
44 self.engines = []
44 self.engines = []
45 self.languages = []
45 self.languages = []
46+ self.timeout_limit = None
46 self.specific = False
47 self.specific = False
47
48
48 # parse query, if tags are set, which
49 # parse query, if tags are set, which
@@ -69,6 +70,21 @@ class RawTextQuery(object):
69 self.query_parts.append(query_part)
70 self.query_parts.append(query_part)
70 continue
71 continue
71
72
73+ # this force the timeout
74+ if query_part[0] == '<':
75+ try:
76+ raw_timeout_limit = int(query_part[1:])
77+ if raw_timeout_limit < 100:
78+ # below 100, the unit is the second ( <3 = 3 seconds timeout )
79+ self.timeout_limit = float(raw_timeout_limit)
80+ else:
81+ # 100 or above, the unit is the millisecond ( <850 = 850 milliseconds timeout )
82+ self.timeout_limit = raw_timeout_limit / 1000.0
83+ parse_next = True
84+ except ValueError:
85+ # error not reported to the user
86+ pass
87+
72 # this force a language
88 # this force a language
73 if query_part[0] == ':':
89 if query_part[0] == ':':
74 lang = query_part[1:].lower().replace('_', '-')
90 lang = query_part[1:].lower().replace('_', '-')
@@ -161,14 +177,15 @@ class RawTextQuery(object):
161class SearchQuery(object):
177class SearchQuery(object):
162 """container for all the search parameters (query, language, etc...)"""
178 """container for all the search parameters (query, language, etc...)"""
163
179
164− def __init__(self, query, engines, categories, lang, safesearch, pageno, time_range):
180+ def __init__(self, query, engines, categories, lang, safesearch, pageno, time_range, timeout_limit=None):
165 self.query = query.encode('utf-8')
181 self.query = query.encode('utf-8')
166 self.engines = engines
182 self.engines = engines
167 self.categories = categories
183 self.categories = categories
168 self.lang = lang
184 self.lang = lang
169 self.safesearch = safesearch
185 self.safesearch = safesearch
170 self.pageno = pageno
186 self.pageno = pageno
171− self.time_range = time_range
187+ self.time_range = None if time_range in ('', 'None', None) else time_range
188+ self.timeout_limit = timeout_limit
172
189
173 def __str__(self):
190 def __str__(self):
174 return str(self.query) + ";" + str(self.engines)
191 return str(self.query) + ";" + str(self.engines)
searx/results.py+50−32
@@ -67,8 +67,9 @@ def merge_two_infoboxes(infobox1, infobox2):
67
67
68 for url2 in infobox2.get('urls', []):
68 for url2 in infobox2.get('urls', []):
69 unique_url = True
69 unique_url = True
70+ parsed_url2 = urlparse(url2.get('url', ''))
70− for url1 in infobox1.get('urls', []):
71+ for url1 in urls1:
71− if compare_urls(urlparse(url1.get('url', '')), urlparse(url2.get('url', ''))):
72+ if compare_urls(urlparse(url1.get('url', '')), parsed_url2):
72 unique_url = False
73 unique_url = False
73 break
74 break
74 if unique_url:
75 if unique_url:
@@ -188,8 +189,9 @@ class ResultContainer(object):
188 add_infobox = True
189 add_infobox = True
189 infobox_id = infobox.get('id', None)
190 infobox_id = infobox.get('id', None)
190 if infobox_id is not None:
191 if infobox_id is not None:
192+ parsed_url_infobox_id = urlparse(infobox_id)
191 for existingIndex in self.infoboxes:
193 for existingIndex in self.infoboxes:
192− if compare_urls(urlparse(existingIndex.get('id', '')), urlparse(infobox_id)):
194+ if compare_urls(urlparse(existingIndex.get('id', '')), parsed_url_infobox_id):
193 merge_two_infoboxes(existingIndex, infobox)
195 merge_two_infoboxes(existingIndex, infobox)
194 add_infobox = False
196 add_infobox = False
195
197
@@ -197,6 +199,13 @@ class ResultContainer(object):
197 self.infoboxes.append(infobox)
199 self.infoboxes.append(infobox)
198
200
199 def _merge_result(self, result, position):
201 def _merge_result(self, result, position):
202+ if 'url' in result:
203+ self.__merge_url_result(result, position)
204+ return
205+
206+ self.__merge_result_no_url(result, position)
207+
208+ def __merge_url_result(self, result, position):
200 result['parsed_url'] = urlparse(result['url'])
209 result['parsed_url'] = urlparse(result['url'])
201
210
202 # if the result has no scheme, use http as default
211 # if the result has no scheme, use http as default
@@ -210,51 +219,60 @@ class ResultContainer(object):
210 if result.get('content'):
219 if result.get('content'):
211 result['content'] = WHITESPACE_REGEX.sub(' ', result['content'])
220 result['content'] = WHITESPACE_REGEX.sub(' ', result['content'])
212
221
213− # check for duplicates
222+ duplicated = self.__find_duplicated_http_result(result)
214− duplicated = False
223+ if duplicated:
224+ self.__merge_duplicated_http_result(duplicated, result, position)
225+ return
226+
227+ # if there is no duplicate found, append result
228+ result['positions'] = [position]
229+ with RLock():
230+ self._merged_results.append(result)
231+
232+ def __find_duplicated_http_result(self, result):
215 result_template = result.get('template')
233 result_template = result.get('template')
216 for merged_result in self._merged_results:
234 for merged_result in self._merged_results:
235+ if 'parsed_url' not in merged_result:
236+ continue
217 if compare_urls(result['parsed_url'], merged_result['parsed_url'])\
237 if compare_urls(result['parsed_url'], merged_result['parsed_url'])\
218 and result_template == merged_result.get('template'):
238 and result_template == merged_result.get('template'):
219 if result_template != 'images.html':
239 if result_template != 'images.html':
220 # not an image, same template, same url : it's a duplicate
240 # not an image, same template, same url : it's a duplicate
221− duplicated = merged_result
241+ return merged_result
222− break
223 else:
242 else:
224 # it's an image
243 # it's an image
225 # it's a duplicate if the parsed_url, template and img_src are differents
244 # it's a duplicate if the parsed_url, template and img_src are differents
226 if result.get('img_src', '') == merged_result.get('img_src', ''):
245 if result.get('img_src', '') == merged_result.get('img_src', ''):
227− duplicated = merged_result
246+ return merged_result
228− break
247+ return None
229
248
230− # merge duplicates together
249+ def __merge_duplicated_http_result(self, duplicated, result, position):
231− if duplicated:
232− # using content with more text
250+ # using content with more text
233− if result_content_len(result.get('content', '')) >\
251+ if result_content_len(result.get('content', '')) >\
234− result_content_len(duplicated.get('content', '')):
252+ result_content_len(duplicated.get('content', '')):
235− duplicated['content'] = result['content']
253+ duplicated['content'] = result['content']
236
254
237− # merge all result's parameters not found in duplicate
255+ # merge all result's parameters not found in duplicate
238− for key in result.keys():
256+ for key in result.keys():
239− if not duplicated.get(key):
257+ if not duplicated.get(key):
240− duplicated[key] = result.get(key)
258+ duplicated[key] = result.get(key)
241
259
242− # add the new position
260+ # add the new position
243− duplicated['positions'].append(position)
261+ duplicated['positions'].append(position)
244
262
245− # add engine to list of result-engines
263+ # add engine to list of result-engines
246− duplicated['engines'].add(result['engine'])
264+ duplicated['engines'].add(result['engine'])
247
265
248− # using https if possible
266+ # using https if possible
249− if duplicated['parsed_url'].scheme != 'https' and result['parsed_url'].scheme == 'https':
267+ if duplicated['parsed_url'].scheme != 'https' and result['parsed_url'].scheme == 'https':
250− duplicated['url'] = result['parsed_url'].geturl()
268+ duplicated['url'] = result['parsed_url'].geturl()
251− duplicated['parsed_url'] = result['parsed_url']
269+ duplicated['parsed_url'] = result['parsed_url']
252
270
253− # if there is no duplicate found, append result
271+ def __merge_result_no_url(self, result, position):
254− else:
272+ result['engines'] = set([result['engine']])
255− result['positions'] = [position]
273+ result['positions'] = [position]
256− with RLock():
274+ with RLock():
257− self._merged_results.append(result)
275+ self._merged_results.append(result)
258
276
259 def order_results(self):
277 def order_results(self):
260 for result in self._merged_results:
278 for result in self._merged_results:
searx/search.py+112−20
@@ -45,6 +45,16 @@ if sys.version_info[0] == 3:
45logger = logger.getChild('search')
45logger = logger.getChild('search')
46
46
47number_of_searches = 0
47number_of_searches = 0
48+max_request_timeout = settings.get('outgoing', {}).get('max_request_timeout' or None)
49+if max_request_timeout is None:
50+ logger.info('max_request_timeout={0}'.format(max_request_timeout))
51+else:
52+ if isinstance(max_request_timeout, float):
53+ logger.info('max_request_timeout={0} second(s)'.format(max_request_timeout))
54+ else:
55+ logger.critical('outgoing.max_request_timeout if defined has to be float')
56+ from sys import exit
57+ exit(1)
48
58
49
59
50def send_http_request(engine, request_params):
60def send_http_request(engine, request_params):
@@ -67,7 +77,7 @@ def send_http_request(engine, request_params):
67 return req(request_params['url'], **request_args)
77 return req(request_params['url'], **request_args)
68
78
69
79
70−def search_one_request(engine, query, request_params):
80+def search_one_http_request(engine, query, request_params):
71 # update request parameters dependent on
81 # update request parameters dependent on
72 # search-engine (contained in engines folder)
82 # search-engine (contained in engines folder)
73 engine.request(query, request_params)
83 engine.request(query, request_params)
@@ -87,7 +97,53 @@ def search_one_request(engine, query, request_params):
87 return engine.response(response)
97 return engine.response(response)
88
98
89
99
100+def search_one_offline_request(engine, query, request_params):
101+ return engine.search(query, request_params)
102+
103+
90def search_one_request_safe(engine_name, query, request_params, result_container, start_time, timeout_limit):
104def search_one_request_safe(engine_name, query, request_params, result_container, start_time, timeout_limit):
105+ if engines[engine_name].offline:
106+ return search_one_offline_request_safe(engine_name, query, request_params, result_container, start_time, timeout_limit) # noqa
107+ return search_one_http_request_safe(engine_name, query, request_params, result_container, start_time, timeout_limit)
108+
109+
110+def search_one_offline_request_safe(engine_name, query, request_params, result_container, start_time, timeout_limit):
111+ engine = engines[engine_name]
112+
113+ try:
114+ search_results = search_one_offline_request(engine, query, request_params)
115+
116+ if search_results:
117+ result_container.extend(engine_name, search_results)
118+
119+ engine_time = time() - start_time
120+ result_container.add_timing(engine_name, engine_time, engine_time)
121+ with threading.RLock():
122+ engine.stats['engine_time'] += engine_time
123+ engine.stats['engine_time_count'] += 1
124+
125+ except ValueError as e:
126+ record_offline_engine_stats_on_error(engine, result_container, start_time)
127+ logger.exception('engine {0} : invalid input : {1}'.format(engine_name, e))
128+ except Exception as e:
129+ record_offline_engine_stats_on_error(engine, result_container, start_time)
130+
131+ result_container.add_unresponsive_engine((
132+ engine_name,
133+ u'{0}: {1}'.format(gettext('unexpected crash'), e),
134+ ))
135+ logger.exception('engine {0} : exception : {1}'.format(engine_name, e))
136+
137+
138+def record_offline_engine_stats_on_error(engine, result_container, start_time):
139+ engine_time = time() - start_time
140+ result_container.add_timing(engine.name, engine_time, engine_time)
141+
142+ with threading.RLock():
143+ engine.stats['errors'] += 1
144+
145+
146+def search_one_http_request_safe(engine_name, query, request_params, result_container, start_time, timeout_limit):
91 # set timeout for all HTTP requests
147 # set timeout for all HTTP requests
92 requests_lib.set_timeout_for_thread(timeout_limit, start_time=start_time)
148 requests_lib.set_timeout_for_thread(timeout_limit, start_time=start_time)
93 # reset the HTTP total time
149 # reset the HTTP total time
@@ -101,7 +157,7 @@ def search_one_request_safe(engine_name, query, request_params, result_container
101
157
102 try:
158 try:
103 # send requests and parse the results
159 # send requests and parse the results
104− search_results = search_one_request(engine, query, request_params)
160+ search_results = search_one_http_request(engine, query, request_params)
105
161
106 # check if the engine accepted the request
162 # check if the engine accepted the request
107 if search_results is not None:
163 if search_results is not None:
@@ -265,6 +321,18 @@ def get_search_query_from_webapp(preferences, form):
265 # query_engines
321 # query_engines
266 query_engines = raw_text_query.engines
322 query_engines = raw_text_query.engines
267
323
324+ # timeout_limit
325+ query_timeout = raw_text_query.timeout_limit
326+ if query_timeout is None and 'timeout_limit' in form:
327+ raw_time_limit = form.get('timeout_limit')
328+ if raw_time_limit in ['None', '']:
329+ raw_time_limit = None
330+ else:
331+ try:
332+ query_timeout = float(raw_time_limit)
333+ except ValueError:
334+ raise SearxParameterException('timeout_limit', raw_time_limit)
335+
268 # query_categories
336 # query_categories
269 query_categories = []
337 query_categories = []
270
338
@@ -338,7 +406,8 @@ def get_search_query_from_webapp(preferences, form):
338 query_engines = deduplicate_query_engines(query_engines)
406 query_engines = deduplicate_query_engines(query_engines)
339
407
340 return (SearchQuery(query, query_engines, query_categories,
408 return (SearchQuery(query, query_engines, query_categories,
341− query_lang, query_safesearch, query_pageno, query_time_range),
409+ query_lang, query_safesearch, query_pageno,
410+ query_time_range, query_timeout),
342 raw_text_query)
411 raw_text_query)
343
412
344
413
@@ -351,6 +420,7 @@ class Search(object):
351 super(Search, self).__init__()
420 super(Search, self).__init__()
352 self.search_query = search_query
421 self.search_query = search_query
353 self.result_container = ResultContainer()
422 self.result_container = ResultContainer()
423+ self.actual_timeout = None
354
424
355 # do search-request
425 # do search-request
356 def search(self):
426 def search(self):
@@ -380,7 +450,7 @@ class Search(object):
380 search_query = self.search_query
450 search_query = self.search_query
381
451
382 # max of all selected engine timeout
452 # max of all selected engine timeout
383− timeout_limit = 0
453+ default_timeout = 0
384
454
385 # start search-reqest for all selected engines
455 # start search-reqest for all selected engines
386 for selected_engine in search_query.engines:
456 for selected_engine in search_query.engines:
@@ -403,29 +473,51 @@ class Search(object):
403 continue
473 continue
404
474
405 # set default request parameters
475 # set default request parameters
476+ request_params = {}
477+ if not engine.offline:
406− request_params = default_request_params()
478+ request_params = default_request_params()
407− request_params['headers']['User-Agent'] = user_agent
479+ request_params['headers']['User-Agent'] = user_agent
408− request_params['category'] = selected_engine['category']
409− request_params['pageno'] = search_query.pageno
410
480
411− if hasattr(engine, 'language') and engine.language:
481+ if hasattr(engine, 'language') and engine.language:
412− request_params['language'] = engine.language
482+ request_params['language'] = engine.language
413− else:
483+ else:
414− request_params['language'] = search_query.lang
484+ request_params['language'] = search_query.lang
415
485
416− # 0 = None, 1 = Moderate, 2 = Strict
486+ request_params['safesearch'] = search_query.safesearch
417− request_params['safesearch'] = search_query.safesearch
487+ request_params['time_range'] = search_query.time_range
488+
489+ request_params['category'] = selected_engine['category']
418− request_params['time_range'] = search_query.time_range
490+ request_params['pageno'] = search_query.pageno
419
491
420 # append request to list
492 # append request to list
421 requests.append((selected_engine['name'], search_query.query, request_params))
493 requests.append((selected_engine['name'], search_query.query, request_params))
422
494
423− # update timeout_limit
495+ # update default_timeout
424− timeout_limit = max(timeout_limit, engine.timeout)
496+ default_timeout = max(default_timeout, engine.timeout)
425−
497+
498+ # adjust timeout
499+ self.actual_timeout = default_timeout
500+ query_timeout = self.search_query.timeout_limit
501+
502+ if max_request_timeout is None and query_timeout is None:
503+ # No max, no user query: default_timeout
504+ pass
505+ elif max_request_timeout is None and query_timeout is not None:
506+ # No max, but user query: From user query except if above default
507+ self.actual_timeout = min(default_timeout, query_timeout)
508+ elif max_request_timeout is not None and query_timeout is None:
509+ # Max, no user query: Default except if above max
510+ self.actual_timeout = min(default_timeout, max_request_timeout)
511+ elif max_request_timeout is not None and query_timeout is not None:
512+ # Max & user query: From user query except if above max
513+ self.actual_timeout = min(query_timeout, max_request_timeout)
514+
515+ logger.debug("actual_timeout={0} (default_timeout={1}, ?timeout_limit={2}, max_request_timeout={3})"
516+ .format(self.actual_timeout, default_timeout, query_timeout, max_request_timeout))
517+
518+ # send all search-request
426 if requests:
519 if requests:
427− # send all search-request
428− search_multiple_requests(requests, self.result_container, start_time, timeout_limit)
520+ search_multiple_requests(requests, self.result_container, start_time, self.actual_timeout)
429 start_new_thread(gc.collect, tuple())
521 start_new_thread(gc.collect, tuple())
430
522
431 # return results, suggestions, answers and infoboxes
523 # return results, suggestions, answers and infoboxes
searx/settings.yml+33−20
@@ -34,7 +34,8 @@ ui:
34# key : !!binary "your_morty_proxy_key"
34# key : !!binary "your_morty_proxy_key"
35
35
36outgoing: # communication with search engines
36outgoing: # communication with search engines
37− request_timeout : 2.0 # seconds
37+ request_timeout : 2.0 # default timeout in seconds, can be override by engine
38+ # max_request_timeout: 10.0 # the maximum timeout in seconds
38 useragent_suffix : "" # suffix of searx_useragent, could contain informations like an email address to the administrator
39 useragent_suffix : "" # suffix of searx_useragent, could contain informations like an email address to the administrator
39 pool_connections : 100 # Number of different hosts
40 pool_connections : 100 # Number of different hosts
40 pool_maxsize : 10 # Number of simultaneous requests by host
41 pool_maxsize : 10 # Number of simultaneous requests by host
@@ -160,11 +161,12 @@ engines:
160 weight : 2
161 weight : 2
161 disabled : True
162 disabled : True
162
163
164+# cloudflare protected
163− - name : digbt
165+# - name : digbt
164− engine : digbt
166+# engine : digbt
165− shortcut : dbt
167+# shortcut : dbt
166− timeout : 6.0
168+# timeout : 6.0
167− disabled : True
169+# disabled : True
168
170
169 - name : digg
171 - name : digg
170 engine : digg
172 engine : digg
@@ -203,11 +205,11 @@ engines:
203 - name : etymonline
205 - name : etymonline
204 engine : xpath
206 engine : xpath
205 paging : True
207 paging : True
206− search_url : http://etymonline.com/?search={query}&p={pageno}
208+ search_url : https://etymonline.com/search?page={pageno}&q={query}
207− url_xpath : //a[contains(@class, "word--")]/@href
209+ url_xpath : //a[contains(@class, "word__name--")]/@href
208− title_xpath : //p[contains(@class, "word__name--")]/text()
210+ title_xpath : //a[contains(@class, "word__name--")]
209− content_xpath : //section[contains(@class, "word__defination")]/object
211+ content_xpath : //section[contains(@class, "word__defination")]
210− first_page_num : 0
212+ first_page_num : 1
211 shortcut : et
213 shortcut : et
212 disabled : True
214 disabled : True
213
215
@@ -392,6 +394,12 @@ engines:
392 timeout : 6.0
394 timeout : 6.0
393 disabled : True
395 disabled : True
394
396
397+ - name : invidious
398+ engine : invidious
399+ base_url : 'https://invidio.us/'
400+ shortcut: iv
401+ timeout : 5.0
402+
395 - name: kickass
403 - name: kickass
396 engine : kickass
404 engine : kickass
397 shortcut : kc
405 shortcut : kc
@@ -400,7 +408,7 @@ engines:
400
408
401 - name : library genesis
409 - name : library genesis
402 engine : xpath
410 engine : xpath
403− search_url : http://libgen.io/search.php?req={query}
411+ search_url : https://libgen.is/search.php?req={query}
404 url_xpath : //a[contains(@href,"bookfi.net")]/@href
412 url_xpath : //a[contains(@href,"bookfi.net")]/@href
405 title_xpath : //a[contains(@href,"book/")]/text()[1]
413 title_xpath : //a[contains(@href,"book/")]/text()[1]
406 content_xpath : //td/a[1][contains(@href,"=author")]/text()
414 content_xpath : //td/a[1][contains(@href,"=author")]/text()
@@ -456,7 +464,7 @@ engines:
456 - name : openairedatasets
464 - name : openairedatasets
457 engine : json_engine
465 engine : json_engine
458 paging : True
466 paging : True
459− search_url : http://api.openaire.eu/search/datasets?format=json&page={pageno}&size=10&title={query}
467+ search_url : https://api.openaire.eu/search/datasets?format=json&page={pageno}&size=10&title={query}
460 results_query : response/results/result
468 results_query : response/results/result
461 url_query : metadata/oaf:entity/oaf:result/children/instance/webresource/url/$
469 url_query : metadata/oaf:entity/oaf:result/children/instance/webresource/url/$
462 title_query : metadata/oaf:entity/oaf:result/title/$
470 title_query : metadata/oaf:entity/oaf:result/title/$
@@ -468,7 +476,7 @@ engines:
468 - name : openairepublications
476 - name : openairepublications
469 engine : json_engine
477 engine : json_engine
470 paging : True
478 paging : True
471− search_url : http://api.openaire.eu/search/publications?format=json&page={pageno}&size=10&title={query}
479+ search_url : https://api.openaire.eu/search/publications?format=json&page={pageno}&size=10&title={query}
472 results_query : response/results/result
480 results_query : response/results/result
473 url_query : metadata/oaf:entity/oaf:result/children/instance/webresource/url/$
481 url_query : metadata/oaf:entity/oaf:result/children/instance/webresource/url/$
474 title_query : metadata/oaf:entity/oaf:result/title/$
482 title_query : metadata/oaf:entity/oaf:result/title/$
@@ -699,9 +707,9 @@ engines:
699 shortcut: vo
707 shortcut: vo
700 categories: social media
708 categories: social media
701 search_url : https://searchvoat.co/?t={query}
709 search_url : https://searchvoat.co/?t={query}
702− url_xpath : //div[@class="entry"]/p/a[@class="title"]/@href
710+ url_xpath : //div[@class="entry"]//p[@class="title"]/a/@href
703− title_xpath : //div[@class="entry"]/p/a[@class="title"]
711+ title_xpath : //div[@class="entry"]//p[@class="title"]/a/text()
704− content_xpath : //div[@class="entry"]/p/span[@class="domain"]
712+ content_xpath : //div[@class="entry"]//span[@class="domain"]/a/text()
705 timeout : 10.0
713 timeout : 10.0
706 disabled : True
714 disabled : True
707
715
@@ -739,10 +747,15 @@ engines:
739 title_xpath : ./h2
747 title_xpath : ./h2
740 content_xpath : ./p[@class="s"]
748 content_xpath : ./p[@class="s"]
741 suggestion_xpath : /html/body//div[@class="top-info"]/p[@class="top-info spell"]/a
749 suggestion_xpath : /html/body//div[@class="top-info"]/p[@class="top-info spell"]/a
742− first_page_num : 1
750+ first_page_num : 0
743 page_size : 10
751 page_size : 10
744 disabled : True
752 disabled : True
745
753
754+ - name : seedpeer
755+ shortcut : speu
756+ engine : seedpeer
757+ categories: files, music, videos
758+
746# - name : yacy
759# - name : yacy
747# engine : yacy
760# engine : yacy
748# shortcut : ya
761# shortcut : ya
@@ -802,7 +815,7 @@ locales:
802doi_resolvers :
815doi_resolvers :
803 oadoi.org : 'https://oadoi.org/'
816 oadoi.org : 'https://oadoi.org/'
804 doi.org : 'https://doi.org/'
817 doi.org : 'https://doi.org/'
805− doai.io : 'http://doai.io/'
818+ doai.io : 'https://doai.io/'
806− sci-hub.tw : 'http://sci-hub.tw/'
819+ sci-hub.tw : 'https://sci-hub.tw/'
807
820
808default_doi_resolver : 'oadoi.org'
821default_doi_resolver : 'oadoi.org'
searx/settings_robot.yml+2−2
@@ -43,7 +43,7 @@ locales:
43doi_resolvers :
43doi_resolvers :
44 oadoi.org : 'https://oadoi.org/'
44 oadoi.org : 'https://oadoi.org/'
45 doi.org : 'https://doi.org/'
45 doi.org : 'https://doi.org/'
46− doai.io : 'http://doai.io/'
46+ doai.io : 'https://doai.io/'
47− sci-hub.tw : 'http://sci-hub.tw/'
47+ sci-hub.tw : 'https://sci-hub.tw/'
48
48
49default_doi_resolver : 'oadoi.org'
49default_doi_resolver : 'oadoi.org'
searx/static/css/bootstrap.min.css+1−1
@@ -1 +1 @@
1−/*! 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}
1+/*! normalize.css v3.0.1 | MIT License | git.io/normalize */.sr-only,svg:not(:root){overflow:hidden}hr,img{border:0}body,figure{margin:0}.img-thumbnail,.thumbnail{-o-transition:all .2s ease-in-out}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.pre-scrollable{max-height:340px}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}b,optgroup,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0}mark{background:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{vertical-align:middle}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre,textarea{overflow:auto}code,kbd,pre,samp{font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}.glyphicon,address,cite{font-style:normal}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[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-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{blockquote,img,pre,tr{page-break-inside:avoid}*{text-shadow:none!important;color:#000!important;background:0 0!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^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{border:1px solid #999}thead{display:table-header-group}img{max-width:100%!important}h2,h3,p{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 td,.table-bordered th{border:1px solid #ddd!important}}.btn,.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-warning.active,.btn-warning:active,.btn.active,.btn:active,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover,.form-control,.navbar-toggle,.open>.dropdown-toggle.btn-danger,.open>.dropdown-toggle.btn-default,.open>.dropdown-toggle.btn-info,.open>.dropdown-toggle.btn-primary,.open>.dropdown-toggle.btn-warning{background-image:none}.img-thumbnail,body{background-color:#fff}@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-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:transparent}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:focus,a:hover{color:#2a6496;text-decoration:underline}a:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;width:100%\9;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;border:1px solid #ddd;border-radius:4px;-webkit-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-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;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,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,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,.h5,.h6,h4,h5,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}dt,label{font-weight:700}address,blockquote .small,blockquote footer,blockquote small,dd,dt,pre{line-height:1.42857143}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{background-color:#fcf8e3;padding:.2em}.list-inline,.list-unstyled{padding-left:0;list-style:none}.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}pre code,table{background-color:transparent}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}dl,ol,ul{margin-top:0}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child,ol ol,ol ul,ul ol,ul ul{margin-bottom:0}address,dl{margin-bottom:20px}ol,ul{margin-bottom:10px}.list-inline{margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}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}.container{width:750px}}abbr[data-original-title],abbr[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 .small,blockquote footer,blockquote small{display:block;font-size:80%;color:#777}legend,pre{display:block;color:#333}blockquote .small:before,blockquote footer: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}code,kbd{padding:2px 4px;font-size:90%}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}blockquote:after,blockquote:before{content:""}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{color:#fff;background-color:#333;border-radius:3px;box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;box-shadow:none}pre{padding:9.5px;margin:0 0 10px;font-size:13px;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}.container,.container-fluid{margin-right:auto;margin-left:auto}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;border-radius:0}.container,.container-fluid{padding-left:15px;padding-right:15px}.pre-scrollable{overflow-y:scroll}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.row{margin-left:-15px;margin-right:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.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-md-1,.col-md-10,.col-md-11,.col-md-12,.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-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.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-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{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-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{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-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{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-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{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}}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{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>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered,.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{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,.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{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}.btn-group>.btn-group,.btn-toolbar .btn-group,.btn-toolbar .input-group,.dropdown-menu{float:left}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{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>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset,legend{padding:0;border:0}fieldset{margin:0;min-width:0}legend{width:100%;margin-bottom:20px;font-size:21px;line-height:inherit;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}.form-control,output{font-size:14px;line-height:1.42857143;color:#555;display:block}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}output{padding-top:7px}.form-control{width:100%;height:34px;padding:6px 12px;background-color:#fff;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#777;opacity:1}.form-control:-ms-input-placeholder{color:#777}.form-control::-webkit-input-placeholder{color:#777}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .form-control-feedback,.has-success .help-block,.has-success .radio,.has-success .radio-inline{color:#3c763d}.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=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px;line-height:1.42857143\9}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}.checkbox,.radio{position:relative;display:block;min-height:20px;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-left:-20px;margin-top:4px\9}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:400;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}.checkbox-inline.disabled,.checkbox.disabled label,.radio-inline.disabled,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio label,fieldset[disabled] .radio-inline,fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{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}.form-horizontal .form-group-sm .form-control,.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-horizontal .form-group-lg .form-control,.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.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}.collapsing,.dropdown{position:relative}.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 .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .form-control-feedback,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;border-color:#8a6d3b;background-color:#fcf8e3}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .form-control-feedback,.has-error .help-block,.has-error .radio,.has-error .radio-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.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 .control-label,.form-inline .form-group{margin-bottom:0;vertical-align:middle}.form-inline .form-group{display:inline-block}.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 .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:7px}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}.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}.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;vertical-align:middle;cursor:pointer;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.active:focus,.btn:active:focus,.btn:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{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.active,.btn-default:active,.btn-default:focus,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{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.active,.btn-primary:active,.btn-primary:focus,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#3071a9;border-color:#285e8e}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{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.active,.btn-success:active,.btn-success:focus,.btn-success:hover,.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.active,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{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.active,.btn-info:active,.btn-info:focus,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{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.active,.btn-warning:active,.btn-warning:focus,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{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.active,.btn-danger:active,.btn-danger:focus,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#428bca;font-weight:400;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:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{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=button].btn-block,input[type=reset].btn-block,input[type=submit].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{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-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;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,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.dropdown-menu-right,.dropdown-menu.pull-right{left:auto;right:0}.dropdown-header,.dropdown-menu>li>a{display:block;padding:3px 20px;line-height:1.42857143;white-space:nowrap}.btn-group-vertical>.btn:not(:first-child):not(:last-child),.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn,.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{clear:both;font-weight:400;color:#333}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{text-decoration:none;color:#262626;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;outline:0;background-color:#428bca}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;background-color:transparent;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{font-size:12px;color:#777}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.nav-justified>.dropdown .dropdown-menu,.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}.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-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group-vertical>.btn:focus,.btn-group>.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,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn .caret,.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: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,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn-lg .caret{border-width:5px 5px 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}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group,.input-group-btn>.btn+.btn{margin-left:-1px}.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=checkbox],[data-toggle=buttons]>.btn>input[type=radio]{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}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.nav>li,.nav>li>a{display:block;position:relative}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{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-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){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:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{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:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li>a{padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{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:focus,.nav-tabs>li.active>a:hover{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;margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0;border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-justified>li,.nav-stacked>li{float:none}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#428bca}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li>a{text-align:center;margin-bottom:5px}.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:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}.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:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar-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,.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar{border-radius:4px}.navbar-header{float:left}.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-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-left:0;padding-right:0}}.embed-responsive,.modal,.modal-open,.progress{overflow:hidden}@media (max-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}.navbar-static-top{z-index:1000;border-width:0 0 1px}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,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;font-size:18px;line-height:20px;height:50px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}.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;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}.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 .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}.progress-bar-striped,.progress-striped .progress-bar,.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}@media (min-width:768px){.navbar-toggle{display:none}.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}.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin:8px -15px}@media (min-width:768px){.navbar-form .control-label,.navbar-form .form-group{margin-bottom:0;vertical-align:middle}.navbar-form .form-group{display:inline-block}.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 .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}.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}}.breadcrumb>li,.pagination{display:inline-block}.btn .badge,.btn .label{top:-1px;position:relative}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}}.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:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-nav>li>a,.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{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:focus,.navbar-default .navbar-nav>.open>a:hover{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:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{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:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#777}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>li>a,.navbar-inverse .navbar-text{color:#777}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{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:focus,.navbar-inverse .navbar-nav>.open>a:hover{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:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{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:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#ccc}.breadcrumb>.active{color:#777}.pagination{padding-left:0;margin:20px 0;border-radius:4px}.pager li,.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}.badge,.label{font-weight:700;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center}.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:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca;cursor:default}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{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>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{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:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;background-color:#fff;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;color:#fff;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#428bca}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;color:#fff;background-color:#777;border-radius:10px}.badge:empty{display:none}.list-group-item,.media-object,.thumbnail{display:block}.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.nav-pills>.active>a>.badge,a.list-group-item.active>.badge{color:#428bca;background-color:#fff}.jumbotron,.jumbotron .h1,.jumbotron h1{color:inherit}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;background-color:#eee}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.alert,.thumbnail{margin-bottom:20px}.alert .alert-link,.close{font-weight:700}.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{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-left:auto;margin-right:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.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}.modal,.modal-backdrop{top:0;right:0;bottom:0;left:0}.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{height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0%;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.close,.list-group-item>.badge{float:right}.progress-bar-striped,.progress-striped .progress-bar{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-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:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-striped .progress-bar-info,.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-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;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+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover{text-decoration:none;color:#555;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{background-color:#eee;color:#777}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .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:focus,a.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover{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:focus,a.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover{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:focus,a.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover{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:focus,a.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.panel-heading>.dropdown .dropdown-toggle,.panel-title,.panel-title>a{color:inherit}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-title,.panel>.list-group,.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.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-title{margin-top:0;font-size:16px}.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 .list-group-item{border-width:1px 0;border-radius:0}.panel-group .panel-heading,.panel>.list-group:last-child .list-group-item:last-child,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.list-group:last-child .list-group-item:last-child,.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-left-radius:3px;border-bottom-right-radius:3px}.panel>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:3px;border-top-left-radius:3px}.list-group+.panel-footer,.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.table-responsive:first-child>.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 th:first-child,.panel>.table-responsive:first-child>.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 th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.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 th:last-child,.panel>.table-responsive:first-child>.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 th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.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 th:first-child,.panel>.table-responsive:last-child>.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 th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.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 th:last-child,.panel>.table-responsive:last-child>.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 th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.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 td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right: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+.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}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.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,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{font-size:21px;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.carousel-caption,.carousel-control{text-shadow:0 1px 2px rgba(0,0,0,.6)}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.modal-content,.popover,.tt-dropdown-menu{background-clip:padding-box}.modal{display:none;position:fixed;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 .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform: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,.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);outline:0}.modal-backdrop{position:fixed;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.43px}.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,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;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,.tooltip.top-left .tooltip-arrow,.tooltip.top-right .tooltip-arrow{bottom:0;border-width:5px 5px 0;border-top-color:#000}.tooltip.top .tooltip-arrow{left:50%;margin-left:-5px}.tooltip.top-left .tooltip-arrow{left:5px}.tooltip.top-right .tooltip-arrow{right:5px}.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,.tooltip.bottom-left .tooltip-arrow,.tooltip.bottom-right .tooltip-arrow{border-width:0 5px 5px;border-bottom-color:#000;top:0}.tooltip.bottom .tooltip-arrow{left:50%;margin-left:-5px}.tooltip.bottom-left .tooltip-arrow{left:5px}.tooltip.bottom-right .tooltip-arrow{right:5px}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);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:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.carousel,.carousel-inner{position:relative}.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,.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.left>.arrow:after,.popover.right>.arrow:after{content:" ";bottom:-10px}.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,.25)}.popover.right>.arrow:after{left:1px;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,.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,.25)}.popover.left>.arrow:after{right:1px;border-right-width:0;border-left-color:#fff}.carousel-inner{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>a>img,.carousel-inner>.item>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}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(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,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:focus,.carousel-control:hover{outline:0;color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{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}.carousel-caption .btn,.text-hide{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{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}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{content:" ";display:table}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row: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}.hidden,.visible-lg,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;background-color:transparent;border:0}.hidden{visibility:hidden!important}.affix{position:fixed;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@-ms-viewport{width:device-width}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}.visible-xs-block{display:block!important}.visible-xs-inline{display:inline!important}.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}td.visible-sm,th.visible-sm{display:table-cell!important}.visible-sm-block{display:block!important}.visible-sm-inline{display:inline!important}.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}td.visible-md,th.visible-md{display:table-cell!important}.visible-md-block{display:block!important}.visible-md-inline{display:inline!important}.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}td.visible-lg,th.visible-lg{display:table-cell!important}.visible-lg-block{display:block!important}.visible-lg-inline{display:inline!important}.visible-lg-inline-block{display:inline-block!important}.hidden-lg{display:none!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}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}td.visible-print,th.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}.hidden-print{display:none!important}}.has-warning .twitter-typeahead .tt-hint,.has-warning .twitter-typeahead .tt-input{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .twitter-typeahead .tt-hint:focus,.has-warning .twitter-typeahead .tt-input:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-error .twitter-typeahead .tt-hint,.has-error .twitter-typeahead .tt-input{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .twitter-typeahead .tt-hint:focus,.has-error .twitter-typeahead .tt-input:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-success .twitter-typeahead .tt-hint,.has-success .twitter-typeahead .tt-input{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .twitter-typeahead .tt-hint:focus,.has-success .twitter-typeahead .tt-input:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.input-group .twitter-typeahead:first-child .tt-hint,.input-group .twitter-typeahead:first-child .tt-input{border-bottom-left-radius:4px;border-top-left-radius:4px}.input-group .twitter-typeahead:last-child .tt-hint,.input-group .twitter-typeahead:last-child .tt-input{border-bottom-right-radius:4px;border-top-right-radius:4px}.input-group.input-group-sm .twitter-typeahead .tt-hint,.input-group.input-group-sm .twitter-typeahead .tt-input{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group.input-group-sm .twitter-typeahead .tt-hint,select.input-group.input-group-sm .twitter-typeahead .tt-input{height:30px;line-height:30px}select[multiple].input-group.input-group-sm .twitter-typeahead .tt-hint,select[multiple].input-group.input-group-sm .twitter-typeahead .tt-input,textarea.input-group.input-group-sm .twitter-typeahead .tt-hint,textarea.input-group.input-group-sm .twitter-typeahead .tt-input{height:auto}.input-group.input-group-sm .twitter-typeahead:not(:first-child):not(:last-child) .tt-hint,.input-group.input-group-sm .twitter-typeahead:not(:first-child):not(:last-child) .tt-input{border-radius:0}.input-group.input-group-sm .twitter-typeahead:first-child .tt-hint,.input-group.input-group-sm .twitter-typeahead:first-child .tt-input{border-radius:3px 0 0 3px}.input-group.input-group-sm .twitter-typeahead:last-child .tt-hint,.input-group.input-group-sm .twitter-typeahead:last-child .tt-input{border-radius:0 3px 3px 0}.input-group.input-group-lg .twitter-typeahead .tt-hint,.input-group.input-group-lg .twitter-typeahead .tt-input{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group.input-group-lg .twitter-typeahead .tt-hint,select.input-group.input-group-lg .twitter-typeahead .tt-input{height:46px;line-height:46px}select[multiple].input-group.input-group-lg .twitter-typeahead .tt-hint,select[multiple].input-group.input-group-lg .twitter-typeahead .tt-input,textarea.input-group.input-group-lg .twitter-typeahead .tt-hint,textarea.input-group.input-group-lg .twitter-typeahead .tt-input{height:auto}.input-group.input-group-lg .twitter-typeahead:not(:first-child):not(:last-child) .tt-hint,.input-group.input-group-lg .twitter-typeahead:not(:first-child):not(:last-child) .tt-input{border-radius:0}.input-group.input-group-lg .twitter-typeahead:first-child .tt-hint,.input-group.input-group-lg .twitter-typeahead:first-child .tt-input{border-radius:6px 0 0 6px}.input-group.input-group-lg .twitter-typeahead:last-child .tt-hint,.input-group.input-group-lg .twitter-typeahead:last-child .tt-input{border-radius:0 6px 6px 0}.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,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.tt-dropdown-menu .tt-suggestion{display:block;padding:3px 20px;clear:both;font-weight:400;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}
searx/static/plugins/js/vim_hotkeys.js+10−2
@@ -125,6 +125,14 @@ $(document).ready(function() {
125 }
125 }
126 });
126 });
127
127
128+ function nextResult(current, direction) {
129+ var next = current[direction]();
130+ while (!next.is('.result') && next.length !== 0) {
131+ next = next[direction]();
132+ }
133+ return next
134+ }
135+
128 function highlightResult(which) {
136 function highlightResult(which) {
129 return function() {
137 return function() {
130 var current = $('.result[data-vim-selected]');
138 var current = $('.result[data-vim-selected]');
@@ -157,13 +165,13 @@ $(document).ready(function() {
157 }
165 }
158 break;
166 break;
159 case 'down':
167 case 'down':
160− next = current.next('.result');
168+ next = nextResult(current, 'next');
161 if (next.length === 0) {
169 if (next.length === 0) {
162 next = $('.result:first');
170 next = $('.result:first');
163 }
171 }
164 break;
172 break;
165 case 'up':
173 case 'up':
166− next = current.prev('.result');
174+ next = nextResult(current, 'prev');
167 if (next.length === 0) {
175 if (next.length === 0) {
168 next = $('.result:last');
176 next = $('.result:last');
169 }
177 }
searx/static/themes/courgette/css/style-rtl.css+1−1
@@ -1 +1 @@
1−.q{padding:.5em 1em .5em 3em}#search_submit{left:0;right:auto}.result .favicon{float:right;margin-left:.5em;margin-right:0}#sidebar{right:auto;left:0}#results{padding:0 32px 0 272px}.search.center{padding-right:0;padding-left:17em}.right{right:auto;left:0}#pagination form+form{float:left;margin-top:-2em}.engine-table{text-align:right}
1+#search_submit,#sidebar,.right{right:auto;left:0}.q{padding:.5em 1em .5em 3em}.result .favicon{float:right;margin-left:.5em;margin-right:0}#results{padding:0 32px 0 272px}.search.center{padding-right:0;padding-left:17em}#pagination form+form{float:left;margin-top:-2em}.engine-table{text-align:right}
searx/static/themes/courgette/css/style.css+1−1
@@ -1 +1 @@
1−*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="search"]{-webkit-appearance:textfield}h2{color:#666;text-transform:uppercase}body{font-family:sans-serif;line-height:1.5;margin:0;background:#eee}html{position:relative;min-height:100%}a{color:#666}.title h1{font-size:7em;color:#3498db;margin:0 auto;line-height:100px;margin-top:-20px;padding-bottom:20px}.center{max-width:70em;text-align:center;background:rgba(255,255,255,0.6);padding:2em;margin:7% auto 0;position:relative}.center.search{position:static;width:auto;background:none;margin:auto;padding-top:1.8em}@media screen and (min-width:1001px){.center:after{content:"";z-index:-1;background:url(../img/bg-body-index.jpg) no-repeat;background-size:cover;width:100%;height:100%;top:0;left:0;position:fixed}.center.search:after{content:none}}.autocompleter-choices{position:absolute;margin:0;padding:0;background:#fff}.autocompleter-choices li{padding:.5em 1em}.autocompleter-choices li:hover{background:#3498db;color:#fff;cursor:pointer}#categories{text-align:center}.top_margin{position:absolute;bottom:-3.5em;width:100%;left:0}.top_margin a{display:inline-block;margin-right:1em;color:#fff;text-decoration:none}.top_margin a:hover,.top_margin a:focus{text-decoration:underline}@media screen and (max-width:1000px){.center{background:none}.top_margin a{color:#333}}.checkbox_container{margin-top:1.5em}.checkbox_container label{padding:.5em 1em;color:#333;cursor:pointer;font-size:.9em}.checkbox_container label:hover{background:#3498db;color:#fff}.checkbox_container input[type="checkbox"]{position:absolute;top:-9999px}.checkbox_container input[type="checkbox"]:checked+label{background:#3498db;color:#fff}#categories_container>div{display:inline-block}#categories .hidden{display:none;position:absolute;bottom:1em;left:0;text-align:center;width:100%;font-size:.9em;font-style:italic;color:#333}#categories:hover .hidden{display:block}@media screen and (max-width:900px){#categories_container{letter-spacing:-5px}#categories_container>div{letter-spacing:normal;margin-top:1em}.checkbox_container{margin:0}.checkbox_container label{display:block;background:#ccc;padding:1em;border:1px solid #fff}.top_margin{position:static}#categories .hidden{position:static;display:block}}@media screen and (max-width:900px) and (min-width:501px){#categories_container>div{width:31%;margin-left:2.333%}#categories_container>div:nth-child(3n+1){margin-left:0}}@media screen and (max-width:500px){#categories_container>div{width:48%;margin-left:2%;font-size:.9em}#categories_container>div:nth-child(2n+1){margin-left:0}.title h1{background:url(../img/searx-mobile.png) no-repeat;width:200px;height:39px}}#search_wrapper{position:relative}.q{padding:.5em 3em .5em 1em;width:100%;font-size:1.5em;border:0;color:#666}#search_submit{position:absolute;top:0;right:0;border:0;background:url("../img/search-icon.png") no-repeat scroll center center / 65% auto #3498db;text-indent:-9999px;width:5em;height:100%;cursor:pointer}#search_submit:hover,#search_submit:focus{background-color:#0665a2}#sidebar{background:#3498db;position:fixed;top:0;right:0;width:15em;height:100%;padding:1.5em;text-align:right}.right{position:fixed;bottom:1.5em;width:15em;right:0;z-index:1;padding:0 1.5em;text-align:right}.right a{color:#fff;display:block;text-decoration:none}.right a:hover,.right a:focus{text-decoration:underline}#preferences{background:url("../img/preference-icon.png") no-repeat right center / 12% auto;padding-right:1.8em}#search_url input{border:0;padding:.5em}#sidebar>div{margin-bottom:1em;color:#fff}#sidebar form{display:inline-block}#sidebar input[type="submit"]{background:#ccc;border:0;padding:.5em 1em;cursor:pointer;margin-top:.5em}#sidebar input[type="submit"]:hover,#sidebar input[type="submit"]:focus{color:#fff;background-color:#0665a2}#results{padding-right:17em;padding-left:2em;padding:0 17em 0 2em}.result p{font-size:.9em}.result .content{margin:0;color:#666}.result .url{margin-top:0;color:#ff6530}.result .favicon{float:left;position:relative;top:.5em;margin-right:.5em}.definition_result{background:#ccc;padding:1em}.definition_result .result_title,.definition_result p{margin:0}.result_title{margin-bottom:0;font-weight:normal}.highlight{font-weight:bold}.result_title a{color:#3498db;text-decoration:none}.result_title a:hover,.result_title a:focus{text-decoration:underline}.cache_link{color:#666;font-size:.9em;font-style:italic}.search.center{padding-right:17em}#answers{border:2px solid #3498db;padding:20px;color:#666;text-align:center;max-width:70em;margin:0 auto 20px}#suggestions{margin-bottom:1em}#suggestions span{color:#666}#suggestions form{display:inline-block;vertical-align:top;margin-bottom:.5em}#suggestions input[type="submit"]{color:#333;padding:.5em 1em;border:0;background:#ccc;cursor:pointer}#suggestions input[type="submit"]:hover,#suggestions input[type="submit"]:focus{background:#3498db;color:#fff}#pagination{margin:1.5em 0 2em}#pagination form+form{float:right;margin-top:-2em}input[type="submit"]{display:inline-block;background:#3498db;color:#fff;border:0;padding:.6em 1em;cursor:pointer}input[type="submit"]:hover,input[type="submit"]:focus{background:#0665a2}.row{max-width:60em;margin:auto}.row a{color:#3498db}.row form{letter-spacing:-5px}.row form>*{letter-spacing:normal}.row p{margin:0}.row fieldset{display:inline-block;width:48%;vertical-align:top}.row fieldset:last-of-type{display:block;width:auto;background:none;padding:0}.row fieldset:nth-child(odd){margin-right:2%}.row fieldset:nth-child(2){min-height:10.5em}@media screen and (max-width:900px){.row{margin:0 1em}.row fieldset{width:49%}.row fieldset,.row fieldset:nth-child(odd){margin-right:0}.row fieldset:first-child{width:100%;margin-right:0}.row fieldset:nth-child(even){margin-right:2%}}@media screen and (max-width:800px){.row fieldset{width:100%}select{width:100%}table{font-size:.8em}.right{display:none}#sidebar{display:none}#results{padding:0 2em}.search.center{padding-right:2em}}@media screen and (max-width:400px){.row #categories_container>div{width:100%;margin-left:0}}fieldset{border:0;margin:1em 0;background:#ccc;padding:1.5em}table{width:100%;text-align:left;border:1px solid #ccc;border-collapse:collapse}table th{background:#999;color:#fff}table tr:nth-child(odd){background:#ccc}table th,table td{padding:.5em 1em;border:1px solid #fff}.engine_checkbox label{padding:.5em;background:#3498db;color:#fff;cursor:pointer}.engine_checkbox .deny{background:#3498db}.engine_checkbox .allow{display:none;background:#666}.engine_checkbox input{display:none}.engine_checkbox input:checked+.allow{display:inline}.engine_checkbox input:checked+.allow+.deny{display:none}.row input[type="submit"]{font-size:1em;margin:1em 0 2em}.row .right{position:static;display:inline-block}.row .right a{color:#333;width:auto;text-align:left;padding:0}.small_font{font-size:.8em}table th{padding:1em}legend{background:#eee;padding:0 1em;position:relative}select{border:1px solid #ddd;padding:.5em .8em;font-size:1em}.highlight .hll{background-color:#ffc}.highlight{background:#f8f8f8}.highlight .c{color:#408080;font-style:italic}.highlight .err{border:1px solid #f00}.highlight .k{color:#008000;font-weight:bold}.highlight .o{color:#666}.highlight .cm{color:#408080;font-style:italic}.highlight .cp{color:#bc7a00}.highlight .c1{color:#408080;font-style:italic}.highlight .cs{color:#408080;font-style:italic}.highlight .gd{color:#a00000}.highlight .ge{font-style:italic}.highlight .gr{color:#f00}.highlight .gh{color:#000080;font-weight:bold}.highlight .gi{color:#00a000}.highlight .go{color:#888}.highlight .gp{color:#000080;font-weight:bold}.highlight .gs{font-weight:bold}.highlight .gu{color:#800080;font-weight:bold}.highlight .gt{color:#04d}.highlight .kc{color:#008000;font-weight:bold}.highlight .kd{color:#008000;font-weight:bold}.highlight .kn{color:#008000;font-weight:bold}.highlight .kp{color:#008000}.highlight .kr{color:#008000;font-weight:bold}.highlight .kt{color:#b00040}.highlight .m{color:#666}.highlight .s{color:#ba2121}.highlight .na{color:#7d9029}.highlight .nb{color:#008000}.highlight .nc{color:#00f;font-weight:bold}.highlight .no{color:#800}.highlight .nd{color:#a2f}.highlight .ni{color:#999;font-weight:bold}.highlight .ne{color:#d2413a;font-weight:bold}.highlight .nf{color:#00f}.highlight .nl{color:#a0a000}.highlight .nn{color:#00f;font-weight:bold}.highlight .nt{color:#008000;font-weight:bold}.highlight .nv{color:#19177c}.highlight .ow{color:#a2f;font-weight:bold}.highlight .w{color:#bbb}.highlight .mf{color:#666}.highlight .mh{color:#666}.highlight .mi{color:#666}.highlight .mo{color:#666}.highlight .sb{color:#ba2121}.highlight .sc{color:#ba2121}.highlight .sd{color:#ba2121;font-style:italic}.highlight .s2{color:#ba2121}.highlight .se{color:#b62;font-weight:bold}.highlight .sh{color:#ba2121}.highlight .si{color:#b68;font-weight:bold}.highlight .sx{color:#008000}.highlight .sr{color:#b68}.highlight .s1{color:#ba2121}.highlight .ss{color:#19177c}.highlight .bp{color:#008000}.highlight .vc{color:#19177c}.highlight .vg{color:#19177c}.highlight .vi{color:#19177c}.highlight .il{color:#666}.highlight pre{overflow:auto}.highlight .lineno{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.highlight .lineno::selection{background:transparent}.highlight .lineno::-moz-selection{background:transparent}
1+a,h2{color:#666}.center,html{position:relative}#categories_container>div,.top_margin a{display:inline-block}#categories,.center{text-align:center}#categories .hidden,.cache_link,.highlight .c,.highlight .cm,.highlight .ge,.highlight .sd{font-style:italic}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]{-webkit-appearance:textfield}h2{text-transform:uppercase}body{font-family:sans-serif;line-height:1.5;margin:0;background:#EEE}html{min-height:100%}.title h1{font-size:7em;color:#3498DB;margin:-20px auto 0;line-height:100px;padding-bottom:20px}.center{max-width:70em;background:rgba(255,255,255,.6);padding:2em;margin:7% auto 0}.center.search{position:static;width:auto;background:0 0;margin:auto;padding-top:1.8em}@media screen and (min-width:1001px){.center:after{content:"";z-index:-1;background:url(../img/bg-body-index.jpg) no-repeat;background-size:cover;width:100%;height:100%;top:0;left:0;position:fixed}.center.search:after{content:none}}.autocompleter-choices{position:absolute;margin:0;padding:0;background:#FFF}.autocompleter-choices li{padding:.5em 1em}.autocompleter-choices li:hover{background:#3498DB;color:#FFF;cursor:pointer}.top_margin{position:absolute;bottom:-3.5em;width:100%;left:0}.top_margin a{margin-right:1em;color:#FFF;text-decoration:none}.top_margin a:focus,.top_margin a:hover{text-decoration:underline}@media screen and (max-width:1000px){.center{background:0 0}.top_margin a{color:#333}}.checkbox_container{margin-top:1.5em}.checkbox_container label{padding:.5em 1em;color:#333;cursor:pointer;font-size:.9em}.checkbox_container input[type=checkbox]:checked+label,.checkbox_container label:hover{background:#3498DB;color:#FFF}.checkbox_container input[type=checkbox]{position:absolute;top:-9999px}#categories .hidden{display:none;position:absolute;bottom:1em;left:0;text-align:center;width:100%;font-size:.9em;color:#333}#categories:hover .hidden,.right a{display:block}@media screen and (max-width:900px){#categories_container{letter-spacing:-5px}#categories_container>div{letter-spacing:normal;margin-top:1em}.checkbox_container{margin:0}.checkbox_container label{display:block;background:#CCC;padding:1em;border:1px solid #FFF}.top_margin{position:static}#categories .hidden{position:static;display:block}}@media screen and (max-width:900px) and (min-width:501px){#categories_container>div{width:31%;margin-left:2.333%}#categories_container>div:nth-child(3n+1){margin-left:0}}@media screen and (max-width:500px){#categories_container>div{width:48%;margin-left:2%;font-size:.9em}#categories_container>div:nth-child(2n+1){margin-left:0}.title h1{background:url(../img/searx-mobile.png) no-repeat;width:200px;height:39px}}#search_wrapper{position:relative}.q{padding:.5em 3em .5em 1em;width:100%;font-size:1.5em;border:0;color:#666}.cache_link,.result p{font-size:.9em}#search_submit{position:absolute;top:0;right:0;border:0;background:url(../img/search-icon.png) center center/65% auto no-repeat #3498DB;text-indent:-9999px;width:5em;height:100%;cursor:pointer}#sidebar,.right{position:fixed;width:15em;right:0;text-align:right}#search_submit:focus,#search_submit:hover{background-color:#0665A2}#sidebar{background:#3498DB;top:0;height:100%;padding:1.5em}.right{bottom:1.5em;z-index:1;padding:0 1.5em}.right a{color:#FFF;text-decoration:none}#sidebar form,#suggestions form,.row fieldset{display:inline-block}.right a:focus,.right a:hover{text-decoration:underline}#preferences{background:url(../img/preference-icon.png) right center/12% auto no-repeat;padding-right:1.8em}#search_url input{border:0;padding:.5em}#sidebar>div{margin-bottom:1em;color:#FFF}#sidebar input[type=submit]{background:#CCC;border:0;padding:.5em 1em;cursor:pointer;margin-top:.5em}#sidebar input[type=submit]:focus,#sidebar input[type=submit]:hover{color:#FFF;background-color:#0665A2}#results{padding:0 17em 0 2em}.result .engines{text-align:right}.result .content{margin:0;color:#666}.result .url{margin-top:0;color:#FF6530}.result .favicon{float:left;position:relative;top:.5em;margin-right:.5em}.definition_result{background:#CCC;padding:1em}.definition_result .result_title,.definition_result p{margin:0}.result_title{margin-bottom:0;font-weight:400}.result_title a{color:#3498DB;text-decoration:none}#answers,#suggestions span{color:#666}.result_title a:focus,.result_title a:hover{text-decoration:underline}.cache_link{color:#666}.search.center{padding-right:17em}#answers{border:2px solid #3498DB;padding:20px;text-align:center;max-width:70em;margin:0 auto 20px}#suggestions{margin-bottom:1em}#suggestions form{vertical-align:top;margin-bottom:.5em}#suggestions input[type=submit]{color:#333;padding:.5em 1em;border:0;background:#CCC;cursor:pointer}#suggestions input[type=submit]:focus,#suggestions input[type=submit]:hover{background:#3498DB;color:#FFF}#pagination{margin:1.5em 0 2em}#pagination form+form{float:right;margin-top:-2em}input[type=submit]{display:inline-block;background:#3498DB;color:#FFF;border:0;padding:.6em 1em;cursor:pointer}input[type=submit]:focus,input[type=submit]:hover{background:#0665A2}.row{max-width:60em;margin:auto}.row a{color:#3498DB}.row form{letter-spacing:-5px}.row form>*{letter-spacing:normal}.row p{margin:0}.row fieldset{width:48%;vertical-align:top}.row fieldset:last-of-type{display:block;width:auto;background:0 0;padding:0}fieldset,table tr:nth-child(odd){background:#CCC}.row fieldset:nth-child(odd){margin-right:2%}.row fieldset:nth-child(2){min-height:10.5em}@media screen and (max-width:900px){.row{margin:0 1em}.row fieldset{width:49%}.row fieldset,.row fieldset:nth-child(odd){margin-right:0}.row fieldset:first-child{width:100%;margin-right:0}.row fieldset:nth-child(even){margin-right:2%}}@media screen and (max-width:800px){.row fieldset,select{width:100%}table{font-size:.8em}#sidebar,.right{display:none}#results{padding:0 2em}.search.center{padding-right:2em}}@media screen and (max-width:400px){.row #categories_container>div{width:100%;margin-left:0}}fieldset{border:0;margin:1em 0;padding:1.5em}table{width:100%;text-align:left;border:1px solid #CCC;border-collapse:collapse}table th{background:#999;color:#FFF}table td,table th{padding:.5em 1em;border:1px solid #FFF}.engine_checkbox label{padding:.5em;background:#3498DB;color:#FFF;cursor:pointer}.engine_checkbox .deny{background:#3498DB}.engine_checkbox .allow{display:none;background:#666}.engine_checkbox input{display:none}.engine_checkbox input:checked+.allow{display:inline}.engine_checkbox input:checked+.allow+.deny{display:none}.row input[type=submit]{font-size:1em;margin:1em 0 2em}.row .right{position:static;display:inline-block}.row .right a{color:#333;width:auto;text-align:left;padding:0}.small_font{font-size:.8em}table th{padding:1em}legend{background:#EEE;padding:0 1em;position:relative}select{border:1px solid #DDD;padding:.5em .8em;font-size:1em}.highlight .hll{background-color:#ffc}.highlight{font-weight:700;background:#f8f8f8}.highlight .c{color:#408080}.highlight .err{border:1px solid red}.highlight .k{color:green;font-weight:700}.highlight .o{color:#666}.highlight .cm{color:#408080}.highlight .cp{color:#BC7A00}.highlight .c1,.highlight .cs{color:#408080;font-style:italic}.highlight .gd{color:#A00000}.highlight .gr{color:red}.highlight .gh{color:navy;font-weight:700}.highlight .gi{color:#00A000}.highlight .go{color:#888}.highlight .gp{color:navy;font-weight:700}.highlight .gs{font-weight:700}.highlight .gu{color:purple;font-weight:700}.highlight .gt{color:#04D}.highlight .kc,.highlight .kd,.highlight .kn{color:green;font-weight:700}.highlight .kp{color:green}.highlight .kr{color:green;font-weight:700}.highlight .kt{color:#B00040}.highlight .m{color:#666}.highlight .s{color:#BA2121}.highlight .na{color:#7D9029}.highlight .nb{color:green}.highlight .nc{color:#00F;font-weight:700}.highlight .no{color:#800}.highlight .nd{color:#A2F}.highlight .ni{color:#999;font-weight:700}.highlight .ne{color:#D2413A;font-weight:700}.highlight .nf{color:#00F}.highlight .nl{color:#A0A000}.highlight .nn{color:#00F;font-weight:700}.highlight .nt{color:green;font-weight:700}.highlight .nv{color:#19177C}.highlight .ow{color:#A2F;font-weight:700}.highlight .w{color:#bbb}.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:#666}.highlight .s2,.highlight .sb,.highlight .sc{color:#BA2121}.highlight .sd{color:#BA2121}.highlight .se{color:#B62;font-weight:700}.highlight .sh{color:#BA2121}.highlight .si{color:#B68;font-weight:700}.highlight .sx{color:green}.highlight .sr{color:#B68}.highlight .s1{color:#BA2121}.highlight .ss{color:#19177C}.highlight .bp{color:green}.highlight .vc,.highlight .vg,.highlight .vi{color:#19177C}.highlight .il{color:#666}.highlight pre{overflow:auto}.highlight .lineno{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.highlight .lineno::selection{background:0 0}.highlight .lineno::-moz-selection{background:0 0}
searx/static/themes/courgette/less/style.less+4
@@ -325,6 +325,10 @@ a {
325 font-size: 0.9em;
325 font-size: 0.9em;
326}
326}
327
327
328+.result .engines {
329+ text-align: right;
330+}
331+
328.result .content {
332.result .content {
329 margin: 0;
333 margin: 0;
330 color: #666;
334 color: #666;
searx/static/themes/legacy/css/style.css+1−1
@@ -1 +1 @@
1−.highlight .hll{background-color:#ffc}.highlight{background:#f8f8f8}.highlight .c{color:#408080;font-style:italic}.highlight .err{border:1px solid #f00}.highlight .k{color:#008000;font-weight:bold}.highlight .o{color:#666}.highlight .cm{color:#408080;font-style:italic}.highlight .cp{color:#bc7a00}.highlight .c1{color:#408080;font-style:italic}.highlight .cs{color:#408080;font-style:italic}.highlight .gd{color:#a00000}.highlight .ge{font-style:italic}.highlight .gr{color:#f00}.highlight .gh{color:#000080;font-weight:bold}.highlight .gi{color:#00a000}.highlight .go{color:#888}.highlight .gp{color:#000080;font-weight:bold}.highlight .gs{font-weight:bold}.highlight .gu{color:#800080;font-weight:bold}.highlight .gt{color:#04d}.highlight .kc{color:#008000;font-weight:bold}.highlight .kd{color:#008000;font-weight:bold}.highlight .kn{color:#008000;font-weight:bold}.highlight .kp{color:#008000}.highlight .kr{color:#008000;font-weight:bold}.highlight .kt{color:#b00040}.highlight .m{color:#666}.highlight .s{color:#ba2121}.highlight .na{color:#7d9029}.highlight .nb{color:#008000}.highlight .nc{color:#00f;font-weight:bold}.highlight .no{color:#800}.highlight .nd{color:#a2f}.highlight .ni{color:#999;font-weight:bold}.highlight .ne{color:#d2413a;font-weight:bold}.highlight .nf{color:#00f}.highlight .nl{color:#a0a000}.highlight .nn{color:#00f;font-weight:bold}.highlight .nt{color:#008000;font-weight:bold}.highlight .nv{color:#19177c}.highlight .ow{color:#a2f;font-weight:bold}.highlight .w{color:#bbb}.highlight .mf{color:#666}.highlight .mh{color:#666}.highlight .mi{color:#666}.highlight .mo{color:#666}.highlight .sb{color:#ba2121}.highlight .sc{color:#ba2121}.highlight .sd{color:#ba2121;font-style:italic}.highlight .s2{color:#ba2121}.highlight .se{color:#b62;font-weight:bold}.highlight .sh{color:#ba2121}.highlight .si{color:#b68;font-weight:bold}.highlight .sx{color:#008000}.highlight .sr{color:#b68}.highlight .s1{color:#ba2121}.highlight .ss{color:#19177c}.highlight .bp{color:#008000}.highlight .vc{color:#19177c}.highlight .vg{color:#19177c}.highlight .vi{color:#19177c}.highlight .il{color:#666}.highlight pre{overflow:auto}.highlight .lineno{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.highlight .lineno::selection{background:transparent}.highlight .lineno::-moz-selection{background:transparent}html{font-family:sans-serif;font-size:.9em;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;color:#444;padding:0;margin:0}body,#container{padding:0;margin:0}#container{width:100%;position:absolute;top:0}.search{padding:0;margin:0}.search .checkbox_container label{font-size:.9em;border-bottom:2px solid #e8e7e6}.search .checkbox_container label:hover{border-bottom:2px solid #3498db}.search .checkbox_container input[type="checkbox"]:checked+label{border-bottom:2px solid #2980b9}#search_wrapper{position:relative;width:50em;padding:10px}.center #search_wrapper{margin-left:auto;margin-right:auto}.q{background:none repeat scroll 0 0 #fff;border:1px solid #3498db;color:#222;font-size:16px;height:28px;margin:0;outline:medium none;padding:2px;padding-left:8px;padding-right:0 !important;width:100%;z-index:2}#search_submit{position:absolute;top:13px;right:1px;padding:0;border:0;background:url('../img/search-icon.png') no-repeat;background-size:24px 24px;opacity:.8;width:24px;height:30px;font-size:0}@media screen and (max-width:50em){#search_wrapper{width:90%;clear:both;overflow:hidden}}ul.autocompleter-choices{position:absolute;margin:0;padding:0;list-style:none;border:1px solid #3498db;border-left-color:#3498db;border-right-color:#3498db;border-bottom-color:#3498db;text-align:left;font-family:Verdana,Geneva,Arial,Helvetica,sans-serif;z-index:50;background-color:#fff;color:#444}ul.autocompleter-choices li{position:relative;margin:-2px 0 0 0;padding:.2em 1.5em .2em 1em;display:block;float:none !important;cursor:pointer;font-weight:normal;white-space:nowrap;font-size:1em;line-height:1.5em}ul.autocompleter-choices li.autocompleter-selected{background-color:#444;color:#fff}ul.autocompleter-choices li.autocompleter-selected span.autocompleter-queried{color:#9fcfff}ul.autocompleter-choices span.autocompleter-queried{display:inline;float:none;font-weight:bold;margin:0;padding:0}.row{max-width:800px;margin:20px auto;text-align:justify}.row h1{font-size:3em;margin-top:50px}.row p{padding:0 10px;max-width:700px}.row h3,.row ul{margin:4px 8px}.hmarg{margin:0 20px;border:1px solid #3498db;padding:4px 10px}a:link.hmarg{color:#3498db}a:visited.hmarg{color:#3498db}a:active.hmarg{color:#3498db}a:hover.hmarg{color:#3498db}.top_margin{margin-top:60px}.center{text-align:center}h1{font-size:5em}div.title{background:url('../img/searx.png') no-repeat;width:100%;min-height:80px;background-position:center}div.title h1{visibility:hidden}input[type="submit"]{padding:2px 6px;margin:2px 4px;display:inline-block;background:#3498db;color:#fff;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border:0;cursor:pointer}input[type="checkbox"]{visibility:hidden}fieldset{margin:8px;border:1px solid #3498db}#categories{margin:0 10px;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.checkbox_container{display:inline-block;position:relative;margin:0 3px;padding:0}.checkbox_container input{display:none}.checkbox_container label,.engine_checkbox label{cursor:pointer;padding:4px 10px;margin:0;display:block;text-transform:capitalize;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.checkbox_container input[type="checkbox"]:checked+label{background:#3498db;color:#fff}.engine_checkbox{padding:4px}label.allow{background:#e74c3c;padding:4px 8px;color:#fff;display:none}label.deny{background:#2ecc71;padding:4px 8px;color:#444;display:inline}.engine_checkbox input[type="checkbox"]:checked+label:nth-child(2)+label{display:none}.engine_checkbox input[type="checkbox"]:checked+label.allow{display:inline}a{text-decoration:none;color:#1a11be}a:visited{color:#8e44ad}.result{margin:19px 0 18px 0;padding:0;clear:both}.result_title{margin-bottom:0}.result_title a{color:#2980b9;font-weight:normal;font-size:1.1em}.result_title a:hover{text-decoration:underline}.result_title a:visited{color:#8e44ad}.cache_link{font-size:10px !important}.result h3{font-size:1em;word-wrap:break-word;margin:5px 0 1px 0;padding:0}.result .content{font-size:.8em;margin:0;padding:0;max-width:54em;word-wrap:break-word;line-height:1.24}.result .content img{float:left;margin-right:5px;max-width:200px;max-height:100px}.result .content br.last{clear:both}.result .url{font-size:.8em;margin:0 0 3px 0;padding:0;max-width:54em;word-wrap:break-word;color:#c0392b}.result .published_date{font-size:.8em;color:#888;Margin:5px 20px}.result .thumbnail{width:400px}.engines{color:#888}.small_font{font-size:.8em}.small p{margin:2px 0}.right{float:right}.invisible{display:none}.left{float:left}.highlight{color:#094089}.content .highlight{color:#000}.image_result{display:inline-block;margin:10px 10px;position:relative;max-height:160px}.image_result img{border:0;max-height:160px}.image_result p{margin:0;padding:0}.image_result p span a{display:none;color:#fff}.image_result p:hover span a{display:block;position:absolute;bottom:0;right:0;padding:4px;background-color:rgba(0,0,0,0.6);font-size:.7em}.torrent_result{border-left:10px solid lightgray;padding-left:3px}.torrent_result p{margin:3px;font-size:.8em}.torrent_result a{color:#2980b9}.torrent_result a:hover{text-decoration:underline}.torrent_result a:visited{color:#8e44ad}.definition_result{border-left:10px solid gray;padding-left:3px}.percentage{position:relative;width:300px}.percentage div{background:#444}table{width:100%}td{padding:0 4px}tr:hover{background:#ddd}#results{margin:auto;padding:0;width:50em;margin-bottom:20px}#sidebar{position:fixed;bottom:10px;left:10px;margin:0 2px 5px 5px;padding:0 2px 2px 2px;width:14em}#sidebar input{padding:0;margin:3px;font-size:.8em;display:inline-block;background:transparent;color:#444;cursor:pointer}#sidebar input[type="submit"]{text-decoration:underline}#suggestions form{display:inline}#suggestions,#answers{margin-top:20px;max-width:45em}#suggestions input,#answers input,#infoboxes input{padding:0;margin:3px;font-size:.8em;display:inline-block;background:transparent;color:#444;cursor:pointer}#suggestions input[type="submit"],#answers input[type="submit"],#infoboxes input[type="submit"]{text-decoration:underline}#suggestions-title{color:#888}#answers{border:2px solid #2980b9;padding:20px}#answers form,#infoboxes form{min-width:210px}#infoboxes{position:absolute;top:100px;right:20px;margin:0 2px 5px 5px;padding:0 2px 2px;max-width:21em;word-wrap:break-word;}#infoboxes .infobox{margin:10px 0 10px;border:1px solid #ddd;padding:5px;font-size:.8em}#infoboxes .infobox img{max-width:90%;max-heigt:12em;display:block;margin:5px;padding:5px}#infoboxes .infobox h2{margin:0}#infoboxes .infobox table{table-layout:fixed;}#infoboxes .infobox table td{vertical-align:top}#infoboxes .infobox input{font-size:1em}#infoboxes .infobox br{clear:both}#search_url{margin-top:8px}#search_url input{border:1px solid #888;padding:4px;color:#444;width:14em;display:block;margin:4px;font-size:.8em}#preferences{top:10px;padding:0;border:0;background:url('../img/preference-icon.png') no-repeat;background-size:28px 28px;opacity:.8;width:28px;height:30px;display:block}#preferences *{display:none}#pagination{clear:both}#pagination br{clear:both}#apis{margin-top:8px;clear:both}#categories_container{position:relative}@media screen and (max-width:50em){#results{margin:auto;padding:0;width:90%}.github{display:none}.checkbox_container{display:block;width:90%}.checkbox_container label{border-bottom:0}.preferences_container{display:none;postion:fixed !important;top:100px;right:0}}@media screen and (max-width:75em){div.title h1{font-size:1em}html.touch #categories{width:95%;height:30px;text-align:left;overflow-x:scroll;overflow-y:hidden;-webkit-overflow-scrolling:touch}html.touch #categories #categories_container{width:1000px;width:-moz-max-content;width:-webkit-max-content;width:max-content}html.touch #categories #categories_container .checkbox_container{display:inline-block;width:auto}#categories{font-size:90%;clear:both}#categories .checkbox_container{margin-top:2px;margin:auto}#suggestions,#answers{margin-top:5px}#infoboxes{position:inherit;max-width:inherit}#infoboxes .infobox{clear:both}#infoboxes .infobox img{float:left;max-width:10em}#categories{font-size:90%;clear:both}#categories .checkbox_container{margin-top:2px;margin:auto}#sidebar{position:static;max-width:50em;margin:0 0 2px 0;padding:0;float:none;border:none;width:auto}#sidebar input{border:0}#apis{display:none}#search_url{display:none}.result{border-top:1px solid #e8e7e6;margin:8px 0 8px 0}.result .thumbnail{max-width:98%}.image_result{max-width:98%}.image_result img{max-width:98%}}.favicon{float:left;margin-right:4px;margin-top:2px}.preferences_back{background:none repeat scroll 0 0 #3498db;border:0 none;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;cursor:pointer;display:inline-block;margin:2px 4px;padding:4px 6px}.preferences_back a{color:#fff}.hidden{opacity:0;overflow:hidden;font-size:.8em;position:absolute;bottom:-20px;width:100%;text-position:center;background:white;transition:opacity 1s ease}#categories_container:hover .hidden{transition:opacity 1s ease;opacity:.8}
1+.highlight .c,.highlight .cm,.highlight .ge,.highlight .sd{font-style:italic}#categories,.highlight .lineno{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}#container,.search,body,html{padding:0;margin:0}div.title h1,input[type=checkbox]{visibility:hidden}#categories,.checkbox_container label,.engine_checkbox label,.highlight .lineno{-webkit-touch-callout:none;-khtml-user-select:none}#answers input[type=submit],#infoboxes input[type=submit],#sidebar input[type=submit],#suggestions input[type=submit],.result_title a:hover,.torrent_result a:hover{text-decoration:underline}#infoboxes,.result .content,.result .url,.result h3{word-wrap:break-word}#apis,#infoboxes .infobox br,#pagination,#pagination br,.result,.result .content br.last{clear:both}.highlight .hll{background-color:#ffc}.highlight{background:#f8f8f8}.highlight .c{color:#408080}.highlight .err{border:1px solid red}.highlight .k{color:green;font-weight:700}.highlight .o{color:#666}.highlight .cm{color:#408080}.highlight .cp{color:#BC7A00}.highlight .c1,.highlight .cs{color:#408080;font-style:italic}.highlight .gd{color:#A00000}.highlight .gr{color:red}.highlight .gh{color:navy;font-weight:700}.highlight .gi{color:#00A000}.highlight .go{color:#888}.highlight .gp{color:navy;font-weight:700}.highlight .gs{font-weight:700}.highlight .gu{color:purple;font-weight:700}.highlight .gt{color:#04D}.highlight .kc,.highlight .kd,.highlight .kn{color:green;font-weight:700}.highlight .kp{color:green}.highlight .kr{color:green;font-weight:700}.highlight .kt{color:#B00040}.highlight .m{color:#666}.highlight .s{color:#BA2121}.highlight .na{color:#7D9029}.highlight .nb{color:green}.highlight .nc{color:#00F;font-weight:700}.highlight .no{color:#800}.highlight .nd{color:#A2F}.highlight .ni{color:#999;font-weight:700}.highlight .ne{color:#D2413A;font-weight:700}.highlight .nf{color:#00F}.highlight .nl{color:#A0A000}.highlight .nn{color:#00F;font-weight:700}.highlight .nt{color:green;font-weight:700}.highlight .nv{color:#19177C}.highlight .ow{color:#A2F;font-weight:700}.highlight .w{color:#bbb}.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:#666}.highlight .s2,.highlight .sb,.highlight .sc{color:#BA2121}.highlight .sd{color:#BA2121}.highlight .se{color:#B62;font-weight:700}.highlight .sh{color:#BA2121}.highlight .si{color:#B68;font-weight:700}.highlight .sx{color:green}.highlight .sr{color:#B68}.highlight .s1{color:#BA2121}.highlight .ss{color:#19177C}.highlight .bp{color:green}.highlight .vc,.highlight .vg,.highlight .vi{color:#19177C}.highlight .il{color:#666}.highlight pre{overflow:auto}.highlight .lineno{user-select:none;cursor:default}.highlight .lineno::selection{background:0 0}.highlight .lineno::-moz-selection{background:0 0}html{font-family:sans-serif;font-size:.9em;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;color:#444}#container{width:100%;position:absolute;top:0}.search .checkbox_container label{font-size:.9em;border-bottom:2px solid #E8E7E6}.search .checkbox_container label:hover{border-bottom:2px solid #3498DB}.search .checkbox_container input[type=checkbox]:checked+label{border-bottom:2px solid #2980B9}#search_wrapper{position:relative;width:50em;padding:10px}.center #search_wrapper{margin-left:auto;margin-right:auto}.q,ul.autocompleter-choices{margin:0;border:1px solid #3498DB}.q{background:#FFF;color:#222;font-size:16px;height:28px;outline:0;padding:2px 2px 2px 8px;padding-right:0!important;width:100%;z-index:2}#search_submit{position:absolute;top:13px;right:1px;padding:0;border:0;background:url(../img/search-icon.png) no-repeat;background-size:24px 24px;opacity:.8;width:24px;height:30px;font-size:0}@media screen and (max-width:50em){#search_wrapper{width:90%;clear:both;overflow:hidden}}ul.autocompleter-choices{position:absolute;padding:0;list-style:none;border-left-color:#3498DB;border-right-color:#3498DB;border-bottom-color:#3498DB;text-align:left;font-family:Verdana,Geneva,Arial,Helvetica,sans-serif;z-index:50;background-color:#FFF;color:#444}ul.autocompleter-choices li{position:relative;margin:-2px 0 0;padding:.2em 1.5em .2em 1em;display:block;float:none!important;cursor:pointer;font-weight:400;white-space:nowrap;font-size:1em;line-height:1.5em}ul.autocompleter-choices li.autocompleter-selected{background-color:#444;color:#FFF}ul.autocompleter-choices li.autocompleter-selected span.autocompleter-queried{color:#9FCFFF}ul.autocompleter-choices span.autocompleter-queried{display:inline;float:none;font-weight:700;margin:0;padding:0}.row{max-width:800px;margin:20px auto;text-align:justify}.row h1{font-size:3em;margin-top:50px}.row p{padding:0 10px;max-width:700px}.row h3,.row ul{margin:4px 8px}.hmarg{margin:0 20px;border:1px solid #3498DB;padding:4px 10px}a:active.hmarg,a:hover.hmarg,a:link.hmarg,a:visited.hmarg{color:#3498DB}.top_margin{margin-top:60px}.center{text-align:center}h1{font-size:5em}div.title{background:url(../img/searx.png) center no-repeat;width:100%;min-height:80px}input[type=submit]{padding:2px 6px;margin:2px 4px;display:inline-block;background:#3498DB;color:#FFF;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border:0;cursor:pointer}fieldset{margin:8px;border:1px solid #3498DB}#categories{margin:0 10px;user-select:none}.checkbox_container{display:inline-block;position:relative;margin:0 3px;padding:0}.checkbox_container input{display:none}.checkbox_container label,.engine_checkbox label{cursor:pointer;padding:4px 10px;margin:0;display:block;text-transform:capitalize;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.checkbox_container input[type=checkbox]:checked+label{background:#3498DB;color:#FFF}.engine_checkbox{padding:4px}label.allow{background:#E74C3C;padding:4px 8px;color:#FFF;display:none}label.deny{background:#2ECC71;padding:4px 8px;color:#444;display:inline}.engine_checkbox input[type=checkbox]:checked+label:nth-child(2)+label{display:none}.engine_checkbox input[type=checkbox]:checked+label.allow{display:inline}a{text-decoration:none;color:#1a11be}a:visited{color:#8E44AD}.result{margin:19px 0 18px;padding:0}.result_title{margin-bottom:0}.result_title a{color:#2980B9;font-weight:400;font-size:1.1em}.result_title a:visited{color:#8E44AD}.cache_link{font-size:10px!important}.result h3{font-size:1em;margin:5px 0 1px;padding:0}.result .content,.result .url,.small_font{font-size:.8em}.result .content{margin:0;padding:0;max-width:54em;line-height:1.24}.result .content img{float:left;margin-right:5px;max-width:200px;max-height:100px}.result .url{margin:0 0 3px;padding:0;max-width:54em;color:#C0392B}.result .published_date{font-size:.8em;color:#888;Margin:5px 20px}.result .thumbnail{width:400px}.engines{color:#888}.small p{margin:2px 0}.right{float:right}.invisible{display:none}.left{float:left}.highlight{color:#094089}.content .highlight{color:#000}.image_result{display:inline-block;margin:10px;position:relative;max-height:160px}.image_result img{border:0;max-height:160px}.image_result p{margin:0;padding:0}.image_result p span a{display:none;color:#FFF}.image_result p:hover span a{display:block;position:absolute;bottom:0;right:0;padding:4px;background-color:rgba(0,0,0,.6);font-size:.7em}#categories_container,.percentage{position:relative}.torrent_result{border-left:10px solid #d3d3d3;padding-left:3px}.torrent_result p{margin:3px;font-size:.8em}.torrent_result a{color:#2980B9}.torrent_result a:visited{color:#8E44AD}.definition_result{border-left:10px solid gray;padding-left:3px}.percentage{width:300px}.percentage div{background:#444}table{width:100%}.result-table{margin-bottom:10px}#infoboxes,#sidebar{margin:0 2px 5px 5px;padding:0 2px 2px}td{padding:0 4px}tr:hover{background:#DDD}#results{margin:auto auto 20px;padding:0;width:50em}#sidebar{position:fixed;bottom:10px;left:10px;width:14em}#answers input,#infoboxes input,#sidebar input,#suggestions input{padding:0;margin:3px;font-size:.8em;display:inline-block;background:0 0;color:#444;cursor:pointer}#suggestions form{display:inline}#answers,#suggestions{margin-top:20px;max-width:45em}#suggestions-title{color:#888}#answers{border:2px solid #2980B9;padding:20px}#answers form,#infoboxes form{min-width:210px}#infoboxes{position:absolute;top:100px;right:20px;max-width:21em}#infoboxes .infobox{margin:10px 0;border:1px solid #ddd;padding:5px;font-size:.8em}#infoboxes .infobox img{max-width:90%;max-heigt:12em;display:block;margin:5px;padding:5px}#infoboxes .infobox h2{margin:0}#apis,#search_url{margin-top:8px}#infoboxes .infobox table{table-layout:fixed}#infoboxes .infobox table td{vertical-align:top}#infoboxes .infobox input{font-size:1em}#search_url input{border:1px solid #888;padding:4px;color:#444;width:14em;display:block;margin:4px;font-size:.8em}#preferences{top:10px;padding:0;border:0;background:url(../img/preference-icon.png) no-repeat;background-size:28px 28px;opacity:.8;width:28px;height:30px;display:block}#preferences *{display:none}@media screen and (max-width:50em){#results{margin:auto;padding:0;width:90%}.github{display:none}.checkbox_container{display:block;width:90%}.checkbox_container label{border-bottom:0}.preferences_container{display:none;postion:fixed!important;top:100px;right:0}}@media screen and (max-width:75em){div.title h1{font-size:1em}html.touch #categories{width:95%;height:30px;text-align:left;overflow-x:scroll;overflow-y:hidden;-webkit-overflow-scrolling:touch}html.touch #categories #categories_container{width:1000px;width:-moz-max-content;width:-webkit-max-content;width:max-content}html.touch #categories #categories_container .checkbox_container{display:inline-block;width:auto}#answers,#suggestions{margin-top:5px}#infoboxes{position:inherit;max-width:inherit}#infoboxes .infobox{clear:both}#infoboxes .infobox img{float:left;max-width:10em}#categories{font-size:90%;clear:both}#categories .checkbox_container{margin:auto}#sidebar{position:static;max-width:50em;margin:0 0 2px;padding:0;float:none;border:none;width:auto}#sidebar input{border:0}#apis,#search_url{display:none}.result{border-top:1px solid #E8E7E6;margin:8px 0}.image_result,.image_result img,.result .thumbnail{max-width:98%}}.favicon{float:left;margin-right:4px;margin-top:2px}.preferences_back{background:#3498DB;border:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;cursor:pointer;display:inline-block;margin:2px 4px;padding:4px 6px}.preferences_back a{color:#FFF}.hidden{opacity:0;overflow:hidden;font-size:.8em;position:absolute;bottom:-20px;width:100%;text-position:center;background:#fff;transition:opacity 1s ease}#categories_container:hover .hidden{transition:opacity 1s ease;opacity:.8}
searx/static/themes/legacy/less/autocompleter.less+61−61
@@ -1,61 +1,61 @@
1−/*
1+/*
2− * searx, A privacy-respecting, hackable metasearch engine
2+ * searx, A privacy-respecting, hackable metasearch engine
3− */
3+ */
4−
4+
5−ul {
5+ul {
6− &.autocompleter-choices {
6+ &.autocompleter-choices {
7− position: absolute;
7+ position: absolute;
8− margin: 0;
8+ margin: 0;
9− padding: 0;
9+ padding: 0;
10− list-style: none;
10+ list-style: none;
11− border: 1px solid @color-autocompleter-choices-border;
11+ border: 1px solid @color-autocompleter-choices-border;
12− border-left-color: @color-autocompleter-choices-border-left-right;
12+ border-left-color: @color-autocompleter-choices-border-left-right;
13− border-right-color: @color-autocompleter-choices-border-left-right;
13+ border-right-color: @color-autocompleter-choices-border-left-right;
14− border-bottom-color: @color-autocompleter-choices-border-bottom;
14+ border-bottom-color: @color-autocompleter-choices-border-bottom;
15− text-align: left;
15+ text-align: left;
16− font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
16+ font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
17− z-index: 50;
17+ z-index: 50;
18− background-color: @color-autocompleter-choices-background;
18+ background-color: @color-autocompleter-choices-background;
19− color: @color-autocompleter-choices-font;
19+ color: @color-autocompleter-choices-font;
20−
20+
21− li {
21+ li {
22− position: relative;
22+ position: relative;
23− margin: -2px 0 0 0;
23+ margin: -2px 0 0 0;
24− padding: 0.2em 1.5em 0.2em 1em;
24+ padding: 0.2em 1.5em 0.2em 1em;
25− display: block;
25+ display: block;
26− float: none !important;
26+ float: none !important;
27− cursor: pointer;
27+ cursor: pointer;
28− font-weight: normal;
28+ font-weight: normal;
29− white-space: nowrap;
29+ white-space: nowrap;
30− font-size: 1em;
30+ font-size: 1em;
31− line-height: 1.5em;
31+ line-height: 1.5em;
32−
32+
33− &.autocompleter-selected {
33+ &.autocompleter-selected {
34− background-color: @color-autocompleter-selected-background;
34+ background-color: @color-autocompleter-selected-background;
35− color: @color-autocompleter-selected-font;
35+ color: @color-autocompleter-selected-font;
36−
36+
37− span.autocompleter-queried {
37+ span.autocompleter-queried {
38− color: @color-autocompleter-selected-queried-font;
38+ color: @color-autocompleter-selected-queried-font;
39− }
39+ }
40− }
40+ }
41− }
41+ }
42−
42+
43− span.autocompleter-queried {
43+ span.autocompleter-queried {
44− display: inline;
44+ display: inline;
45− float: none;
45+ float: none;
46− font-weight: bold;
46+ font-weight: bold;
47− margin: 0;
47+ margin: 0;
48− padding: 0;
48+ padding: 0;
49− }
49+ }
50− }
50+ }
51−}
51+}
52−
52+
53−/*.autocompleter-loading {
53+/*.autocompleter-loading {
54− //background-image: url(images/spinner.gif);
54+ //background-image: url(images/spinner.gif);
55− background-repeat: no-repeat;
55+ background-repeat: no-repeat;
56− background-position: right 50%;
56+ background-position: right 50%;
57−}*/
57+}*/
58−
58+
59−/*textarea.autocompleter-loading {
59+/*textarea.autocompleter-loading {
60− background-position: right bottom;
60+ background-position: right bottom;
61−}*/
61+}*/
searx/static/themes/legacy/less/style.less+4
@@ -376,6 +376,10 @@ table {
376 width: 100%;
376 width: 100%;
377}
377}
378
378
379+.result-table {
380+ margin-bottom: 10px;
381+}
382+
379td {
383td {
380 padding: 0 4px;
384 padding: 0 4px;
381}
385}
searx/static/themes/oscar/css/logicodev-dark.cssnew file+732
@@ -0,0 +1,732 @@
1+.searx-navbar {
2+ background: #29314d;
3+ height: 2.3rem;
4+ font-size: 1.3rem;
5+ line-height: 1.3rem;
6+ padding: 0.5rem;
7+ font-weight: bold;
8+ margin-bottom: 0.8rem;
9+}
10+.searx-navbar a,
11+.searx-navbar a:hover {
12+ margin-right: 2.0rem;
13+ color: white;
14+ text-decoration: none;
15+}
16+.searx-navbar .instance a {
17+ color: #01d7d4;
18+ margin-left: 2.0rem;
19+}
20+#main-logo {
21+ margin-top: 20vh;
22+ margin-bottom: 25px;
23+}
24+#main-logo > img {
25+ max-width: 350px;
26+ width: 80%;
27+}
28+* {
29+ border-radius: 0 !important;
30+}
31+html {
32+ position: relative;
33+ min-height: 100%;
34+ color: #29314d;
35+}
36+body {
37+ /* Margin bottom by footer height */
38+ font-family: 'Roboto', Helvetica, Arial, sans-serif;
39+ margin-bottom: 80px;
40+ background-color: white;
41+}
42+body a {
43+ color: #0088cc;
44+}
45+.footer {
46+ position: absolute;
47+ bottom: 0;
48+ width: 100%;
49+ /* Set the fixed height of the footer here */
50+ height: 60px;
51+ text-align: center;
52+ color: #999;
53+}
54+input[type=checkbox]:checked + .label_hide_if_checked,
55+input[type=checkbox]:checked + .label_hide_if_not_checked + .label_hide_if_checked {
56+ display: none;
57+}
58+input[type=checkbox]:not(:checked) + .label_hide_if_not_checked,
59+input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not_checked {
60+ display: none;
61+}
62+.onoff-checkbox {
63+ width: 15%;
64+}
65+.onoffswitch {
66+ position: relative;
67+ width: 110px;
68+ -webkit-user-select: none;
69+ -moz-user-select: none;
70+ -ms-user-select: none;
71+}
72+.onoffswitch-checkbox {
73+ display: none;
74+}
75+.onoffswitch-label {
76+ display: block;
77+ overflow: hidden;
78+ cursor: pointer;
79+ border: 2px solid #FFFFFF !important;
80+ border-radius: 50px !important;
81+}
82+.onoffswitch-inner {
83+ display: block;
84+ transition: margin 0.3s ease-in 0s;
85+}
86+.onoffswitch-inner:before,
87+.onoffswitch-inner:after {
88+ display: block;
89+ float: left;
90+ width: 50%;
91+ height: 30px;
92+ padding: 0;
93+ line-height: 40px;
94+ font-size: 20px;
95+ box-sizing: border-box;
96+ content: "";
97+ background-color: #EEEEEE;
98+}
99+.onoffswitch-switch {
100+ display: block;
101+ width: 37px;
102+ background-color: #01d7d4;
103+ position: absolute;
104+ top: 0;
105+ bottom: 0;
106+ right: 0px;
107+ border: 2px solid #FFFFFF !important;
108+ border-radius: 50px !important;
109+ transition: all 0.3s ease-in 0s;
110+}
111+.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
112+ margin-right: 0;
113+}
114+.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
115+ right: 71px;
116+ background-color: #A1A1A1;
117+}
118+.result_header {
119+ margin-top: 0px;
120+ margin-bottom: 2px;
121+ font-size: 16px;
122+}
123+.result_header .favicon {
124+ margin-bottom: -3px;
125+}
126+.result_header a {
127+ color: #29314d;
128+ text-decoration: none;
129+}
130+.result_header a:hover {
131+ color: #0088cc;
132+}
133+.result_header a:visited {
134+ color: #684898;
135+}
136+.result_header a .highlight {
137+ background-color: #f6f9fa;
138+}
139+.result-content,
140+.result-format,
141+.result-source {
142+ margin-top: 2px;
143+ margin-bottom: 0;
144+ word-wrap: break-word;
145+ color: #666666;
146+ font-size: 13px;
147+}
148+.result-content .highlight,
149+.result-format .highlight,
150+.result-source .highlight {
151+ font-weight: bold;
152+}
153+.result-source {
154+ font-size: 10px;
155+ float: left;
156+}
157+.result-format {
158+ font-size: 10px;
159+ float: right;
160+}
161+.external-link {
162+ color: #069025;
163+ font-size: 12px;
164+ margin-bottom: 15px;
165+}
166+.external-link a {
167+ margin-right: 3px;
168+}
169+.result-default,
170+.result-code,
171+.result-torrent,
172+.result-videos,
173+.result-map {
174+ clear: both;
175+ padding: 2px 4px;
176+}
177+.result-default:hover,
178+.result-code:hover,
179+.result-torrent:hover,
180+.result-videos:hover,
181+.result-map:hover {
182+ background-color: #f6f9fa;
183+}
184+.result-images {
185+ float: left !important;
186+ width: 24%;
187+ margin: .5%;
188+}
189+.result-images a {
190+ display: block;
191+ width: 100%;
192+ background-size: cover;
193+}
194+.img-thumbnail {
195+ margin: 5px;
196+ max-height: 128px;
197+ min-height: 128px;
198+}
199+.result-videos {
200+ clear: both;
201+}
202+.result-videos hr {
203+ margin: 5px 0 15px 0;
204+}
205+.result-videos .collapse {
206+ width: 100%;
207+}
208+.result-videos .in {
209+ margin-bottom: 8px;
210+}
211+.result-torrent {
212+ clear: both;
213+}
214+.result-torrent b {
215+ margin-right: 5px;
216+ margin-left: 5px;
217+}
218+.result-torrent .seeders {
219+ color: #2ecc71;
220+}
221+.result-torrent .leechers {
222+ color: #f35e77;
223+}
224+.result-map {
225+ clear: both;
226+}
227+.result-code {
228+ clear: both;
229+}
230+.result-code .code-fork,
231+.result-code .code-fork a {
232+ color: #666666;
233+}
234+.suggestion_item {
235+ margin: 2px 5px;
236+ max-width: 100%;
237+}
238+.suggestion_item .btn {
239+ max-width: 100%;
240+ white-space: normal;
241+ word-wrap: break-word;
242+ text-align: left;
243+}
244+.result_download {
245+ margin-right: 5px;
246+}
247+#pagination {
248+ margin-top: 30px;
249+ padding-bottom: 60px;
250+}
251+.label-default {
252+ color: #a4a4a4;
253+ background: transparent;
254+}
255+.result .text-muted small {
256+ word-wrap: break-word;
257+}
258+.modal-wrapper {
259+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
260+}
261+.modal-wrapper {
262+ background-clip: padding-box;
263+ background-color: #fff;
264+ border: 1px solid rgba(0, 0, 0, 0.2);
265+ border-radius: 6px;
266+ box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
267+ outline: 0 none;
268+ position: relative;
269+}
270+.infobox .panel-heading {
271+ background-color: #f6f9fa;
272+}
273+.infobox .panel-heading .panel-title {
274+ font-weight: 700;
275+}
276+.infobox p {
277+ font-family: "DejaVu Serif", Georgia, Cambria, "Times New Roman", Times, serif !important;
278+ font-style: italic;
279+}
280+.infobox .btn {
281+ background-color: #2ecc71;
282+ border: none;
283+}
284+.infobox .btn a {
285+ color: white;
286+ margin: 5px;
287+}
288+.infobox .infobox_part {
289+ margin-bottom: 20px;
290+ word-wrap: break-word;
291+ table-layout: fixed;
292+}
293+.infobox .infobox_part:last-child {
294+ margin-bottom: 0;
295+}
296+.search_categories,
297+#categories {
298+ text-transform: capitalize;
299+ margin-bottom: 0.5rem;
300+ display: flex;
301+ flex-wrap: wrap;
302+ flex-flow: row wrap;
303+ align-content: stretch;
304+}
305+.search_categories label,
306+#categories label,
307+.search_categories .input-group-addon,
308+#categories .input-group-addon {
309+ flex-grow: 1;
310+ flex-basis: auto;
311+ font-size: 1.2rem;
312+ font-weight: normal;
313+ background-color: white;
314+ border: #dddddd 1px solid;
315+ border-right: none;
316+ color: #666666;
317+ padding-bottom: 0.4rem;
318+ padding-top: 0.4rem;
319+ text-align: center;
320+ min-width: 50px;
321+}
322+.search_categories label:last-child,
323+#categories label:last-child,
324+.search_categories .input-group-addon:last-child,
325+#categories .input-group-addon:last-child {
326+ border-right: #dddddd 1px solid;
327+}
328+.search_categories input[type="checkbox"]:checked + label,
329+#categories input[type="checkbox"]:checked + label {
330+ color: #29314d;
331+ font-weight: bold;
332+ border-bottom: #01d7d4 5px solid;
333+}
334+#main-logo {
335+ margin-top: 10vh;
336+ margin-bottom: 25px;
337+}
338+#main-logo > img {
339+ max-width: 350px;
340+ width: 80%;
341+}
342+#q {
343+ box-shadow: none;
344+ border-right: none;
345+ border-color: #a4a4a4;
346+}
347+#search_form .input-group-btn .btn {
348+ border-color: #a4a4a4;
349+}
350+#search_form .input-group-btn .btn:hover {
351+ background-color: #2ecc71;
352+ color: white;
353+}
354+.custom-select {
355+ appearance: none;
356+ -webkit-appearance: none;
357+ -moz-appearance: none;
358+ font-size: 1.2rem;
359+ font-weight: normal;
360+ background-color: white;
361+ border: #dddddd 1px solid;
362+ color: #666666;
363+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAQAAACR313BAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
364+AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAJcEhZ
365+cwAABFkAAARZAVnbJUkAAAAHdElNRQfgBxgLDwB20OFsAAAAbElEQVQY073OsQ3CMAAEwJMYwJGn
366+sAehpoXJItltBkmcdZBYgIIiQoLglnz3ui+eP+bk5uneteTMZJa6OJuIqvYzSJoqwqBq8gdmTTW8
367+6/dghxAUq4xsVYT9laBYXCw93Aajh7GPEF23t4fkBYevGFTANkPRAAAAJXRFWHRkYXRlOmNyZWF0
368+ZQAyMDE2LTA3LTI0VDExOjU1OjU4KzAyOjAwRFqFOQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNi0w
369+Ny0yNFQxMToxNTowMCswMjowMP7RDgQAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb
370+7jwaAAAAAElFTkSuQmCC) 96% no-repeat;
371+}
372+.search-margin {
373+ margin-bottom: 0.6em;
374+}
375+#advanced-search-container {
376+ display: none;
377+ text-align: left;
378+ margin-bottom: 1rem;
379+ clear: both;
380+}
381+#advanced-search-container label,
382+#advanced-search-container .input-group-addon {
383+ font-size: 1.2rem;
384+ font-weight: normal;
385+ background-color: white;
386+ border: #dddddd 1px solid;
387+ border-right: none;
388+ color: #666666;
389+ padding-bottom: 0.4rem;
390+ padding-right: 0.7rem;
391+ padding-left: 0.7rem;
392+}
393+#advanced-search-container label:last-child,
394+#advanced-search-container .input-group-addon:last-child {
395+ border-right: #dddddd 1px solid;
396+}
397+#advanced-search-container input[type="radio"] {
398+ display: none;
399+}
400+#advanced-search-container input[type="radio"]:checked + label {
401+ color: #29314d;
402+ font-weight: bold;
403+ border-bottom: #01d7d4 5px solid;
404+}
405+#check-advanced {
406+ display: none;
407+}
408+#check-advanced:checked ~ #advanced-search-container {
409+ display: block;
410+}
411+.advanced {
412+ padding: 0;
413+ margin-top: 0.3rem;
414+ text-align: right;
415+}
416+.advanced label,
417+.advanced select {
418+ cursor: pointer;
419+}
420+.cursor-text {
421+ cursor: text !important;
422+}
423+.cursor-pointer {
424+ cursor: pointer !important;
425+}
426+pre,
427+code {
428+ font-family: 'Ubuntu Mono', 'Courier New', 'Lucida Console', monospace !important;
429+}
430+.lineno {
431+ margin-right: 5px;
432+}
433+.highlight .hll {
434+ background-color: #ffffcc;
435+}
436+.highlight {
437+ background: #f8f8f8;
438+}
439+.highlight .c {
440+ color: #556366;
441+ font-style: italic;
442+}
443+/* Comment */
444+.highlight .err {
445+ border: 1px solid #ffa92f;
446+}
447+/* Error */
448+.highlight .k {
449+ color: #BE74D5;
450+ font-weight: bold;
451+}
452+/* Keyword */
453+.highlight .o {
454+ color: #d19a66;
455+}
456+/* Operator */
457+.highlight .cm {
458+ color: #556366;
459+ font-style: italic;
460+}
461+/* Comment.Multiline */
462+.highlight .cp {
463+ color: #bc7a00;
464+}
465+/* Comment.Preproc */
466+.highlight .c1 {
467+ color: #556366;
468+ font-style: italic;
469+}
470+/* Comment.Single */
471+.highlight .cs {
472+ color: #556366;
473+ font-style: italic;
474+}
475+/* Comment.Special */
476+.highlight .gd {
477+ color: #a00000;
478+}
479+/* Generic.Deleted */
480+.highlight .ge {
481+ font-style: italic;
482+}
483+/* Generic.Emph */
484+.highlight .gr {
485+ color: #ff0000;
486+}
487+/* Generic.Error */
488+.highlight .gh {
489+ color: #000080;
490+ font-weight: bold;
491+}
492+/* Generic.Heading */
493+.highlight .gi {
494+ color: #00a000;
495+}
496+/* Generic.Inserted */
497+.highlight .go {
498+ color: #888888;
499+}
500+/* Generic.Output */
501+.highlight .gp {
502+ color: #000080;
503+ font-weight: bold;
504+}
505+/* Generic.Prompt */
506+.highlight .gs {
507+ font-weight: bold;
508+}
509+/* Generic.Strong */
510+.highlight .gu {
511+ color: #800080;
512+ font-weight: bold;
513+}
514+/* Generic.Subheading */
515+.highlight .gt {
516+ color: #0044dd;
517+}
518+/* Generic.Traceback */
519+.highlight .kc {
520+ color: #BE74D5;
521+ font-weight: bold;
522+}
523+/* Keyword.Constant */
524+.highlight .kd {
525+ color: #BE74D5;
526+ font-weight: bold;
527+}
528+/* Keyword.Declaration */
529+.highlight .kn {
530+ color: #BE74D5;
531+ font-weight: bold;
532+}
533+/* Keyword.Namespace */
534+.highlight .kp {
535+ color: #be74d5;
536+}
537+/* Keyword.Pseudo */
538+.highlight .kr {
539+ color: #BE74D5;
540+ font-weight: bold;
541+}
542+/* Keyword.Reserved */
543+.highlight .kt {
544+ color: #d46c72;
545+}
546+/* Keyword.Type */
547+.highlight .m {
548+ color: #d19a66;
549+}
550+/* Literal.Number */
551+.highlight .s {
552+ color: #86c372;
553+}
554+/* Literal.String */
555+.highlight .na {
556+ color: #7d9029;
557+}
558+/* Name.Attribute */
559+.highlight .nb {
560+ color: #be74d5;
561+}
562+/* Name.Builtin */
563+.highlight .nc {
564+ color: #61AFEF;
565+ font-weight: bold;
566+}
567+/* Name.Class */
568+.highlight .no {
569+ color: #d19a66;
570+}
571+/* Name.Constant */
572+.highlight .nd {
573+ color: #aa22ff;
574+}
575+/* Name.Decorator */
576+.highlight .ni {
577+ color: #999999;
578+ font-weight: bold;
579+}
580+/* Name.Entity */
581+.highlight .ne {
582+ color: #D2413A;
583+ font-weight: bold;
584+}
585+/* Name.Exception */
586+.highlight .nf {
587+ color: #61afef;
588+}
589+/* Name.Function */
590+.highlight .nl {
591+ color: #a0a000;
592+}
593+/* Name.Label */
594+.highlight .nn {
595+ color: #61AFEF;
596+ font-weight: bold;
597+}
598+/* Name.Namespace */
599+.highlight .nt {
600+ color: #BE74D5;
601+ font-weight: bold;
602+}
603+/* Name.Tag */
604+.highlight .nv {
605+ color: #dfc06f;
606+}
607+/* Name.Variable */
608+.highlight .ow {
609+ color: #AA22FF;
610+ font-weight: bold;
611+}
612+/* Operator.Word */
613+.highlight .w {
614+ color: #d7dae0;
615+}
616+/* Text.Whitespace */
617+.highlight .mf {
618+ color: #d19a66;
619+}
620+/* Literal.Number.Float */
621+.highlight .mh {
622+ color: #d19a66;
623+}
624+/* Literal.Number.Hex */
625+.highlight .mi {
626+ color: #d19a66;
627+}
628+/* Literal.Number.Integer */
629+.highlight .mo {
630+ color: #d19a66;
631+}
632+/* Literal.Number.Oct */
633+.highlight .sb {
634+ color: #86c372;
635+}
636+/* Literal.String.Backtick */
637+.highlight .sc {
638+ color: #86c372;
639+}
640+/* Literal.String.Char */
641+.highlight .sd {
642+ color: #86C372;
643+ font-style: italic;
644+}
645+/* Literal.String.Doc */
646+.highlight .s2 {
647+ color: #86c372;
648+}
649+/* Literal.String.Double */
650+.highlight .se {
651+ color: #BB6622;
652+ font-weight: bold;
653+}
654+/* Literal.String.Escape */
655+.highlight .sh {
656+ color: #86c372;
657+}
658+/* Literal.String.Heredoc */
659+.highlight .si {
660+ color: #BB6688;
661+ font-weight: bold;
662+}
663+/* Literal.String.Interpol */
664+.highlight .sx {
665+ color: #be74d5;
666+}
667+/* Literal.String.Other */
668+.highlight .sr {
669+ color: #bb6688;
670+}
671+/* Literal.String.Regex */
672+.highlight .s1 {
673+ color: #86c372;
674+}
675+/* Literal.String.Single */
676+.highlight .ss {
677+ color: #dfc06f;
678+}
679+/* Literal.String.Symbol */
680+.highlight .bp {
681+ color: #be74d5;
682+}
683+/* Name.Builtin.Pseudo */
684+.highlight .vc {
685+ color: #dfc06f;
686+}
687+/* Name.Variable.Class */
688+.highlight .vg {
689+ color: #dfc06f;
690+}
691+/* Name.Variable.Global */
692+.highlight .vi {
693+ color: #dfc06f;
694+}
695+/* Name.Variable.Instance */
696+.highlight .il {
697+ color: #d19a66;
698+}
699+/* Literal.Number.Integer.Long */
700+.highlight .lineno {
701+ -webkit-touch-callout: none;
702+ -webkit-user-select: none;
703+ -khtml-user-select: none;
704+ -moz-user-select: none;
705+ -ms-user-select: none;
706+ user-select: none;
707+ cursor: default;
708+ color: #556366;
709+}
710+.highlight .lineno::selection {
711+ background: transparent;
712+ /* WebKit/Blink Browsers */
713+}
714+.highlight .lineno::-moz-selection {
715+ background: transparent;
716+ /* Gecko Browsers */
717+}
718+.highlight pre {
719+ background-color: #282C34;
720+ color: #D7DAE0;
721+ border: none;
722+ margin-bottom: 25px;
723+ font-size: 15px;
724+ padding: 20px 10px;
725+}
726+.highlight {
727+ font-weight: 700;
728+}
729+.table > tbody > tr > td,
730+.table > tbody > tr > th {
731+ vertical-align: middle !important;
732+}
searx/static/themes/oscar/css/logicodev-dark.min.css+1−1
@@ -1 +1 @@
1−*{border-radius:0!important}html{position:relative;min-height:100%;color:#29314d}body{font-family:Roboto,Helvetica,Arial,sans-serif;margin-bottom:80px;background-color:#fff}body a{color:#08c}.footer{position:absolute;bottom:0;width:100%;height:60px;text-align:center;color:#999}input[type=checkbox]:checked+.label_hide_if_checked,input[type=checkbox]:checked+.label_hide_if_not_checked+.label_hide_if_checked{display:none}input[type=checkbox]:not(:checked)+.label_hide_if_not_checked,input[type=checkbox]:not(:checked)+.label_hide_if_checked+.label_hide_if_not_checked{display:none}.onoff-checkbox{width:15%}.onoffswitch{position:relative;width:110px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.onoffswitch-checkbox{display:none}.onoffswitch-label{display:block;overflow:hidden;cursor:pointer;border:2px solid #FFF!important;border-radius:50px!important}.onoffswitch-inner{display:block;transition:margin .3s ease-in 0s}.onoffswitch-inner:before,.onoffswitch-inner:after{display:block;float:left;width:50%;height:30px;padding:0;line-height:40px;font-size:20px;box-sizing:border-box;content:"";background-color:#EEE}.onoffswitch-switch{display:block;width:37px;background-color:#01d7d4;position:absolute;top:0;bottom:0;right:0;border:2px solid #FFF!important;border-radius:50px!important;transition:all .3s ease-in 0s}.onoffswitch-checkbox:checked+.onoffswitch-label .onoffswitch-inner{margin-right:0}.onoffswitch-checkbox:checked+.onoffswitch-label .onoffswitch-switch{right:71px;background-color:#A1A1A1}.result_header{margin-top:0;margin-bottom:2px;font-size:16px}.result_header .favicon{margin-bottom:-3px}.result_header a{color:#29314d;text-decoration:none}.result_header a:hover{color:#08c}.result_header a:visited{color:#684898}.result_header a .highlight{background-color:#f6f9fa}.result-content{margin-top:2px;margin-bottom:0;word-wrap:break-word;color:#666;font-size:13px}.result-content .highlight{font-weight:700}.external-link{color:#069025;font-size:12px;margin-bottom:15px}.external-link a{margin-right:3px}.result-default,.result-code,.result-torrent,.result-videos,.result-map{clear:both;padding:2px 4px}.result-default:hover,.result-code:hover,.result-torrent:hover,.result-videos:hover,.result-map:hover{background-color:#f6f9fa}.result-images{float:left!important;width:24%;margin:.5%}.result-images a{display:block;width:100%;background-size:cover}.img-thumbnail{margin:5px;max-height:128px;min-height:128px}.result-videos{clear:both}.result-videos hr{margin:5px 0 15px 0}.result-videos .collapse{width:100%}.result-videos .in{margin-bottom:8px}.result-torrent{clear:both}.result-torrent b{margin-right:5px;margin-left:5px}.result-torrent .seeders{color:#2ecc71}.result-torrent .leechers{color:#f35e77}.result-map{clear:both}.result-code{clear:both}.result-code .code-fork,.result-code .code-fork a{color:#666}.suggestion_item{margin:2px 5px;max-width:100%}.suggestion_item .btn{max-width:100%;white-space:normal;word-wrap:break-word;text-align:left}.result_download{margin-right:5px}#pagination{margin-top:30px;padding-bottom:60px}.label-default{color:#a4a4a4;background:0 0}.result .text-muted small{word-wrap:break-word}.modal-wrapper{box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-wrapper{background-clip:padding-box;background-color:#fff;border:1px solid rgba(0,0,0,.2);border-radius:6px;box-shadow:0 3px 9px rgba(0,0,0,.5);outline:0 none;position:relative}.infobox .panel-heading{background-color:#f6f9fa}.infobox .panel-heading .panel-title{font-weight:700}.infobox p{font-family:"DejaVu Serif",Georgia,Cambria,"Times New Roman",Times,serif!important;font-style:italic}.infobox .btn{background-color:#2ecc71;border:none}.infobox .btn a{color:#fff;margin:5px}.infobox .infobox_part{margin-bottom:20px;word-wrap:break-word;table-layout:fixed}.infobox .infobox_part:last-child{margin-bottom:0}.search_categories,#categories{text-transform:capitalize;margin-bottom:.5rem;display:flex;flex-wrap:wrap;flex-flow:row wrap;align-content:stretch}.search_categories label,#categories label,.search_categories .input-group-addon,#categories .input-group-addon{flex-grow:1;flex-basis:auto;font-size:1.2rem;font-weight:400;background-color:#fff;border:#ddd 1px solid;border-right:none;color:#666;padding-bottom:.4rem;padding-top:.4rem;text-align:center;min-width:50px}.search_categories label:last-child,#categories label:last-child,.search_categories .input-group-addon:last-child,#categories .input-group-addon:last-child{border-right:#ddd 1px solid}.search_categories input[type=checkbox]:checked+label,#categories input[type=checkbox]:checked+label{color:#29314d;font-weight:700;border-bottom:#01d7d4 5px solid}#main-logo{margin-top:10vh;margin-bottom:25px}#main-logo>img{max-width:350px;width:80%}#q{box-shadow:none;border-right:none;border-color:#a4a4a4}#search_form .input-group-btn .btn{border-color:#a4a4a4}#search_form .input-group-btn .btn:hover{background-color:#2ecc71;color:#fff}.custom-select{appearance:none;-webkit-appearance:none;-moz-appearance:none;font-size:1.2rem;font-weight:400;background-color:#fff;border:#ddd 1px solid;color:#666;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAQAAACR313BAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAABFkAAARZAVnbJUkAAAAHdElNRQfgBxgLDwB20OFsAAAAbElEQVQY073OsQ3CMAAEwJMYwJGnsAehpoXJItltBkmcdZBYgIIiQoLglnz3ui+eP+bk5uneteTMZJa6OJuIqvYzSJoqwqBq8gdmTTW86/dghxAUq4xsVYT9laBYXCw93Aajh7GPEF23t4fkBYevGFTANkPRAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE2LTA3LTI0VDExOjU1OjU4KzAyOjAwRFqFOQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNi0wNy0yNFQxMToxNTowMCswMjowMP7RDgQAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC) 96% no-repeat}.search-margin{margin-bottom:.6em}#advanced-search-container{display:none;text-align:left;margin-bottom:1rem;clear:both}#advanced-search-container label,#advanced-search-container .input-group-addon{font-size:1.2rem;font-weight:400;background-color:#fff;border:#ddd 1px solid;border-right:none;color:#666;padding-bottom:.4rem;padding-right:.7rem;padding-left:.7rem}#advanced-search-container label:last-child,#advanced-search-container .input-group-addon:last-child{border-right:#ddd 1px solid}#advanced-search-container input[type=radio]{display:none}#advanced-search-container input[type=radio]:checked+label{color:#29314d;font-weight:700;border-bottom:#01d7d4 5px solid}#check-advanced{display:none}#check-advanced:checked~#advanced-search-container{display:block}.advanced{padding:0;margin-top:.3rem;text-align:right}.advanced label,.advanced select{cursor:pointer}.cursor-text{cursor:text!important}.cursor-pointer{cursor:pointer!important}pre,code{font-family:'Ubuntu Mono','Courier New','Lucida Console',monospace!important}.lineno{margin-right:5px}.highlight .hll{background-color:#ffc}.highlight{background:#f8f8f8}.highlight .c{color:#556366;font-style:italic}.highlight .err{border:1px solid #ffa92f}.highlight .k{color:#BE74D5;font-weight:700}.highlight .o{color:#d19a66}.highlight .cm{color:#556366;font-style:italic}.highlight .cp{color:#bc7a00}.highlight .c1{color:#556366;font-style:italic}.highlight .cs{color:#556366;font-style:italic}.highlight .gd{color:#a00000}.highlight .ge{font-style:italic}.highlight .gr{color:red}.highlight .gh{color:navy;font-weight:700}.highlight .gi{color:#00a000}.highlight .go{color:#888}.highlight .gp{color:navy;font-weight:700}.highlight .gs{font-weight:700}.highlight .gu{color:purple;font-weight:700}.highlight .gt{color:#04d}.highlight .kc{color:#BE74D5;font-weight:700}.highlight .kd{color:#BE74D5;font-weight:700}.highlight .kn{color:#BE74D5;font-weight:700}.highlight .kp{color:#be74d5}.highlight .kr{color:#BE74D5;font-weight:700}.highlight .kt{color:#d46c72}.highlight .m{color:#d19a66}.highlight .s{color:#86c372}.highlight .na{color:#7d9029}.highlight .nb{color:#be74d5}.highlight .nc{color:#61AFEF;font-weight:700}.highlight .no{color:#d19a66}.highlight .nd{color:#a2f}.highlight .ni{color:#999;font-weight:700}.highlight .ne{color:#D2413A;font-weight:700}.highlight .nf{color:#61afef}.highlight .nl{color:#a0a000}.highlight .nn{color:#61AFEF;font-weight:700}.highlight .nt{color:#BE74D5;font-weight:700}.highlight .nv{color:#dfc06f}.highlight .ow{color:#A2F;font-weight:700}.highlight .w{color:#d7dae0}.highlight .mf{color:#d19a66}.highlight .mh{color:#d19a66}.highlight .mi{color:#d19a66}.highlight .mo{color:#d19a66}.highlight .sb{color:#86c372}.highlight .sc{color:#86c372}.highlight .sd{color:#86C372;font-style:italic}.highlight .s2{color:#86c372}.highlight .se{color:#B62;font-weight:700}.highlight .sh{color:#86c372}.highlight .si{color:#B68;font-weight:700}.highlight .sx{color:#be74d5}.highlight .sr{color:#b68}.highlight .s1{color:#86c372}.highlight .ss{color:#dfc06f}.highlight .bp{color:#be74d5}.highlight .vc{color:#dfc06f}.highlight .vg{color:#dfc06f}.highlight .vi{color:#dfc06f}.highlight .il{color:#d19a66}.highlight .lineno{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default;color:#556366}.highlight .lineno::selection{background:0 0}.highlight .lineno::-moz-selection{background:0 0}.highlight pre{background-color:#282C34;color:#D7DAE0;border:none;margin-bottom:25px;font-size:15px;padding:20px 10px}.highlight{font-weight:700}.table>tbody>tr>td,.table>tbody>tr>th{vertical-align:middle!important}body{background:#1d1f21 none!important;color:#D5D8D7!important}a{color:#41a2ce!important;text-decoration:none!important}a:hover{color:#5F89AC!important}input,button,textarea,select{border:1px solid #282a2e!important;background-color:#444!important;color:#BBB!important}input:focus,button:focus,textarea:focus,select:focus{border:1px solid #C5C8C6!important;box-shadow:initial!important}div#advanced-search-container div#categories label{background:0 0;border:1px solid #282a2e}ul.nav li a{border:0!important;border-bottom:1px solid #4d3f43!important}#categories *,.modal-wrapper *{background:#1d1f21 none!important;color:#D5D8D7!important}#categories *{border:1px solid #3d3f43!important}#categories :checked+label{border-bottom:4px solid #3d9f94!important}.result-content{color:#B5B8B7!important}.external-link{color:#35B887!important}.table-striped tr td,.table-striped tr th{border-color:#4d3f43!important}.highlight{background:#333!important}.navbar{background:#1d1f21 none;border:none}.navbar .active,.menu{background:none!important}.label-default{background:0 0;color:#BBB}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus,.nav-tabs.nav-justified>.active>a{background-color:#282a2e!important}.result-default:hover,.result-code:hover,.result-torrent:hover,.result-videos:hover,.result-map:hover{background-color:#222426}.btn{color:#BBB;background-color:#444;border:1px solid #282a2e}.btn:hover{color:#444!important;background-color:#BBB!important}.btn-primary.active{color:#C5C8C6;background-color:#5F89AC;border-color:#5F89AC}.panel{border:1px solid #111;background:0 0}.panel-heading{color:#C5C8C6!important;background:#282a2e!important;border-bottom:none}.panel-body{color:#C5C8C6!important;background:#1d1f21!important;border-color:#111!important}p.btn.btn-default{background:0 0}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th,.table-striped>thead>tr:nth-child(odd)>th{background:#2d2f32 none!important;color:#D5D8D7!important}.label-success{background:#1d6f42 none!important}.label-danger{background:#ad1f12 none!important}.searx-navbar{background:#333334;height:2.3rem;font-size:1.3rem;line-height:1.3rem;padding:.5rem;font-weight:700;margin-bottom:.8rem}.searx-navbar a,.searx-navbar a:hover{margin-right:2rem;color:#fff;text-decoration:none}.searx-navbar .instance a{color:#01d7d4;margin-left:2rem}#main-logo{margin-top:20vh;margin-bottom:25px}#main-logo>img{max-width:350px;width:80%}.onoffswitch-inner:before,.onoffswitch-inner:after{background:#1d1f21 none!important}.onoffswitch-switch,.onoffswitch-label{border:2px solid #3d3f43!important}.nav>li>a:hover,.nav>li>a:focus{background-color:#3d3f43!important}.img-thumbnail,.thumbnail{padding:0;line-height:1.42857143;background:0 0;border:none}.modal-content{background:#1d1f21 none!important}.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:rgba(240,0,0,.56)!important;color:#C5C8C6!important}.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:rgba(237,59,59,.61)!important;color:#C5C8C6!important}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background:#66696e!important}.btn-success{color:#C5C8C6;background:#449d44}.btn-danger{color:#C5C8C6;background:#d9534f}.well{background:#444;border-color:#282a2e}.highlight{background-color:transparent!important}
1+*{border-radius:0!important}html{position:relative;min-height:100%;color:#29314d}body{font-family:Roboto,Helvetica,Arial,sans-serif;margin-bottom:80px;background-color:#fff}body a{color:#08c}.footer{position:absolute;bottom:0;width:100%;height:60px;text-align:center;color:#999}input[type=checkbox]:checked+.label_hide_if_checked,input[type=checkbox]:checked+.label_hide_if_not_checked+.label_hide_if_checked{display:none}input[type=checkbox]:not(:checked)+.label_hide_if_not_checked,input[type=checkbox]:not(:checked)+.label_hide_if_checked+.label_hide_if_not_checked{display:none}.onoff-checkbox{width:15%}.onoffswitch{position:relative;width:110px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.onoffswitch-checkbox{display:none}.onoffswitch-label{display:block;overflow:hidden;cursor:pointer;border:2px solid #FFF!important;border-radius:50px!important}.onoffswitch-inner{display:block;transition:margin .3s ease-in 0s}.onoffswitch-inner:before,.onoffswitch-inner:after{display:block;float:left;width:50%;height:30px;padding:0;line-height:40px;font-size:20px;box-sizing:border-box;content:"";background-color:#EEE}.onoffswitch-switch{display:block;width:37px;background-color:#01d7d4;position:absolute;top:0;bottom:0;right:0;border:2px solid #FFF!important;border-radius:50px!important;transition:all .3s ease-in 0s}.onoffswitch-checkbox:checked+.onoffswitch-label .onoffswitch-inner{margin-right:0}.onoffswitch-checkbox:checked+.onoffswitch-label .onoffswitch-switch{right:71px;background-color:#A1A1A1}.result_header{margin-top:0;margin-bottom:2px;font-size:16px}.result_header .favicon{margin-bottom:-3px}.result_header a{color:#29314d;text-decoration:none}.result_header a:hover{color:#08c}.result_header a:visited{color:#684898}.result_header a .highlight{background-color:#f6f9fa}.result-content,.result-format,.result-source{margin-top:2px;margin-bottom:0;word-wrap:break-word;color:#666;font-size:13px}.result-content .highlight,.result-format .highlight,.result-source .highlight{font-weight:700}.result-source{font-size:10px;float:left}.result-format{font-size:10px;float:right}.external-link{color:#069025;font-size:12px;margin-bottom:15px}.external-link a{margin-right:3px}.result-default,.result-code,.result-torrent,.result-videos,.result-map{clear:both;padding:2px 4px}.result-default:hover,.result-code:hover,.result-torrent:hover,.result-videos:hover,.result-map:hover{background-color:#f6f9fa}.result-images{float:left!important;width:24%;margin:.5%}.result-images a{display:block;width:100%;background-size:cover}.img-thumbnail{margin:5px;max-height:128px;min-height:128px}.result-videos{clear:both}.result-videos hr{margin:5px 0 15px 0}.result-videos .collapse{width:100%}.result-videos .in{margin-bottom:8px}.result-torrent{clear:both}.result-torrent b{margin-right:5px;margin-left:5px}.result-torrent .seeders{color:#2ecc71}.result-torrent .leechers{color:#f35e77}.result-map{clear:both}.result-code{clear:both}.result-code .code-fork,.result-code .code-fork a{color:#666}.suggestion_item{margin:2px 5px;max-width:100%}.suggestion_item .btn{max-width:100%;white-space:normal;word-wrap:break-word;text-align:left}.result_download{margin-right:5px}#pagination{margin-top:30px;padding-bottom:60px}.label-default{color:#a4a4a4;background:0 0}.result .text-muted small{word-wrap:break-word}.modal-wrapper{box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-wrapper{background-clip:padding-box;background-color:#fff;border:1px solid rgba(0,0,0,.2);border-radius:6px;box-shadow:0 3px 9px rgba(0,0,0,.5);outline:0 none;position:relative}.infobox .panel-heading{background-color:#f6f9fa}.infobox .panel-heading .panel-title{font-weight:700}.infobox p{font-family:"DejaVu Serif",Georgia,Cambria,"Times New Roman",Times,serif!important;font-style:italic}.infobox .btn{background-color:#2ecc71;border:none}.infobox .btn a{color:#fff;margin:5px}.infobox .infobox_part{margin-bottom:20px;word-wrap:break-word;table-layout:fixed}.infobox .infobox_part:last-child{margin-bottom:0}.search_categories,#categories{text-transform:capitalize;margin-bottom:.5rem;display:flex;flex-wrap:wrap;flex-flow:row wrap;align-content:stretch}.search_categories label,#categories label,.search_categories .input-group-addon,#categories .input-group-addon{flex-grow:1;flex-basis:auto;font-size:1.2rem;font-weight:400;background-color:#fff;border:#ddd 1px solid;border-right:none;color:#666;padding-bottom:.4rem;padding-top:.4rem;text-align:center;min-width:50px}.search_categories label:last-child,#categories label:last-child,.search_categories .input-group-addon:last-child,#categories .input-group-addon:last-child{border-right:#ddd 1px solid}.search_categories input[type=checkbox]:checked+label,#categories input[type=checkbox]:checked+label{color:#29314d;font-weight:700;border-bottom:#01d7d4 5px solid}#main-logo{margin-top:10vh;margin-bottom:25px}#main-logo>img{max-width:350px;width:80%}#q{box-shadow:none;border-right:none;border-color:#a4a4a4}#search_form .input-group-btn .btn{border-color:#a4a4a4}#search_form .input-group-btn .btn:hover{background-color:#2ecc71;color:#fff}.custom-select{appearance:none;-webkit-appearance:none;-moz-appearance:none;font-size:1.2rem;font-weight:400;background-color:#fff;border:#ddd 1px solid;color:#666;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAQAAACR313BAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAABFkAAARZAVnbJUkAAAAHdElNRQfgBxgLDwB20OFsAAAAbElEQVQY073OsQ3CMAAEwJMYwJGnsAehpoXJItltBkmcdZBYgIIiQoLglnz3ui+eP+bk5uneteTMZJa6OJuIqvYzSJoqwqBq8gdmTTW86/dghxAUq4xsVYT9laBYXCw93Aajh7GPEF23t4fkBYevGFTANkPRAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE2LTA3LTI0VDExOjU1OjU4KzAyOjAwRFqFOQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNi0wNy0yNFQxMToxNTowMCswMjowMP7RDgQAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC) 96% no-repeat}.search-margin{margin-bottom:.6em}#advanced-search-container{display:none;text-align:left;margin-bottom:1rem;clear:both}#advanced-search-container label,#advanced-search-container .input-group-addon{font-size:1.2rem;font-weight:400;background-color:#fff;border:#ddd 1px solid;border-right:none;color:#666;padding-bottom:.4rem;padding-right:.7rem;padding-left:.7rem}#advanced-search-container label:last-child,#advanced-search-container .input-group-addon:last-child{border-right:#ddd 1px solid}#advanced-search-container input[type=radio]{display:none}#advanced-search-container input[type=radio]:checked+label{color:#29314d;font-weight:700;border-bottom:#01d7d4 5px solid}#check-advanced{display:none}#check-advanced:checked~#advanced-search-container{display:block}.advanced{padding:0;margin-top:.3rem;text-align:right}.advanced label,.advanced select{cursor:pointer}.cursor-text{cursor:text!important}.cursor-pointer{cursor:pointer!important}pre,code{font-family:'Ubuntu Mono','Courier New','Lucida Console',monospace!important}.lineno{margin-right:5px}.highlight .hll{background-color:#ffc}.highlight{background:#f8f8f8}.highlight .c{color:#556366;font-style:italic}.highlight .err{border:1px solid #ffa92f}.highlight .k{color:#BE74D5;font-weight:700}.highlight .o{color:#d19a66}.highlight .cm{color:#556366;font-style:italic}.highlight .cp{color:#bc7a00}.highlight .c1{color:#556366;font-style:italic}.highlight .cs{color:#556366;font-style:italic}.highlight .gd{color:#a00000}.highlight .ge{font-style:italic}.highlight .gr{color:red}.highlight .gh{color:navy;font-weight:700}.highlight .gi{color:#00a000}.highlight .go{color:#888}.highlight .gp{color:navy;font-weight:700}.highlight .gs{font-weight:700}.highlight .gu{color:purple;font-weight:700}.highlight .gt{color:#04d}.highlight .kc{color:#BE74D5;font-weight:700}.highlight .kd{color:#BE74D5;font-weight:700}.highlight .kn{color:#BE74D5;font-weight:700}.highlight .kp{color:#be74d5}.highlight .kr{color:#BE74D5;font-weight:700}.highlight .kt{color:#d46c72}.highlight .m{color:#d19a66}.highlight .s{color:#86c372}.highlight .na{color:#7d9029}.highlight .nb{color:#be74d5}.highlight .nc{color:#61AFEF;font-weight:700}.highlight .no{color:#d19a66}.highlight .nd{color:#a2f}.highlight .ni{color:#999;font-weight:700}.highlight .ne{color:#D2413A;font-weight:700}.highlight .nf{color:#61afef}.highlight .nl{color:#a0a000}.highlight .nn{color:#61AFEF;font-weight:700}.highlight .nt{color:#BE74D5;font-weight:700}.highlight .nv{color:#dfc06f}.highlight .ow{color:#A2F;font-weight:700}.highlight .w{color:#d7dae0}.highlight .mf{color:#d19a66}.highlight .mh{color:#d19a66}.highlight .mi{color:#d19a66}.highlight .mo{color:#d19a66}.highlight .sb{color:#86c372}.highlight .sc{color:#86c372}.highlight .sd{color:#86C372;font-style:italic}.highlight .s2{color:#86c372}.highlight .se{color:#B62;font-weight:700}.highlight .sh{color:#86c372}.highlight .si{color:#B68;font-weight:700}.highlight .sx{color:#be74d5}.highlight .sr{color:#b68}.highlight .s1{color:#86c372}.highlight .ss{color:#dfc06f}.highlight .bp{color:#be74d5}.highlight .vc{color:#dfc06f}.highlight .vg{color:#dfc06f}.highlight .vi{color:#dfc06f}.highlight .il{color:#d19a66}.highlight .lineno{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default;color:#556366}.highlight .lineno::selection{background:0 0}.highlight .lineno::-moz-selection{background:0 0}.highlight pre{background-color:#282C34;color:#D7DAE0;border:none;margin-bottom:25px;font-size:15px;padding:20px 10px}.highlight{font-weight:700}.table>tbody>tr>td,.table>tbody>tr>th{vertical-align:middle!important}body{background:#1d1f21 none!important;color:#D5D8D7!important}a{color:#41a2ce!important;text-decoration:none!important}a:hover{color:#5F89AC!important}input,button,textarea,select{border:1px solid #282a2e!important;background-color:#444!important;color:#BBB!important}input:focus,button:focus,textarea:focus,select:focus{border:1px solid #C5C8C6!important;box-shadow:initial!important}div#advanced-search-container div#categories label{background:0 0;border:1px solid #282a2e}ul.nav li a{border:0!important;border-bottom:1px solid #4d3f43!important}#categories *,.modal-wrapper *{background:#1d1f21 none!important;color:#D5D8D7!important}#categories *{border:1px solid #3d3f43!important}#categories :checked+label{border-bottom:4px solid #3d9f94!important}.result-content,.result-source,.result-format{color:#B5B8B7!important}.external-link{color:#35B887!important}.table-striped tr td,.table-striped tr th{border-color:#4d3f43!important}.highlight{background:#333!important}.navbar{background:#1d1f21 none;border:none}.navbar .active,.menu{background:none!important}.label-default{background:0 0;color:#BBB}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus,.nav-tabs.nav-justified>.active>a{background-color:#282a2e!important}.result-default:hover,.result-code:hover,.result-torrent:hover,.result-videos:hover,.result-map:hover{background-color:#222426}.btn{color:#BBB;background-color:#444;border:1px solid #282a2e}.btn:hover{color:#444!important;background-color:#BBB!important}.btn-primary.active{color:#C5C8C6;background-color:#5F89AC;border-color:#5F89AC}.panel{border:1px solid #111;background:0 0}.panel-heading{color:#C5C8C6!important;background:#282a2e!important;border-bottom:none}.panel-body{color:#C5C8C6!important;background:#1d1f21!important;border-color:#111!important}p.btn.btn-default{background:0 0}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th,.table-striped>thead>tr:nth-child(odd)>th{background:#2d2f32 none!important;color:#D5D8D7!important}.label-success{background:#1d6f42 none!important}.label-danger{background:#ad1f12 none!important}.searx-navbar{background:#333334;height:2.3rem;font-size:1.3rem;line-height:1.3rem;padding:.5rem;font-weight:700;margin-bottom:.8rem}.searx-navbar a,.searx-navbar a:hover{margin-right:2rem;color:#fff;text-decoration:none}.searx-navbar .instance a{color:#01d7d4;margin-left:2rem}#main-logo{margin-top:20vh;margin-bottom:25px}#main-logo>img{max-width:350px;width:80%}.onoffswitch-inner:before,.onoffswitch-inner:after{background:#1d1f21 none!important}.onoffswitch-switch,.onoffswitch-label{border:2px solid #3d3f43!important}.nav>li>a:hover,.nav>li>a:focus{background-color:#3d3f43!important}.img-thumbnail,.thumbnail{padding:0;line-height:1.42857143;background:0 0;border:none}.modal-content{background:#1d1f21 none!important}.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:rgba(240,0,0,.56)!important;color:#C5C8C6!important}.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:rgba(237,59,59,.61)!important;color:#C5C8C6!important}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background:#66696e!important}.btn-success{color:#C5C8C6;background:#449d44}.btn-danger{color:#C5C8C6;background:#d9534f}.well{background:#444;border-color:#282a2e}.highlight{background-color:transparent!important}
searx/static/themes/oscar/css/logicodev.cssnew file+931
@@ -0,0 +1,931 @@
1+* {
2+ border-radius: 0 !important;
3+}
4+html {
5+ position: relative;
6+ min-height: 100%;
7+ color: #29314d;
8+}
9+body {
10+ /* Margin bottom by footer height */
11+ font-family: 'Roboto', Helvetica, Arial, sans-serif;
12+ margin-bottom: 80px;
13+ background-color: white;
14+}
15+body a {
16+ color: #0088cc;
17+}
18+.footer {
19+ position: absolute;
20+ bottom: 0;
21+ width: 100%;
22+ /* Set the fixed height of the footer here */
23+ height: 60px;
24+ text-align: center;
25+ color: #999;
26+}
27+input[type=checkbox]:checked + .label_hide_if_checked,
28+input[type=checkbox]:checked + .label_hide_if_not_checked + .label_hide_if_checked {
29+ display: none;
30+}
31+input[type=checkbox]:not(:checked) + .label_hide_if_not_checked,
32+input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not_checked {
33+ display: none;
34+}
35+.onoff-checkbox {
36+ width: 15%;
37+}
38+.onoffswitch {
39+ position: relative;
40+ width: 110px;
41+ -webkit-user-select: none;
42+ -moz-user-select: none;
43+ -ms-user-select: none;
44+}
45+.onoffswitch-checkbox {
46+ display: none;
47+}
48+.onoffswitch-label {
49+ display: block;
50+ overflow: hidden;
51+ cursor: pointer;
52+ border: 2px solid #FFFFFF !important;
53+ border-radius: 50px !important;
54+}
55+.onoffswitch-inner {
56+ display: block;
57+ transition: margin 0.3s ease-in 0s;
58+}
59+.onoffswitch-inner:before,
60+.onoffswitch-inner:after {
61+ display: block;
62+ float: left;
63+ width: 50%;
64+ height: 30px;
65+ padding: 0;
66+ line-height: 40px;
67+ font-size: 20px;
68+ box-sizing: border-box;
69+ content: "";
70+ background-color: #EEEEEE;
71+}
72+.onoffswitch-switch {
73+ display: block;
74+ width: 37px;
75+ background-color: #01d7d4;
76+ position: absolute;
77+ top: 0;
78+ bottom: 0;
79+ right: 0px;
80+ border: 2px solid #FFFFFF !important;
81+ border-radius: 50px !important;
82+ transition: all 0.3s ease-in 0s;
83+}
84+.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
85+ margin-right: 0;
86+}
87+.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
88+ right: 71px;
89+ background-color: #A1A1A1;
90+}
91+.result_header {
92+ margin-top: 0px;
93+ margin-bottom: 2px;
94+ font-size: 16px;
95+}
96+.result_header .favicon {
97+ margin-bottom: -3px;
98+}
99+.result_header a {
100+ color: #29314d;
101+ text-decoration: none;
102+}
103+.result_header a:hover {
104+ color: #0088cc;
105+}
106+.result_header a:visited {
107+ color: #684898;
108+}
109+.result_header a .highlight {
110+ background-color: #f6f9fa;
111+}
112+.result-content,
113+.result-format,
114+.result-source {
115+ margin-top: 2px;
116+ margin-bottom: 0;
117+ word-wrap: break-word;
118+ color: #666666;
119+ font-size: 13px;
120+}
121+.result-content .highlight,
122+.result-format .highlight,
123+.result-source .highlight {
124+ font-weight: bold;
125+}
126+.result-source {
127+ font-size: 10px;
128+ float: left;
129+}
130+.result-format {
131+ font-size: 10px;
132+ float: right;
133+}
134+.external-link {
135+ color: #069025;
136+ font-size: 12px;
137+ margin-bottom: 15px;
138+}
139+.external-link a {
140+ margin-right: 3px;
141+}
142+.result-default,
143+.result-code,
144+.result-torrent,
145+.result-videos,
146+.result-map {
147+ clear: both;
148+ padding: 2px 4px;
149+}
150+.result-default:hover,
151+.result-code:hover,
152+.result-torrent:hover,
153+.result-videos:hover,
154+.result-map:hover {
155+ background-color: #f6f9fa;
156+}
157+.result-images {
158+ float: left !important;
159+ width: 24%;
160+ margin: .5%;
161+}
162+.result-images a {
163+ display: block;
164+ width: 100%;
165+ background-size: cover;
166+}
167+.img-thumbnail {
168+ margin: 5px;
169+ max-height: 128px;
170+ min-height: 128px;
171+}
172+.result-videos {
173+ clear: both;
174+}
175+.result-videos hr {
176+ margin: 5px 0 15px 0;
177+}
178+.result-videos .collapse {
179+ width: 100%;
180+}
181+.result-videos .in {
182+ margin-bottom: 8px;
183+}
184+.result-torrent {
185+ clear: both;
186+}
187+.result-torrent b {
188+ margin-right: 5px;
189+ margin-left: 5px;
190+}
191+.result-torrent .seeders {
192+ color: #2ecc71;
193+}
194+.result-torrent .leechers {
195+ color: #f35e77;
196+}
197+.result-map {
198+ clear: both;
199+}
200+.result-code {
201+ clear: both;
202+}
203+.result-code .code-fork,
204+.result-code .code-fork a {
205+ color: #666666;
206+}
207+.suggestion_item {
208+ margin: 2px 5px;
209+ max-width: 100%;
210+}
211+.suggestion_item .btn {
212+ max-width: 100%;
213+ white-space: normal;
214+ word-wrap: break-word;
215+ text-align: left;
216+}
217+.result_download {
218+ margin-right: 5px;
219+}
220+#pagination {
221+ margin-top: 30px;
222+ padding-bottom: 60px;
223+}
224+.label-default {
225+ color: #a4a4a4;
226+ background: transparent;
227+}
228+.result .text-muted small {
229+ word-wrap: break-word;
230+}
231+.modal-wrapper {
232+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
233+}
234+.modal-wrapper {
235+ background-clip: padding-box;
236+ background-color: #fff;
237+ border: 1px solid rgba(0, 0, 0, 0.2);
238+ border-radius: 6px;
239+ box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
240+ outline: 0 none;
241+ position: relative;
242+}
243+.infobox .panel-heading {
244+ background-color: #f6f9fa;
245+}
246+.infobox .panel-heading .panel-title {
247+ font-weight: 700;
248+}
249+.infobox p {
250+ font-family: "DejaVu Serif", Georgia, Cambria, "Times New Roman", Times, serif !important;
251+ font-style: italic;
252+}
253+.infobox .btn {
254+ background-color: #2ecc71;
255+ border: none;
256+}
257+.infobox .btn a {
258+ color: white;
259+ margin: 5px;
260+}
261+.infobox .infobox_part {
262+ margin-bottom: 20px;
263+ word-wrap: break-word;
264+ table-layout: fixed;
265+}
266+.infobox .infobox_part:last-child {
267+ margin-bottom: 0;
268+}
269+.search_categories,
270+#categories {
271+ text-transform: capitalize;
272+ margin-bottom: 0.5rem;
273+ display: flex;
274+ flex-wrap: wrap;
275+ flex-flow: row wrap;
276+ align-content: stretch;
277+}
278+.search_categories label,
279+#categories label,
280+.search_categories .input-group-addon,
281+#categories .input-group-addon {
282+ flex-grow: 1;
283+ flex-basis: auto;
284+ font-size: 1.2rem;
285+ font-weight: normal;
286+ background-color: white;
287+ border: #dddddd 1px solid;
288+ border-right: none;
289+ color: #666666;
290+ padding-bottom: 0.4rem;
291+ padding-top: 0.4rem;
292+ text-align: center;
293+ min-width: 50px;
294+}
295+.search_categories label:last-child,
296+#categories label:last-child,
297+.search_categories .input-group-addon:last-child,
298+#categories .input-group-addon:last-child {
299+ border-right: #dddddd 1px solid;
300+}
301+.search_categories input[type="checkbox"]:checked + label,
302+#categories input[type="checkbox"]:checked + label {
303+ color: #29314d;
304+ font-weight: bold;
305+ border-bottom: #01d7d4 5px solid;
306+}
307+#main-logo {
308+ margin-top: 10vh;
309+ margin-bottom: 25px;
310+}
311+#main-logo > img {
312+ max-width: 350px;
313+ width: 80%;
314+}
315+#q {
316+ box-shadow: none;
317+ border-right: none;
318+ border-color: #a4a4a4;
319+}
320+#search_form .input-group-btn .btn {
321+ border-color: #a4a4a4;
322+}
323+#search_form .input-group-btn .btn:hover {
324+ background-color: #2ecc71;
325+ color: white;
326+}
327+.custom-select {
328+ appearance: none;
329+ -webkit-appearance: none;
330+ -moz-appearance: none;
331+ font-size: 1.2rem;
332+ font-weight: normal;
333+ background-color: white;
334+ border: #dddddd 1px solid;
335+ color: #666666;
336+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAQAAACR313BAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
337+AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAJcEhZ
338+cwAABFkAAARZAVnbJUkAAAAHdElNRQfgBxgLDwB20OFsAAAAbElEQVQY073OsQ3CMAAEwJMYwJGn
339+sAehpoXJItltBkmcdZBYgIIiQoLglnz3ui+eP+bk5uneteTMZJa6OJuIqvYzSJoqwqBq8gdmTTW8
340+6/dghxAUq4xsVYT9laBYXCw93Aajh7GPEF23t4fkBYevGFTANkPRAAAAJXRFWHRkYXRlOmNyZWF0
341+ZQAyMDE2LTA3LTI0VDExOjU1OjU4KzAyOjAwRFqFOQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNi0w
342+Ny0yNFQxMToxNTowMCswMjowMP7RDgQAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb
343+7jwaAAAAAElFTkSuQmCC) 96% no-repeat;
344+}
345+.search-margin {
346+ margin-bottom: 0.6em;
347+}
348+#advanced-search-container {
349+ display: none;
350+ text-align: left;
351+ margin-bottom: 1rem;
352+ clear: both;
353+}
354+#advanced-search-container label,
355+#advanced-search-container .input-group-addon {
356+ font-size: 1.2rem;
357+ font-weight: normal;
358+ background-color: white;
359+ border: #dddddd 1px solid;
360+ border-right: none;
361+ color: #666666;
362+ padding-bottom: 0.4rem;
363+ padding-right: 0.7rem;
364+ padding-left: 0.7rem;
365+}
366+#advanced-search-container label:last-child,
367+#advanced-search-container .input-group-addon:last-child {
368+ border-right: #dddddd 1px solid;
369+}
370+#advanced-search-container input[type="radio"] {
371+ display: none;
372+}
373+#advanced-search-container input[type="radio"]:checked + label {
374+ color: #29314d;
375+ font-weight: bold;
376+ border-bottom: #01d7d4 5px solid;
377+}
378+#check-advanced {
379+ display: none;
380+}
381+#check-advanced:checked ~ #advanced-search-container {
382+ display: block;
383+}
384+.advanced {
385+ padding: 0;
386+ margin-top: 0.3rem;
387+ text-align: right;
388+}
389+.advanced label,
390+.advanced select {
391+ cursor: pointer;
392+}
393+.cursor-text {
394+ cursor: text !important;
395+}
396+.cursor-pointer {
397+ cursor: pointer !important;
398+}
399+pre,
400+code {
401+ font-family: 'Ubuntu Mono', 'Courier New', 'Lucida Console', monospace !important;
402+}
403+.lineno {
404+ margin-right: 5px;
405+}
406+.highlight .hll {
407+ background-color: #ffffcc;
408+}
409+.highlight {
410+ background: #f8f8f8;
411+}
412+.highlight .c {
413+ color: #556366;
414+ font-style: italic;
415+}
416+/* Comment */
417+.highlight .err {
418+ border: 1px solid #ffa92f;
419+}
420+/* Error */
421+.highlight .k {
422+ color: #BE74D5;
423+ font-weight: bold;
424+}
425+/* Keyword */
426+.highlight .o {
427+ color: #d19a66;
428+}
429+/* Operator */
430+.highlight .cm {
431+ color: #556366;
432+ font-style: italic;
433+}
434+/* Comment.Multiline */
435+.highlight .cp {
436+ color: #bc7a00;
437+}
438+/* Comment.Preproc */
439+.highlight .c1 {
440+ color: #556366;
441+ font-style: italic;
442+}
443+/* Comment.Single */
444+.highlight .cs {
445+ color: #556366;
446+ font-style: italic;
447+}
448+/* Comment.Special */
449+.highlight .gd {
450+ color: #a00000;
451+}
452+/* Generic.Deleted */
453+.highlight .ge {
454+ font-style: italic;
455+}
456+/* Generic.Emph */
457+.highlight .gr {
458+ color: #ff0000;
459+}
460+/* Generic.Error */
461+.highlight .gh {
462+ color: #000080;
463+ font-weight: bold;
464+}
465+/* Generic.Heading */
466+.highlight .gi {
467+ color: #00a000;
468+}
469+/* Generic.Inserted */
470+.highlight .go {
471+ color: #888888;
472+}
473+/* Generic.Output */
474+.highlight .gp {
475+ color: #000080;
476+ font-weight: bold;
477+}
478+/* Generic.Prompt */
479+.highlight .gs {
480+ font-weight: bold;
481+}
482+/* Generic.Strong */
483+.highlight .gu {
484+ color: #800080;
485+ font-weight: bold;
486+}
487+/* Generic.Subheading */
488+.highlight .gt {
489+ color: #0044dd;
490+}
491+/* Generic.Traceback */
492+.highlight .kc {
493+ color: #BE74D5;
494+ font-weight: bold;
495+}
496+/* Keyword.Constant */
497+.highlight .kd {
498+ color: #BE74D5;
499+ font-weight: bold;
500+}
501+/* Keyword.Declaration */
502+.highlight .kn {
503+ color: #BE74D5;
504+ font-weight: bold;
505+}
506+/* Keyword.Namespace */
507+.highlight .kp {
508+ color: #be74d5;
509+}
510+/* Keyword.Pseudo */
511+.highlight .kr {
512+ color: #BE74D5;
513+ font-weight: bold;
514+}
515+/* Keyword.Reserved */
516+.highlight .kt {
517+ color: #d46c72;
518+}
519+/* Keyword.Type */
520+.highlight .m {
521+ color: #d19a66;
522+}
523+/* Literal.Number */
524+.highlight .s {
525+ color: #86c372;
526+}
527+/* Literal.String */
528+.highlight .na {
529+ color: #7d9029;
530+}
531+/* Name.Attribute */
532+.highlight .nb {
533+ color: #be74d5;
534+}
535+/* Name.Builtin */
536+.highlight .nc {
537+ color: #61AFEF;
538+ font-weight: bold;
539+}
540+/* Name.Class */
541+.highlight .no {
542+ color: #d19a66;
543+}
544+/* Name.Constant */
545+.highlight .nd {
546+ color: #aa22ff;
547+}
548+/* Name.Decorator */
549+.highlight .ni {
550+ color: #999999;
551+ font-weight: bold;
552+}
553+/* Name.Entity */
554+.highlight .ne {
555+ color: #D2413A;
556+ font-weight: bold;
557+}
558+/* Name.Exception */
559+.highlight .nf {
560+ color: #61afef;
561+}
562+/* Name.Function */
563+.highlight .nl {
564+ color: #a0a000;
565+}
566+/* Name.Label */
567+.highlight .nn {
568+ color: #61AFEF;
569+ font-weight: bold;
570+}
571+/* Name.Namespace */
572+.highlight .nt {
573+ color: #BE74D5;
574+ font-weight: bold;
575+}
576+/* Name.Tag */
577+.highlight .nv {
578+ color: #dfc06f;
579+}
580+/* Name.Variable */
581+.highlight .ow {
582+ color: #AA22FF;
583+ font-weight: bold;
584+}
585+/* Operator.Word */
586+.highlight .w {
587+ color: #d7dae0;
588+}
589+/* Text.Whitespace */
590+.highlight .mf {
591+ color: #d19a66;
592+}
593+/* Literal.Number.Float */
594+.highlight .mh {
595+ color: #d19a66;
596+}
597+/* Literal.Number.Hex */
598+.highlight .mi {
599+ color: #d19a66;
600+}
601+/* Literal.Number.Integer */
602+.highlight .mo {
603+ color: #d19a66;
604+}
605+/* Literal.Number.Oct */
606+.highlight .sb {
607+ color: #86c372;
608+}
609+/* Literal.String.Backtick */
610+.highlight .sc {
611+ color: #86c372;
612+}
613+/* Literal.String.Char */
614+.highlight .sd {
615+ color: #86C372;
616+ font-style: italic;
617+}
618+/* Literal.String.Doc */
619+.highlight .s2 {
620+ color: #86c372;
621+}
622+/* Literal.String.Double */
623+.highlight .se {
624+ color: #BB6622;
625+ font-weight: bold;
626+}
627+/* Literal.String.Escape */
628+.highlight .sh {
629+ color: #86c372;
630+}
631+/* Literal.String.Heredoc */
632+.highlight .si {
633+ color: #BB6688;
634+ font-weight: bold;
635+}
636+/* Literal.String.Interpol */
637+.highlight .sx {
638+ color: #be74d5;
639+}
640+/* Literal.String.Other */
641+.highlight .sr {
642+ color: #bb6688;
643+}
644+/* Literal.String.Regex */
645+.highlight .s1 {
646+ color: #86c372;
647+}
648+/* Literal.String.Single */
649+.highlight .ss {
650+ color: #dfc06f;
651+}
652+/* Literal.String.Symbol */
653+.highlight .bp {
654+ color: #be74d5;
655+}
656+/* Name.Builtin.Pseudo */
657+.highlight .vc {
658+ color: #dfc06f;
659+}
660+/* Name.Variable.Class */
661+.highlight .vg {
662+ color: #dfc06f;
663+}
664+/* Name.Variable.Global */
665+.highlight .vi {
666+ color: #dfc06f;
667+}
668+/* Name.Variable.Instance */
669+.highlight .il {
670+ color: #d19a66;
671+}
672+/* Literal.Number.Integer.Long */
673+.highlight .lineno {
674+ -webkit-touch-callout: none;
675+ -webkit-user-select: none;
676+ -khtml-user-select: none;
677+ -moz-user-select: none;
678+ -ms-user-select: none;
679+ user-select: none;
680+ cursor: default;
681+ color: #556366;
682+}
683+.highlight .lineno::selection {
684+ background: transparent;
685+ /* WebKit/Blink Browsers */
686+}
687+.highlight .lineno::-moz-selection {
688+ background: transparent;
689+ /* Gecko Browsers */
690+}
691+.highlight pre {
692+ background-color: #282C34;
693+ color: #D7DAE0;
694+ border: none;
695+ margin-bottom: 25px;
696+ font-size: 15px;
697+ padding: 20px 10px;
698+}
699+.highlight {
700+ font-weight: 700;
701+}
702+.table > tbody > tr > td,
703+.table > tbody > tr > th {
704+ vertical-align: middle !important;
705+}
706+/*Global*/
707+body {
708+ background: #1d1f21 none !important;
709+ color: #D5D8D7 !important;
710+}
711+a {
712+ color: #41a2ce !important;
713+ text-decoration: none !important;
714+}
715+a:hover {
716+ color: #5F89AC !important;
717+}
718+input,
719+button,
720+textarea,
721+select {
722+ border: 1px solid #282a2e !important;
723+ background-color: #444 !important;
724+ color: #BBB !important;
725+}
726+input:focus,
727+button:focus,
728+textarea:focus,
729+select:focus {
730+ border: 1px solid #C5C8C6 !important;
731+ box-shadow: initial !important;
732+}
733+div#advanced-search-container div#categories label {
734+ background: none;
735+ border: 1px solid #282a2e;
736+}
737+ul.nav li a {
738+ border: 0 !important;
739+ border-bottom: 1px solid #4d3f43 !important;
740+}
741+#categories *,
742+.modal-wrapper * {
743+ background: #1d1f21 none !important;
744+ color: #D5D8D7 !important;
745+}
746+#categories * {
747+ border: 1px solid #3d3f43 !important;
748+}
749+#categories *:checked + label {
750+ border-bottom: 4px solid #3d9f94 !important;
751+}
752+.result-content,
753+.result-source,
754+.result-format {
755+ color: #B5B8B7 !important;
756+}
757+.external-link {
758+ color: #35B887 !important;
759+}
760+.table-striped tr td,
761+.table-striped tr th {
762+ border-color: #4d3f43 !important;
763+}
764+.highlight {
765+ background: #333333 !important;
766+}
767+/*nav*/
768+.navbar {
769+ background: #1d1f21 none;
770+ border: none;
771+}
772+.navbar .active,
773+.menu {
774+ background: none !important;
775+}
776+.label-default {
777+ background: none;
778+ color: #BBB;
779+}
780+.navbar-default .navbar-nav > .active > a,
781+.navbar-default .navbar-nav > .active > a:hover,
782+.navbar-default .navbar-nav > .active > a:focus,
783+.nav-tabs.nav-justified > .active > a {
784+ background-color: #282a2e !important;
785+}
786+/*Search Page*/
787+.result-default:hover,
788+.result-code:hover,
789+.result-torrent:hover,
790+.result-videos:hover,
791+.result-map:hover {
792+ background-color: #222426;
793+}
794+/*buttons*/
795+.btn {
796+ color: #BBB;
797+ background-color: #444 ;
798+ border: 1px solid #282a2e;
799+}
800+.btn:hover {
801+ color: #444 !important;
802+ background-color: #BBB !important;
803+}
804+.btn-primary.active {
805+ color: #C5C8C6;
806+ background-color: #5F89AC;
807+ border-color: #5F89AC;
808+}
809+/*Right Pannels*/
810+.panel {
811+ border: 1px solid #111;
812+ background: none;
813+}
814+.panel-heading {
815+ color: #C5C8C6 !important;
816+ background: #282a2e !important;
817+ border-bottom: none;
818+}
819+.panel-body {
820+ color: #C5C8C6 !important;
821+ background: #1d1f21 !important;
822+ border-color: #111 !important;
823+}
824+p.btn.btn-default {
825+ background: none;
826+}
827+.table-striped > tbody > tr:nth-child(odd) > td,
828+.table-striped > tbody > tr:nth-child(odd) > th,
829+.table-striped > thead > tr:nth-child(odd) > th {
830+ background: #2d2f32 none !important;
831+ color: #D5D8D7 !important;
832+}
833+.label-success {
834+ background: #1d6f42 none !important;
835+}
836+.label-danger {
837+ background: #ad1f12 none !important;
838+}
839+.searx-navbar {
840+ background: #333334;
841+ height: 2.3rem;
842+ font-size: 1.3rem;
843+ line-height: 1.3rem;
844+ padding: 0.5rem;
845+ font-weight: bold;
846+ margin-bottom: 0.8rem;
847+}
848+.searx-navbar a,
849+.searx-navbar a:hover {
850+ margin-right: 2.0rem;
851+ color: white;
852+ text-decoration: none;
853+}
854+.searx-navbar .instance a {
855+ color: #01d7d4;
856+ margin-left: 2.0rem;
857+}
858+#main-logo {
859+ margin-top: 20vh;
860+ margin-bottom: 25px;
861+}
862+#main-logo > img {
863+ max-width: 350px;
864+ width: 80%;
865+}
866+.onoffswitch-inner:before,
867+.onoffswitch-inner:after {
868+ background: #1d1f21 none !important;
869+}
870+.onoffswitch-switch,
871+.onoffswitch-label {
872+ border: 2px solid #3d3f43 !important;
873+}
874+.nav > li > a:hover,
875+.nav > li > a:focus {
876+ background-color: #3d3f43 !important;
877+}
878+/*Images search*/
879+.img-thumbnail,
880+.thumbnail {
881+ padding: 0px;
882+ line-height: 1.42857143;
883+ background: none;
884+ border: none;
885+}
886+.modal-content {
887+ background: #1d1f21 none !important;
888+}
889+/*Preferences*/
890+.table > thead > tr > td.danger,
891+.table > tbody > tr > td.danger,
892+.table > tfoot > tr > td.danger,
893+.table > thead > tr > th.danger,
894+.table > tbody > tr > th.danger,
895+.table > tfoot > tr > th.danger,
896+.table > thead > tr.danger > td,
897+.table > tbody > tr.danger > td,
898+.table > tfoot > tr.danger > td,
899+.table > thead > tr.danger > th,
900+.table > tbody > tr.danger > th,
901+.table > tfoot > tr.danger > th {
902+ background: rgba(240, 0, 0, 0.56) !important;
903+ color: #C5C8C6 !important;
904+}
905+.table-hover > tbody > tr > td.danger:hover,
906+.table-hover > tbody > tr > th.danger:hover,
907+.table-hover > tbody > tr.danger:hover > td,
908+.table-hover > tbody > tr:hover > .danger,
909+.table-hover > tbody > tr.danger:hover > th {
910+ background: rgba(237, 59, 59, 0.61) !important;
911+ color: #C5C8C6 !important;
912+}
913+.table-hover > tbody > tr:hover > td,
914+.table-hover > tbody > tr:hover > th {
915+ background: #66696e !important;
916+}
917+.btn-success {
918+ color: #C5C8C6;
919+ background: #449d44;
920+}
921+.btn-danger {
922+ color: #C5C8C6;
923+ background: #d9534f;
924+}
925+.well {
926+ background: #444;
927+ border-color: #282a2e;
928+}
929+.highlight {
930+ background-color: transparent !important;
931+}
searx/static/themes/oscar/css/logicodev.min.css+1−1
@@ -1 +1 @@
1−.searx-navbar{background:#29314d;height:2.3rem;font-size:1.3rem;line-height:1.3rem;padding:.5rem;font-weight:700;margin-bottom:.8rem}.searx-navbar a,.searx-navbar a:hover{margin-right:2rem;color:#fff;text-decoration:none}.searx-navbar .instance a{color:#01d7d4;margin-left:2rem}#main-logo{margin-top:20vh;margin-bottom:25px}#main-logo>img{max-width:350px;width:80%}*{border-radius:0!important}html{position:relative;min-height:100%;color:#29314d}body{font-family:Roboto,Helvetica,Arial,sans-serif;margin-bottom:80px;background-color:#fff}body a{color:#08c}.footer{position:absolute;bottom:0;width:100%;height:60px;text-align:center;color:#999}input[type=checkbox]:checked+.label_hide_if_checked,input[type=checkbox]:checked+.label_hide_if_not_checked+.label_hide_if_checked{display:none}input[type=checkbox]:not(:checked)+.label_hide_if_not_checked,input[type=checkbox]:not(:checked)+.label_hide_if_checked+.label_hide_if_not_checked{display:none}.onoff-checkbox{width:15%}.onoffswitch{position:relative;width:110px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.onoffswitch-checkbox{display:none}.onoffswitch-label{display:block;overflow:hidden;cursor:pointer;border:2px solid #FFF!important;border-radius:50px!important}.onoffswitch-inner{display:block;transition:margin .3s ease-in 0s}.onoffswitch-inner:before,.onoffswitch-inner:after{display:block;float:left;width:50%;height:30px;padding:0;line-height:40px;font-size:20px;box-sizing:border-box;content:"";background-color:#EEE}.onoffswitch-switch{display:block;width:37px;background-color:#01d7d4;position:absolute;top:0;bottom:0;right:0;border:2px solid #FFF!important;border-radius:50px!important;transition:all .3s ease-in 0s}.onoffswitch-checkbox:checked+.onoffswitch-label .onoffswitch-inner{margin-right:0}.onoffswitch-checkbox:checked+.onoffswitch-label .onoffswitch-switch{right:71px;background-color:#A1A1A1}.result_header{margin-top:0;margin-bottom:2px;font-size:16px}.result_header .favicon{margin-bottom:-3px}.result_header a{color:#29314d;text-decoration:none}.result_header a:hover{color:#08c}.result_header a:visited{color:#684898}.result_header a .highlight{background-color:#f6f9fa}.result-content{margin-top:2px;margin-bottom:0;word-wrap:break-word;color:#666;font-size:13px}.result-content .highlight{font-weight:700}.external-link{color:#069025;font-size:12px;margin-bottom:15px}.external-link a{margin-right:3px}.result-default,.result-code,.result-torrent,.result-videos,.result-map{clear:both;padding:2px 4px}.result-default:hover,.result-code:hover,.result-torrent:hover,.result-videos:hover,.result-map:hover{background-color:#f6f9fa}.result-images{float:left!important;width:24%;margin:.5%}.result-images a{display:block;width:100%;background-size:cover}.img-thumbnail{margin:5px;max-height:128px;min-height:128px}.result-videos{clear:both}.result-videos hr{margin:5px 0 15px 0}.result-videos .collapse{width:100%}.result-videos .in{margin-bottom:8px}.result-torrent{clear:both}.result-torrent b{margin-right:5px;margin-left:5px}.result-torrent .seeders{color:#2ecc71}.result-torrent .leechers{color:#f35e77}.result-map{clear:both}.result-code{clear:both}.result-code .code-fork,.result-code .code-fork a{color:#666}.suggestion_item{margin:2px 5px;max-width:100%}.suggestion_item .btn{max-width:100%;white-space:normal;word-wrap:break-word;text-align:left}.result_download{margin-right:5px}#pagination{margin-top:30px;padding-bottom:60px}.label-default{color:#a4a4a4;background:0 0}.result .text-muted small{word-wrap:break-word}.modal-wrapper{box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-wrapper{background-clip:padding-box;background-color:#fff;border:1px solid rgba(0,0,0,.2);border-radius:6px;box-shadow:0 3px 9px rgba(0,0,0,.5);outline:0 none;position:relative}.infobox .panel-heading{background-color:#f6f9fa}.infobox .panel-heading .panel-title{font-weight:700}.infobox p{font-family:"DejaVu Serif",Georgia,Cambria,"Times New Roman",Times,serif!important;font-style:italic}.infobox .btn{background-color:#2ecc71;border:none}.infobox .btn a{color:#fff;margin:5px}.infobox .infobox_part{margin-bottom:20px;word-wrap:break-word;table-layout:fixed}.infobox .infobox_part:last-child{margin-bottom:0}.search_categories,#categories{text-transform:capitalize;margin-bottom:.5rem;display:flex;flex-wrap:wrap;flex-flow:row wrap;align-content:stretch}.search_categories label,#categories label,.search_categories .input-group-addon,#categories .input-group-addon{flex-grow:1;flex-basis:auto;font-size:1.2rem;font-weight:400;background-color:#fff;border:#ddd 1px solid;border-right:none;color:#666;padding-bottom:.4rem;padding-top:.4rem;text-align:center;min-width:50px}.search_categories label:last-child,#categories label:last-child,.search_categories .input-group-addon:last-child,#categories .input-group-addon:last-child{border-right:#ddd 1px solid}.search_categories input[type=checkbox]:checked+label,#categories input[type=checkbox]:checked+label{color:#29314d;font-weight:700;border-bottom:#01d7d4 5px solid}#main-logo{margin-top:10vh;margin-bottom:25px}#main-logo>img{max-width:350px;width:80%}#q{box-shadow:none;border-right:none;border-color:#a4a4a4}#search_form .input-group-btn .btn{border-color:#a4a4a4}#search_form .input-group-btn .btn:hover{background-color:#2ecc71;color:#fff}.custom-select{appearance:none;-webkit-appearance:none;-moz-appearance:none;font-size:1.2rem;font-weight:400;background-color:#fff;border:#ddd 1px solid;color:#666;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAQAAACR313BAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAABFkAAARZAVnbJUkAAAAHdElNRQfgBxgLDwB20OFsAAAAbElEQVQY073OsQ3CMAAEwJMYwJGnsAehpoXJItltBkmcdZBYgIIiQoLglnz3ui+eP+bk5uneteTMZJa6OJuIqvYzSJoqwqBq8gdmTTW86/dghxAUq4xsVYT9laBYXCw93Aajh7GPEF23t4fkBYevGFTANkPRAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE2LTA3LTI0VDExOjU1OjU4KzAyOjAwRFqFOQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNi0wNy0yNFQxMToxNTowMCswMjowMP7RDgQAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC) 96% no-repeat}.search-margin{margin-bottom:.6em}#advanced-search-container{display:none;text-align:left;margin-bottom:1rem;clear:both}#advanced-search-container label,#advanced-search-container .input-group-addon{font-size:1.2rem;font-weight:400;background-color:#fff;border:#ddd 1px solid;border-right:none;color:#666;padding-bottom:.4rem;padding-right:.7rem;padding-left:.7rem}#advanced-search-container label:last-child,#advanced-search-container .input-group-addon:last-child{border-right:#ddd 1px solid}#advanced-search-container input[type=radio]{display:none}#advanced-search-container input[type=radio]:checked+label{color:#29314d;font-weight:700;border-bottom:#01d7d4 5px solid}#check-advanced{display:none}#check-advanced:checked~#advanced-search-container{display:block}.advanced{padding:0;margin-top:.3rem;text-align:right}.advanced label,.advanced select{cursor:pointer}.cursor-text{cursor:text!important}.cursor-pointer{cursor:pointer!important}pre,code{font-family:'Ubuntu Mono','Courier New','Lucida Console',monospace!important}.lineno{margin-right:5px}.highlight .hll{background-color:#ffc}.highlight{background:#f8f8f8}.highlight .c{color:#556366;font-style:italic}.highlight .err{border:1px solid #ffa92f}.highlight .k{color:#BE74D5;font-weight:700}.highlight .o{color:#d19a66}.highlight .cm{color:#556366;font-style:italic}.highlight .cp{color:#bc7a00}.highlight .c1{color:#556366;font-style:italic}.highlight .cs{color:#556366;font-style:italic}.highlight .gd{color:#a00000}.highlight .ge{font-style:italic}.highlight .gr{color:red}.highlight .gh{color:navy;font-weight:700}.highlight .gi{color:#00a000}.highlight .go{color:#888}.highlight .gp{color:navy;font-weight:700}.highlight .gs{font-weight:700}.highlight .gu{color:purple;font-weight:700}.highlight .gt{color:#04d}.highlight .kc{color:#BE74D5;font-weight:700}.highlight .kd{color:#BE74D5;font-weight:700}.highlight .kn{color:#BE74D5;font-weight:700}.highlight .kp{color:#be74d5}.highlight .kr{color:#BE74D5;font-weight:700}.highlight .kt{color:#d46c72}.highlight .m{color:#d19a66}.highlight .s{color:#86c372}.highlight .na{color:#7d9029}.highlight .nb{color:#be74d5}.highlight .nc{color:#61AFEF;font-weight:700}.highlight .no{color:#d19a66}.highlight .nd{color:#a2f}.highlight .ni{color:#999;font-weight:700}.highlight .ne{color:#D2413A;font-weight:700}.highlight .nf{color:#61afef}.highlight .nl{color:#a0a000}.highlight .nn{color:#61AFEF;font-weight:700}.highlight .nt{color:#BE74D5;font-weight:700}.highlight .nv{color:#dfc06f}.highlight .ow{color:#A2F;font-weight:700}.highlight .w{color:#d7dae0}.highlight .mf{color:#d19a66}.highlight .mh{color:#d19a66}.highlight .mi{color:#d19a66}.highlight .mo{color:#d19a66}.highlight .sb{color:#86c372}.highlight .sc{color:#86c372}.highlight .sd{color:#86C372;font-style:italic}.highlight .s2{color:#86c372}.highlight .se{color:#B62;font-weight:700}.highlight .sh{color:#86c372}.highlight .si{color:#B68;font-weight:700}.highlight .sx{color:#be74d5}.highlight .sr{color:#b68}.highlight .s1{color:#86c372}.highlight .ss{color:#dfc06f}.highlight .bp{color:#be74d5}.highlight .vc{color:#dfc06f}.highlight .vg{color:#dfc06f}.highlight .vi{color:#dfc06f}.highlight .il{color:#d19a66}.highlight .lineno{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default;color:#556366}.highlight .lineno::selection{background:0 0}.highlight .lineno::-moz-selection{background:0 0}.highlight pre{background-color:#282C34;color:#D7DAE0;border:none;margin-bottom:25px;font-size:15px;padding:20px 10px}.highlight{font-weight:700}.table>tbody>tr>td,.table>tbody>tr>th{vertical-align:middle!important}
1+.searx-navbar{background:#29314d;height:2.3rem;font-size:1.3rem;line-height:1.3rem;padding:.5rem;font-weight:700;margin-bottom:.8rem}.searx-navbar a,.searx-navbar a:hover{margin-right:2rem;color:#fff;text-decoration:none}.searx-navbar .instance a{color:#01d7d4;margin-left:2rem}#main-logo{margin-top:20vh;margin-bottom:25px}#main-logo>img{max-width:350px;width:80%}*{border-radius:0!important}html{position:relative;min-height:100%;color:#29314d}body{font-family:Roboto,Helvetica,Arial,sans-serif;margin-bottom:80px;background-color:#fff}body a{color:#08c}.footer{position:absolute;bottom:0;width:100%;height:60px;text-align:center;color:#999}input[type=checkbox]:checked+.label_hide_if_checked,input[type=checkbox]:checked+.label_hide_if_not_checked+.label_hide_if_checked{display:none}input[type=checkbox]:not(:checked)+.label_hide_if_not_checked,input[type=checkbox]:not(:checked)+.label_hide_if_checked+.label_hide_if_not_checked{display:none}.onoff-checkbox{width:15%}.onoffswitch{position:relative;width:110px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.onoffswitch-checkbox{display:none}.onoffswitch-label{display:block;overflow:hidden;cursor:pointer;border:2px solid #FFF!important;border-radius:50px!important}.onoffswitch-inner{display:block;transition:margin .3s ease-in 0s}.onoffswitch-inner:before,.onoffswitch-inner:after{display:block;float:left;width:50%;height:30px;padding:0;line-height:40px;font-size:20px;box-sizing:border-box;content:"";background-color:#EEE}.onoffswitch-switch{display:block;width:37px;background-color:#01d7d4;position:absolute;top:0;bottom:0;right:0;border:2px solid #FFF!important;border-radius:50px!important;transition:all .3s ease-in 0s}.onoffswitch-checkbox:checked+.onoffswitch-label .onoffswitch-inner{margin-right:0}.onoffswitch-checkbox:checked+.onoffswitch-label .onoffswitch-switch{right:71px;background-color:#A1A1A1}.result_header{margin-top:0;margin-bottom:2px;font-size:16px}.result_header .favicon{margin-bottom:-3px}.result_header a{color:#29314d;text-decoration:none}.result_header a:hover{color:#08c}.result_header a:visited{color:#684898}.result_header a .highlight{background-color:#f6f9fa}.result-content,.result-format,.result-source{margin-top:2px;margin-bottom:0;word-wrap:break-word;color:#666;font-size:13px}.result-content .highlight,.result-format .highlight,.result-source .highlight{font-weight:700}.result-source{font-size:10px;float:left}.result-format{font-size:10px;float:right}.external-link{color:#069025;font-size:12px;margin-bottom:15px}.external-link a{margin-right:3px}.result-default,.result-code,.result-torrent,.result-videos,.result-map{clear:both;padding:2px 4px}.result-default:hover,.result-code:hover,.result-torrent:hover,.result-videos:hover,.result-map:hover{background-color:#f6f9fa}.result-images{float:left!important;width:24%;margin:.5%}.result-images a{display:block;width:100%;background-size:cover}.img-thumbnail{margin:5px;max-height:128px;min-height:128px}.result-videos{clear:both}.result-videos hr{margin:5px 0 15px 0}.result-videos .collapse{width:100%}.result-videos .in{margin-bottom:8px}.result-torrent{clear:both}.result-torrent b{margin-right:5px;margin-left:5px}.result-torrent .seeders{color:#2ecc71}.result-torrent .leechers{color:#f35e77}.result-map{clear:both}.result-code{clear:both}.result-code .code-fork,.result-code .code-fork a{color:#666}.suggestion_item{margin:2px 5px;max-width:100%}.suggestion_item .btn{max-width:100%;white-space:normal;word-wrap:break-word;text-align:left}.result_download{margin-right:5px}#pagination{margin-top:30px;padding-bottom:60px}.label-default{color:#a4a4a4;background:0 0}.result .text-muted small{word-wrap:break-word}.modal-wrapper{box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-wrapper{background-clip:padding-box;background-color:#fff;border:1px solid rgba(0,0,0,.2);border-radius:6px;box-shadow:0 3px 9px rgba(0,0,0,.5);outline:0 none;position:relative}.infobox .panel-heading{background-color:#f6f9fa}.infobox .panel-heading .panel-title{font-weight:700}.infobox p{font-family:"DejaVu Serif",Georgia,Cambria,"Times New Roman",Times,serif!important;font-style:italic}.infobox .btn{background-color:#2ecc71;border:none}.infobox .btn a{color:#fff;margin:5px}.infobox .infobox_part{margin-bottom:20px;word-wrap:break-word;table-layout:fixed}.infobox .infobox_part:last-child{margin-bottom:0}.search_categories,#categories{text-transform:capitalize;margin-bottom:.5rem;display:flex;flex-wrap:wrap;flex-flow:row wrap;align-content:stretch}.search_categories label,#categories label,.search_categories .input-group-addon,#categories .input-group-addon{flex-grow:1;flex-basis:auto;font-size:1.2rem;font-weight:400;background-color:#fff;border:#ddd 1px solid;border-right:none;color:#666;padding-bottom:.4rem;padding-top:.4rem;text-align:center;min-width:50px}.search_categories label:last-child,#categories label:last-child,.search_categories .input-group-addon:last-child,#categories .input-group-addon:last-child{border-right:#ddd 1px solid}.search_categories input[type=checkbox]:checked+label,#categories input[type=checkbox]:checked+label{color:#29314d;font-weight:700;border-bottom:#01d7d4 5px solid}#main-logo{margin-top:10vh;margin-bottom:25px}#main-logo>img{max-width:350px;width:80%}#q{box-shadow:none;border-right:none;border-color:#a4a4a4}#search_form .input-group-btn .btn{border-color:#a4a4a4}#search_form .input-group-btn .btn:hover{background-color:#2ecc71;color:#fff}.custom-select{appearance:none;-webkit-appearance:none;-moz-appearance:none;font-size:1.2rem;font-weight:400;background-color:#fff;border:#ddd 1px solid;color:#666;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAQAAACR313BAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAABFkAAARZAVnbJUkAAAAHdElNRQfgBxgLDwB20OFsAAAAbElEQVQY073OsQ3CMAAEwJMYwJGnsAehpoXJItltBkmcdZBYgIIiQoLglnz3ui+eP+bk5uneteTMZJa6OJuIqvYzSJoqwqBq8gdmTTW86/dghxAUq4xsVYT9laBYXCw93Aajh7GPEF23t4fkBYevGFTANkPRAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE2LTA3LTI0VDExOjU1OjU4KzAyOjAwRFqFOQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNi0wNy0yNFQxMToxNTowMCswMjowMP7RDgQAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC) 96% no-repeat}.search-margin{margin-bottom:.6em}#advanced-search-container{display:none;text-align:left;margin-bottom:1rem;clear:both}#advanced-search-container label,#advanced-search-container .input-group-addon{font-size:1.2rem;font-weight:400;background-color:#fff;border:#ddd 1px solid;border-right:none;color:#666;padding-bottom:.4rem;padding-right:.7rem;padding-left:.7rem}#advanced-search-container label:last-child,#advanced-search-container .input-group-addon:last-child{border-right:#ddd 1px solid}#advanced-search-container input[type=radio]{display:none}#advanced-search-container input[type=radio]:checked+label{color:#29314d;font-weight:700;border-bottom:#01d7d4 5px solid}#check-advanced{display:none}#check-advanced:checked~#advanced-search-container{display:block}.advanced{padding:0;margin-top:.3rem;text-align:right}.advanced label,.advanced select{cursor:pointer}.cursor-text{cursor:text!important}.cursor-pointer{cursor:pointer!important}pre,code{font-family:'Ubuntu Mono','Courier New','Lucida Console',monospace!important}.lineno{margin-right:5px}.highlight .hll{background-color:#ffc}.highlight{background:#f8f8f8}.highlight .c{color:#556366;font-style:italic}.highlight .err{border:1px solid #ffa92f}.highlight .k{color:#BE74D5;font-weight:700}.highlight .o{color:#d19a66}.highlight .cm{color:#556366;font-style:italic}.highlight .cp{color:#bc7a00}.highlight .c1{color:#556366;font-style:italic}.highlight .cs{color:#556366;font-style:italic}.highlight .gd{color:#a00000}.highlight .ge{font-style:italic}.highlight .gr{color:red}.highlight .gh{color:navy;font-weight:700}.highlight .gi{color:#00a000}.highlight .go{color:#888}.highlight .gp{color:navy;font-weight:700}.highlight .gs{font-weight:700}.highlight .gu{color:purple;font-weight:700}.highlight .gt{color:#04d}.highlight .kc{color:#BE74D5;font-weight:700}.highlight .kd{color:#BE74D5;font-weight:700}.highlight .kn{color:#BE74D5;font-weight:700}.highlight .kp{color:#be74d5}.highlight .kr{color:#BE74D5;font-weight:700}.highlight .kt{color:#d46c72}.highlight .m{color:#d19a66}.highlight .s{color:#86c372}.highlight .na{color:#7d9029}.highlight .nb{color:#be74d5}.highlight .nc{color:#61AFEF;font-weight:700}.highlight .no{color:#d19a66}.highlight .nd{color:#a2f}.highlight .ni{color:#999;font-weight:700}.highlight .ne{color:#D2413A;font-weight:700}.highlight .nf{color:#61afef}.highlight .nl{color:#a0a000}.highlight .nn{color:#61AFEF;font-weight:700}.highlight .nt{color:#BE74D5;font-weight:700}.highlight .nv{color:#dfc06f}.highlight .ow{color:#A2F;font-weight:700}.highlight .w{color:#d7dae0}.highlight .mf{color:#d19a66}.highlight .mh{color:#d19a66}.highlight .mi{color:#d19a66}.highlight .mo{color:#d19a66}.highlight .sb{color:#86c372}.highlight .sc{color:#86c372}.highlight .sd{color:#86C372;font-style:italic}.highlight .s2{color:#86c372}.highlight .se{color:#B62;font-weight:700}.highlight .sh{color:#86c372}.highlight .si{color:#B68;font-weight:700}.highlight .sx{color:#be74d5}.highlight .sr{color:#b68}.highlight .s1{color:#86c372}.highlight .ss{color:#dfc06f}.highlight .bp{color:#be74d5}.highlight .vc{color:#dfc06f}.highlight .vg{color:#dfc06f}.highlight .vi{color:#dfc06f}.highlight .il{color:#d19a66}.highlight .lineno{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default;color:#556366}.highlight .lineno::selection{background:0 0}.highlight .lineno::-moz-selection{background:0 0}.highlight pre{background-color:#282C34;color:#D7DAE0;border:none;margin-bottom:25px;font-size:15px;padding:20px 10px}.highlight{font-weight:700}.table>tbody>tr>td,.table>tbody>tr>th{vertical-align:middle!important}
searx/static/themes/oscar/css/pointhi.cssnew file+562
@@ -0,0 +1,562 @@
1+html {
2+ position: relative;
3+ min-height: 100%;
4+}
5+body {
6+ /* Margin bottom by footer height */
7+ margin-bottom: 80px;
8+}
9+.footer {
10+ position: absolute;
11+ bottom: 0;
12+ width: 100%;
13+ /* Set the fixed height of the footer here */
14+ height: 60px;
15+}
16+input[type=checkbox]:checked + .label_hide_if_checked,
17+input[type=checkbox]:checked + .label_hide_if_not_checked + .label_hide_if_checked {
18+ display: none;
19+}
20+input[type=checkbox]:not(:checked) + .label_hide_if_not_checked,
21+input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not_checked {
22+ display: none;
23+}
24+.onoff-checkbox {
25+ width: 15%;
26+}
27+.onoffswitch {
28+ position: relative;
29+ width: 110px;
30+ -webkit-user-select: none;
31+ -moz-user-select: none;
32+ -ms-user-select: none;
33+}
34+.onoffswitch-checkbox {
35+ display: none;
36+}
37+.onoffswitch-label {
38+ display: block;
39+ overflow: hidden;
40+ cursor: pointer;
41+ border: 2px solid #FFFFFF !important;
42+ border-radius: 50px !important;
43+}
44+.onoffswitch-inner {
45+ display: block;
46+ transition: margin 0.3s ease-in 0s;
47+}
48+.onoffswitch-inner:before,
49+.onoffswitch-inner:after {
50+ display: block;
51+ float: left;
52+ width: 50%;
53+ height: 30px;
54+ padding: 0;
55+ line-height: 40px;
56+ font-size: 20px;
57+ box-sizing: border-box;
58+ content: "";
59+ background-color: #EEEEEE;
60+}
61+.onoffswitch-switch {
62+ display: block;
63+ width: 37px;
64+ background-color: #00CC00;
65+ position: absolute;
66+ top: 0;
67+ bottom: 0;
68+ right: 0px;
69+ border: 2px solid #FFFFFF !important;
70+ border-radius: 50px !important;
71+ transition: all 0.3s ease-in 0s;
72+}
73+.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
74+ margin-right: 0;
75+}
76+.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
77+ right: 71px;
78+ background-color: #A1A1A1;
79+}
80+.result_header {
81+ margin-bottom: 5px;
82+ margin-top: 20px;
83+}
84+.result_header .favicon {
85+ margin-bottom: -3px;
86+}
87+.result_header a {
88+ vertical-align: bottom;
89+}
90+.result_header a .highlight {
91+ font-weight: bold;
92+}
93+.result-content {
94+ margin-top: 5px;
95+ word-wrap: break-word;
96+}
97+.result-content .highlight {
98+ font-weight: bold;
99+}
100+.result-default {
101+ clear: both;
102+}
103+.result-images {
104+ float: left !important;
105+ height: 138px;
106+}
107+.img-thumbnail {
108+ margin: 5px;
109+ max-height: 128px;
110+}
111+.result-videos {
112+ clear: both;
113+}
114+.result-torrents {
115+ clear: both;
116+}
117+.result-map {
118+ clear: both;
119+}
120+.result-code {
121+ clear: both;
122+}
123+.suggestion_item {
124+ margin: 2px 5px;
125+ max-width: 100%;
126+}
127+.suggestion_item .btn {
128+ max-width: 100%;
129+ white-space: normal;
130+ word-wrap: break-word;
131+ text-align: left;
132+}
133+.result_download {
134+ margin-right: 5px;
135+}
136+#pagination {
137+ margin-top: 30px;
138+ padding-bottom: 50px;
139+}
140+.label-default {
141+ color: #AAA;
142+ background: #FFF;
143+}
144+.result .text-muted small {
145+ word-wrap: break-word;
146+}
147+.modal-wrapper {
148+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
149+}
150+.modal-wrapper {
151+ background-clip: padding-box;
152+ background-color: #fff;
153+ border: 1px solid rgba(0, 0, 0, 0.2);
154+ border-radius: 6px;
155+ box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
156+ outline: 0 none;
157+ position: relative;
158+}
159+.infobox .infobox_part {
160+ margin-bottom: 20px;
161+ word-wrap: break-word;
162+ table-layout: fixed;
163+}
164+.infobox .infobox_part:last-child {
165+ margin-bottom: 0;
166+}
167+.search_categories,
168+#categories {
169+ text-transform: capitalize;
170+ margin-bottom: 1.5rem;
171+ margin-top: 1.5rem;
172+ display: flex;
173+ flex-wrap: wrap;
174+ align-content: stretch;
175+}
176+.search_categories label,
177+#categories label,
178+.search_categories .input-group-addon,
179+#categories .input-group-addon {
180+ flex-grow: 1;
181+ flex-basis: auto;
182+ font-size: 1.3rem;
183+ font-weight: normal;
184+ background-color: white;
185+ border: #DDD 1px solid;
186+ border-right: none;
187+ color: #333;
188+ padding-bottom: 0.8rem;
189+ padding-top: 0.8rem;
190+ text-align: center;
191+ min-width: 50px;
192+}
193+.search_categories label:last-child,
194+#categories label:last-child,
195+.search_categories .input-group-addon:last-child,
196+#categories .input-group-addon:last-child {
197+ border-right: #DDD 1px solid;
198+}
199+.search_categories input[type="checkbox"]:checked + label,
200+#categories input[type="checkbox"]:checked + label {
201+ color: black;
202+ font-weight: bold;
203+ background-color: #EEE;
204+}
205+#advanced-search-container {
206+ display: none;
207+ text-align: center;
208+ margin-bottom: 1rem;
209+ clear: both;
210+}
211+#advanced-search-container label,
212+#advanced-search-container .input-group-addon {
213+ font-size: 1.3rem;
214+ font-weight: normal;
215+ background-color: white;
216+ border: #DDD 1px solid;
217+ border-right: none;
218+ color: #333;
219+ padding-bottom: 0.8rem;
220+ padding-left: 1.2rem;
221+ padding-right: 1.2rem;
222+}
223+#advanced-search-container label:last-child,
224+#advanced-search-container .input-group-addon:last-child {
225+ border-right: #DDD 1px solid;
226+}
227+#advanced-search-container input[type="radio"] {
228+ display: none;
229+}
230+#advanced-search-container input[type="radio"]:checked + label {
231+ color: black;
232+ font-weight: bold;
233+ background-color: #EEE;
234+}
235+#check-advanced {
236+ display: none;
237+}
238+#check-advanced:checked ~ #advanced-search-container {
239+ display: block;
240+}
241+.advanced {
242+ padding: 0;
243+ margin-top: 0.3rem;
244+ text-align: right;
245+}
246+.advanced label,
247+.advanced select {
248+ cursor: pointer;
249+}
250+.cursor-text {
251+ cursor: text !important;
252+}
253+.cursor-pointer {
254+ cursor: pointer !important;
255+}
256+.highlight .hll {
257+ background-color: #ffffcc;
258+}
259+.highlight {
260+ background: #f8f8f8;
261+}
262+.highlight .c {
263+ color: #408080;
264+ font-style: italic;
265+}
266+/* Comment */
267+.highlight .err {
268+ border: 1px solid #ff0000;
269+}
270+/* Error */
271+.highlight .k {
272+ color: #008000;
273+ font-weight: bold;
274+}
275+/* Keyword */
276+.highlight .o {
277+ color: #666666;
278+}
279+/* Operator */
280+.highlight .cm {
281+ color: #408080;
282+ font-style: italic;
283+}
284+/* Comment.Multiline */
285+.highlight .cp {
286+ color: #bc7a00;
287+}
288+/* Comment.Preproc */
289+.highlight .c1 {
290+ color: #408080;
291+ font-style: italic;
292+}
293+/* Comment.Single */
294+.highlight .cs {
295+ color: #408080;
296+ font-style: italic;
297+}
298+/* Comment.Special */
299+.highlight .gd {
300+ color: #a00000;
301+}
302+/* Generic.Deleted */
303+.highlight .ge {
304+ font-style: italic;
305+}
306+/* Generic.Emph */
307+.highlight .gr {
308+ color: #ff0000;
309+}
310+/* Generic.Error */
311+.highlight .gh {
312+ color: #000080;
313+ font-weight: bold;
314+}
315+/* Generic.Heading */
316+.highlight .gi {
317+ color: #00a000;
318+}
319+/* Generic.Inserted */
320+.highlight .go {
321+ color: #888888;
322+}
323+/* Generic.Output */
324+.highlight .gp {
325+ color: #000080;
326+ font-weight: bold;
327+}
328+/* Generic.Prompt */
329+.highlight .gs {
330+ font-weight: bold;
331+}
332+/* Generic.Strong */
333+.highlight .gu {
334+ color: #800080;
335+ font-weight: bold;
336+}
337+/* Generic.Subheading */
338+.highlight .gt {
339+ color: #0044dd;
340+}
341+/* Generic.Traceback */
342+.highlight .kc {
343+ color: #008000;
344+ font-weight: bold;
345+}
346+/* Keyword.Constant */
347+.highlight .kd {
348+ color: #008000;
349+ font-weight: bold;
350+}
351+/* Keyword.Declaration */
352+.highlight .kn {
353+ color: #008000;
354+ font-weight: bold;
355+}
356+/* Keyword.Namespace */
357+.highlight .kp {
358+ color: #008000;
359+}
360+/* Keyword.Pseudo */
361+.highlight .kr {
362+ color: #008000;
363+ font-weight: bold;
364+}
365+/* Keyword.Reserved */
366+.highlight .kt {
367+ color: #b00040;
368+}
369+/* Keyword.Type */
370+.highlight .m {
371+ color: #666666;
372+}
373+/* Literal.Number */
374+.highlight .s {
375+ color: #ba2121;
376+}
377+/* Literal.String */
378+.highlight .na {
379+ color: #7d9029;
380+}
381+/* Name.Attribute */
382+.highlight .nb {
383+ color: #008000;
384+}
385+/* Name.Builtin */
386+.highlight .nc {
387+ color: #0000FF;
388+ font-weight: bold;
389+}
390+/* Name.Class */
391+.highlight .no {
392+ color: #880000;
393+}
394+/* Name.Constant */
395+.highlight .nd {
396+ color: #aa22ff;
397+}
398+/* Name.Decorator */
399+.highlight .ni {
400+ color: #999999;
401+ font-weight: bold;
402+}
403+/* Name.Entity */
404+.highlight .ne {
405+ color: #D2413A;
406+ font-weight: bold;
407+}
408+/* Name.Exception */
409+.highlight .nf {
410+ color: #0000ff;
411+}
412+/* Name.Function */
413+.highlight .nl {
414+ color: #a0a000;
415+}
416+/* Name.Label */
417+.highlight .nn {
418+ color: #0000FF;
419+ font-weight: bold;
420+}
421+/* Name.Namespace */
422+.highlight .nt {
423+ color: #008000;
424+ font-weight: bold;
425+}
426+/* Name.Tag */
427+.highlight .nv {
428+ color: #19177c;
429+}
430+/* Name.Variable */
431+.highlight .ow {
432+ color: #AA22FF;
433+ font-weight: bold;
434+}
435+/* Operator.Word */
436+.highlight .w {
437+ color: #bbbbbb;
438+}
439+/* Text.Whitespace */
440+.highlight .mf {
441+ color: #666666;
442+}
443+/* Literal.Number.Float */
444+.highlight .mh {
445+ color: #666666;
446+}
447+/* Literal.Number.Hex */
448+.highlight .mi {
449+ color: #666666;
450+}
451+/* Literal.Number.Integer */
452+.highlight .mo {
453+ color: #666666;
454+}
455+/* Literal.Number.Oct */
456+.highlight .sb {
457+ color: #ba2121;
458+}
459+/* Literal.String.Backtick */
460+.highlight .sc {
461+ color: #ba2121;
462+}
463+/* Literal.String.Char */
464+.highlight .sd {
465+ color: #BA2121;
466+ font-style: italic;
467+}
468+/* Literal.String.Doc */
469+.highlight .s2 {
470+ color: #ba2121;
471+}
472+/* Literal.String.Double */
473+.highlight .se {
474+ color: #BB6622;
475+ font-weight: bold;
476+}
477+/* Literal.String.Escape */
478+.highlight .sh {
479+ color: #ba2121;
480+}
481+/* Literal.String.Heredoc */
482+.highlight .si {
483+ color: #BB6688;
484+ font-weight: bold;
485+}
486+/* Literal.String.Interpol */
487+.highlight .sx {
488+ color: #008000;
489+}
490+/* Literal.String.Other */
491+.highlight .sr {
492+ color: #bb6688;
493+}
494+/* Literal.String.Regex */
495+.highlight .s1 {
496+ color: #ba2121;
497+}
498+/* Literal.String.Single */
499+.highlight .ss {
500+ color: #19177c;
501+}
502+/* Literal.String.Symbol */
503+.highlight .bp {
504+ color: #008000;
505+}
506+/* Name.Builtin.Pseudo */
507+.highlight .vc {
508+ color: #19177c;
509+}
510+/* Name.Variable.Class */
511+.highlight .vg {
512+ color: #19177c;
513+}
514+/* Name.Variable.Global */
515+.highlight .vi {
516+ color: #19177c;
517+}
518+/* Name.Variable.Instance */
519+.highlight .il {
520+ color: #666666;
521+}
522+/* Literal.Number.Integer.Long */
523+.highlight .lineno {
524+ -webkit-touch-callout: none;
525+ -webkit-user-select: none;
526+ -khtml-user-select: none;
527+ -moz-user-select: none;
528+ -ms-user-select: none;
529+ user-select: none;
530+ cursor: default;
531+}
532+.highlight .lineno::selection {
533+ background: transparent;
534+ /* WebKit/Blink Browsers */
535+}
536+.highlight .lineno::-moz-selection {
537+ background: transparent;
538+ /* Gecko Browsers */
539+}
540+.searx-navbar {
541+ background: #eee;
542+ color: #aaa;
543+ height: 2.3rem;
544+ font-size: 1.3rem;
545+ line-height: 1.3rem;
546+ padding: 0.5rem;
547+ font-weight: bold;
548+ margin-bottom: 1.3rem;
549+}
550+.searx-navbar a,
551+.searx-navbar a:hover {
552+ margin-right: 2.0rem;
553+ text-decoration: none;
554+}
555+.searx-navbar .instance a {
556+ color: #444;
557+ margin-left: 2.0rem;
558+}
559+.table > tbody > tr > td,
560+.table > tbody > tr > th {
561+ vertical-align: middle !important;
562+}
searx/static/themes/oscar/gruntfile.js+3−3
@@ -24,7 +24,7 @@ module.exports = function(grunt) {
24 jshint: {
24 jshint: {
25 files: ['gruntfile.js', 'js/searx_src/*.js'],
25 files: ['gruntfile.js', 'js/searx_src/*.js'],
26 options: {
26 options: {
27− reporterOutput: "",
27+ reporterOutput: "",
28 // options here to override JSHint defaults
28 // options here to override JSHint defaults
29 globals: {
29 globals: {
30 jQuery: true,
30 jQuery: true,
@@ -55,7 +55,7 @@ module.exports = function(grunt) {
55 "css/logicodev-dark.min.css": "less/logicodev-dark/oscar.less"}
55 "css/logicodev-dark.min.css": "less/logicodev-dark/oscar.less"}
56 },
56 },
57 /*
57 /*
58− // built with ./manage.sh styles
58+ // built with ./manage.sh styles
59 bootstrap: {
59 bootstrap: {
60 options: {
60 options: {
61 paths: ["less/bootstrap"],
61 paths: ["less/bootstrap"],
@@ -90,7 +90,7 @@ module.exports = function(grunt) {
90 grunt.registerTask('test', ['jshint']);
90 grunt.registerTask('test', ['jshint']);
91
91
92 grunt.registerTask('default', ['jshint', 'concat', 'uglify', 'less']);
92 grunt.registerTask('default', ['jshint', 'concat', 'uglify', 'less']);
93−
93+
94 grunt.registerTask('styles', ['less']);
94 grunt.registerTask('styles', ['less']);
95
95
96};
96};
searx/static/themes/oscar/img/icons/invidious.pngnew file

Binary file not shown.

searx/static/themes/oscar/js/searx.jsnew file+356
@@ -0,0 +1,356 @@
1+/**
2+ * searx is free software: you can redistribute it and/or modify
3+ * it under the terms of the GNU Affero General Public License as published by
4+ * the Free Software Foundation, either version 3 of the License, or
5+ * (at your option) any later version.
6+ *
7+ * searx is distributed in the hope that it will be useful,
8+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
9+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+ * GNU Affero General Public License for more details.
11+ *
12+ * You should have received a copy of the GNU Affero General Public License
13+ * along with searx. If not, see < http://www.gnu.org/licenses/ >.
14+ *
15+ * (C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
16+ */
17+
18+requirejs.config({
19+ baseUrl: './static/themes/oscar/js',
20+ paths: {
21+ app: '../app'
22+ }
23+});
24+;/**
25+ * searx is free software: you can redistribute it and/or modify
26+ * it under the terms of the GNU Affero General Public License as published by
27+ * the Free Software Foundation, either version 3 of the License, or
28+ * (at your option) any later version.
29+ *
30+ * searx is distributed in the hope that it will be useful,
31+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
32+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33+ * GNU Affero General Public License for more details.
34+ *
35+ * You should have received a copy of the GNU Affero General Public License
36+ * along with searx. If not, see < http://www.gnu.org/licenses/ >.
37+ *
38+ * (C) 2019 by Alexandre Flament
39+ */
40+window.searx = (function(d) {
41+ 'use strict';
42+
43+ // add data- properties
44+ var script = d.currentScript || (function() {
45+ var scripts = d.getElementsByTagName('script');
46+ return scripts[scripts.length - 1];
47+ })();
48+
49+ return {
50+ autocompleter: script.getAttribute('data-autocompleter') === 'true',
51+ method: script.getAttribute('data-method')
52+ };
53+})(document);
54+;/**
55+ * searx is free software: you can redistribute it and/or modify
56+ * it under the terms of the GNU Affero General Public License as published by
57+ * the Free Software Foundation, either version 3 of the License, or
58+ * (at your option) any later version.
59+ *
60+ * searx is distributed in the hope that it will be useful,
61+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
62+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
63+ * GNU Affero General Public License for more details.
64+ *
65+ * You should have received a copy of the GNU Affero General Public License
66+ * along with searx. If not, see < http://www.gnu.org/licenses/ >.
67+ *
68+ * (C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
69+ */
70+
71+if(searx.autocompleter) {
72+ searx.searchResults = new Bloodhound({
73+ datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
74+ queryTokenizer: Bloodhound.tokenizers.whitespace,
75+ remote: './autocompleter?q=%QUERY'
76+ });
77+ searx.searchResults.initialize();
78+}
79+
80+$(document).ready(function(){
81+ if(searx.autocompleter) {
82+ $('#q').typeahead(null, {
83+ name: 'search-results',
84+ displayKey: function(result) {
85+ return result;
86+ },
87+ source: searx.searchResults.ttAdapter()
88+ });
89+ }
90+});
91+;/**
92+ * searx is free software: you can redistribute it and/or modify
93+ * it under the terms of the GNU Affero General Public License as published by
94+ * the Free Software Foundation, either version 3 of the License, or
95+ * (at your option) any later version.
96+ *
97+ * searx is distributed in the hope that it will be useful,
98+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
99+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
100+ * GNU Affero General Public License for more details.
101+ *
102+ * You should have received a copy of the GNU Affero General Public License
103+ * along with searx. If not, see < http://www.gnu.org/licenses/ >.
104+ *
105+ * (C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
106+ */
107+
108+$(document).ready(function(){
109+ /**
110+ * focus element if class="autofocus" and id="q"
111+ */
112+ $('#q.autofocus').focus();
113+
114+ /**
115+ * select full content on click if class="select-all-on-click"
116+ */
117+ $(".select-all-on-click").click(function () {
118+ $(this).select();
119+ });
120+
121+ /**
122+ * change text during btn-collapse click if possible
123+ */
124+ $('.btn-collapse').click(function() {
125+ var btnTextCollapsed = $(this).data('btn-text-collapsed');
126+ var btnTextNotCollapsed = $(this).data('btn-text-not-collapsed');
127+
128+ if(btnTextCollapsed !== '' && btnTextNotCollapsed !== '') {
129+ if($(this).hasClass('collapsed')) {
130+ new_html = $(this).html().replace(btnTextCollapsed, btnTextNotCollapsed);
131+ } else {
132+ new_html = $(this).html().replace(btnTextNotCollapsed, btnTextCollapsed);
133+ }
134+ $(this).html(new_html);
135+ }
136+ });
137+
138+ /**
139+ * change text during btn-toggle click if possible
140+ */
141+ $('.btn-toggle .btn').click(function() {
142+ var btnClass = 'btn-' + $(this).data('btn-class');
143+ var btnLabelDefault = $(this).data('btn-label-default');
144+ var btnLabelToggled = $(this).data('btn-label-toggled');
145+ if(btnLabelToggled !== '') {
146+ if($(this).hasClass('btn-default')) {
147+ new_html = $(this).html().replace(btnLabelDefault, btnLabelToggled);
148+ } else {
149+ new_html = $(this).html().replace(btnLabelToggled, btnLabelDefault);
150+ }
151+ $(this).html(new_html);
152+ }
153+ $(this).toggleClass(btnClass);
154+ $(this).toggleClass('btn-default');
155+ });
156+
157+ /**
158+ * change text during btn-toggle click if possible
159+ */
160+ $('.media-loader').click(function() {
161+ var target = $(this).data('target');
162+ var iframe_load = $(target + ' > iframe');
163+ var srctest = iframe_load.attr('src');
164+ if(srctest === undefined || srctest === false){
165+ iframe_load.attr('src', iframe_load.data('src'));
166+ }
167+ });
168+
169+ /**
170+ * Select or deselect every categories on double clic
171+ */
172+ $(".btn-sm").dblclick(function() {
173+ var btnClass = 'btn-' + $(this).data('btn-class'); // primary
174+ if($(this).hasClass('btn-default')) {
175+ $(".btn-sm > input").attr('checked', 'checked');
176+ $(".btn-sm > input").prop("checked", true);
177+ $(".btn-sm").addClass(btnClass);
178+ $(".btn-sm").addClass('active');
179+ $(".btn-sm").removeClass('btn-default');
180+ } else {
181+ $(".btn-sm > input").attr('checked', '');
182+ $(".btn-sm > input").removeAttr('checked');
183+ $(".btn-sm > input").checked = false;
184+ $(".btn-sm").removeClass(btnClass);
185+ $(".btn-sm").removeClass('active');
186+ $(".btn-sm").addClass('btn-default');
187+ }
188+ });
189+});
190+;/**
191+ * searx is free software: you can redistribute it and/or modify
192+ * it under the terms of the GNU Affero General Public License as published by
193+ * the Free Software Foundation, either version 3 of the License, or
194+ * (at your option) any later version.
195+ *
196+ * searx is distributed in the hope that it will be useful,
197+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
198+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
199+ * GNU Affero General Public License for more details.
200+ *
201+ * You should have received a copy of the GNU Affero General Public License
202+ * along with searx. If not, see < http://www.gnu.org/licenses/ >.
203+ *
204+ * (C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
205+ */
206+
207+$(document).ready(function(){
208+ $(".searx_overpass_request").on( "click", function( event ) {
209+ var overpass_url = "https://overpass-api.de/api/interpreter?data=";
210+ var query_start = overpass_url + "[out:json][timeout:25];(";
211+ var query_end = ");out meta;";
212+
213+ var osm_id = $(this).data('osm-id');
214+ var osm_type = $(this).data('osm-type');
215+ var result_table = $(this).data('result-table');
216+ var result_table_loadicon = "#" + $(this).data('result-table-loadicon');
217+
218+ // tags which can be ignored
219+ var osm_ignore_tags = [ "addr:city", "addr:country", "addr:housenumber", "addr:postcode", "addr:street" ];
220+
221+ if(osm_id && osm_type && result_table) {
222+ result_table = "#" + result_table;
223+ var query = null;
224+ switch(osm_type) {
225+ case 'node':
226+ query = query_start + "node(" + osm_id + ");" + query_end;
227+ break;
228+ case 'way':
229+ query = query_start + "way(" + osm_id + ");" + query_end;
230+ break;
231+ case 'relation':
232+ query = query_start + "relation(" + osm_id + ");" + query_end;
233+ break;
234+ default:
235+ break;
236+ }
237+ if(query) {
238+ //alert(query);
239+ var ajaxRequest = $.ajax( query )
240+ .done(function( html) {
241+ if(html && html.elements && html.elements[0]) {
242+ var element = html.elements[0];
243+ var newHtml = $(result_table).html();
244+ for (var row in element.tags) {
245+ if(element.tags.name === null || osm_ignore_tags.indexOf(row) == -1) {
246+ newHtml += "<tr><td>" + row + "</td><td>";
247+ switch(row) {
248+ case "phone":
249+ case "fax":
250+ newHtml += "<a href=\"tel:" + element.tags[row].replace(/ /g,'') + "\">" + element.tags[row] + "</a>";
251+ break;
252+ case "email":
253+ newHtml += "<a href=\"mailto:" + element.tags[row] + "\">" + element.tags[row] + "</a>";
254+ break;
255+ case "website":
256+ case "url":
257+ newHtml += "<a href=\"" + element.tags[row] + "\">" + element.tags[row] + "</a>";
258+ break;
259+ case "wikidata":
260+ newHtml += "<a href=\"https://www.wikidata.org/wiki/" + element.tags[row] + "\">" + element.tags[row] + "</a>";
261+ break;
262+ case "wikipedia":
263+ if(element.tags[row].indexOf(":") != -1) {
264+ newHtml += "<a href=\"https://" + element.tags[row].substring(0,element.tags[row].indexOf(":")) + ".wikipedia.org/wiki/" + element.tags[row].substring(element.tags[row].indexOf(":")+1) + "\">" + element.tags[row] + "</a>";
265+ break;
266+ }
267+ /* jshint ignore:start */
268+ default:
269+ /* jshint ignore:end */
270+ newHtml += element.tags[row];
271+ break;
272+ }
273+ newHtml += "</td></tr>";
274+ }
275+ }
276+ $(result_table).html(newHtml);
277+ $(result_table).removeClass('hidden');
278+ $(result_table_loadicon).addClass('hidden');
279+ }
280+ })
281+ .fail(function() {
282+ $(result_table_loadicon).html($(result_table_loadicon).html() + "<p class=\"text-muted\">could not load data!</p>");
283+ });
284+ }
285+ }
286+
287+ // this event occour only once per element
288+ $( this ).off( event );
289+ });
290+
291+ $(".searx_init_map").on( "click", function( event ) {
292+ var leaflet_target = $(this).data('leaflet-target');
293+ var map_lon = $(this).data('map-lon');
294+ var map_lat = $(this).data('map-lat');
295+ var map_zoom = $(this).data('map-zoom');
296+ var map_boundingbox = $(this).data('map-boundingbox');
297+ var map_geojson = $(this).data('map-geojson');
298+
299+ require(['leaflet-0.7.3.min'], function(leaflet) {
300+ if(map_boundingbox) {
301+ southWest = L.latLng(map_boundingbox[0], map_boundingbox[2]);
302+ northEast = L.latLng(map_boundingbox[1], map_boundingbox[3]);
303+ map_bounds = L.latLngBounds(southWest, northEast);
304+ }
305+
306+ // TODO hack
307+ // change default imagePath
308+ L.Icon.Default.imagePath = "./static/themes/oscar/img/map";
309+
310+ // init map
311+ var map = L.map(leaflet_target);
312+
313+ // create the tile layer with correct attribution
314+ var osmMapnikUrl='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
315+ var osmMapnikAttrib='Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';
316+ var osmMapnik = new L.TileLayer(osmMapnikUrl, {minZoom: 1, maxZoom: 19, attribution: osmMapnikAttrib});
317+
318+ var osmWikimediaUrl='https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png';
319+ var osmWikimediaAttrib = 'Wikimedia maps beta | Maps data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';
320+ var osmWikimedia = new L.TileLayer(osmWikimediaUrl, {minZoom: 1, maxZoom: 19, attribution: osmWikimediaAttrib});
321+
322+ // init map view
323+ if(map_bounds) {
324+ // TODO hack: https://github.com/Leaflet/Leaflet/issues/2021
325+ setTimeout(function () {
326+ map.fitBounds(map_bounds, {
327+ maxZoom:17
328+ });
329+ }, 0);
330+ } else if (map_lon && map_lat) {
331+ if(map_zoom)
332+ map.setView(new L.LatLng(map_lat, map_lon),map_zoom);
333+ else
334+ map.setView(new L.LatLng(map_lat, map_lon),8);
335+ }
336+
337+ map.addLayer(osmMapnik);
338+
339+ var baseLayers = {
340+ "OSM Mapnik": osmMapnik/*,
341+ "OSM Wikimedia": osmWikimedia*/
342+ };
343+
344+ L.control.layers(baseLayers).addTo(map);
345+
346+
347+ if(map_geojson)
348+ L.geoJson(map_geojson).addTo(map);
349+ /*else if(map_bounds)
350+ L.rectangle(map_bounds, {color: "#ff7800", weight: 3, fill:false}).addTo(map);*/
351+ });
352+
353+ // this event occour only once per element
354+ $( this ).off( event );
355+ });
356+});
searx/static/themes/oscar/js/searx.min.js+2−2
@@ -1,2 +1,2 @@
1−/*! oscar/searx.min.js | 06-10-2017 | https://github.com/asciimoo/searx */
1+/*! oscar/searx.min.js | 06-08-2019 | https://github.com/asciimoo/searx */
2−requirejs.config({baseUrl:"./static/themes/oscar/js",paths:{app:"../app"}}),searx.autocompleter&&(searx.searchResults=new Bloodhound({datumTokenizer:Bloodhound.tokenizers.obj.whitespace("value"),queryTokenizer:Bloodhound.tokenizers.whitespace,remote:"./autocompleter?q=%QUERY"}),searx.searchResults.initialize()),$(document).ready(function(){searx.autocompleter&&$("#q").typeahead(null,{name:"search-results",displayKey:function(a){return a},source:searx.searchResults.ttAdapter()})}),$(document).ready(function(){$("#q.autofocus").focus(),$(".select-all-on-click").click(function(){$(this).select()}),$(".btn-collapse").click(function(){var a=$(this).data("btn-text-collapsed"),b=$(this).data("btn-text-not-collapsed");""!==a&&""!==b&&($(this).hasClass("collapsed")?new_html=$(this).html().replace(a,b):new_html=$(this).html().replace(b,a),$(this).html(new_html))}),$(".btn-toggle .btn").click(function(){var a="btn-"+$(this).data("btn-class"),b=$(this).data("btn-label-default"),c=$(this).data("btn-label-toggled");""!==c&&($(this).hasClass("btn-default")?new_html=$(this).html().replace(b,c):new_html=$(this).html().replace(c,b),$(this).html(new_html)),$(this).toggleClass(a),$(this).toggleClass("btn-default")}),$(".media-loader").click(function(){var a=$(this).data("target"),b=$(a+" > iframe"),c=b.attr("src");void 0!==c&&c!==!1||b.attr("src",b.data("src"))}),$(".btn-sm").dblclick(function(){var a="btn-"+$(this).data("btn-class");$(this).hasClass("btn-default")?($(".btn-sm > input").attr("checked","checked"),$(".btn-sm > input").prop("checked",!0),$(".btn-sm").addClass(a),$(".btn-sm").addClass("active"),$(".btn-sm").removeClass("btn-default")):($(".btn-sm > input").attr("checked",""),$(".btn-sm > input").removeAttr("checked"),$(".btn-sm > input").checked=!1,$(".btn-sm").removeClass(a),$(".btn-sm").removeClass("active"),$(".btn-sm").addClass("btn-default"))})}),$(document).ready(function(){$(".searx_overpass_request").on("click",function(a){var b="https://overpass-api.de/api/interpreter?data=",c=b+"[out:json][timeout:25];(",d=");out meta;",e=$(this).data("osm-id"),f=$(this).data("osm-type"),g=$(this).data("result-table"),h="#"+$(this).data("result-table-loadicon"),i=["addr:city","addr:country","addr:housenumber","addr:postcode","addr:street"];if(e&&f&&g){g="#"+g;var j=null;switch(f){case"node":j=c+"node("+e+");"+d;break;case"way":j=c+"way("+e+");"+d;break;case"relation":j=c+"relation("+e+");"+d}if(j){$.ajax(j).done(function(a){if(a&&a.elements&&a.elements[0]){var b=a.elements[0],c=$(g).html();for(var d in b.tags)if(null===b.tags.name||i.indexOf(d)==-1){switch(c+="<tr><td>"+d+"</td><td>",d){case"phone":case"fax":c+='<a href="tel:'+b.tags[d].replace(/ /g,"")+'">'+b.tags[d]+"</a>";break;case"email":c+='<a href="mailto:'+b.tags[d]+'">'+b.tags[d]+"</a>";break;case"website":case"url":c+='<a href="'+b.tags[d]+'">'+b.tags[d]+"</a>";break;case"wikidata":c+='<a href="https://www.wikidata.org/wiki/'+b.tags[d]+'">'+b.tags[d]+"</a>";break;case"wikipedia":if(b.tags[d].indexOf(":")!=-1){c+='<a href="https://'+b.tags[d].substring(0,b.tags[d].indexOf(":"))+".wikipedia.org/wiki/"+b.tags[d].substring(b.tags[d].indexOf(":")+1)+'">'+b.tags[d]+"</a>";break}default:c+=b.tags[d]}c+="</td></tr>"}$(g).html(c),$(g).removeClass("hidden"),$(h).addClass("hidden")}}).fail(function(){$(h).html($(h).html()+'<p class="text-muted">could not load data!</p>')})}}$(this).off(a)}),$(".searx_init_map").on("click",function(a){var b=$(this).data("leaflet-target"),c=$(this).data("map-lon"),d=$(this).data("map-lat"),e=$(this).data("map-zoom"),f=$(this).data("map-boundingbox"),g=$(this).data("map-geojson");require(["leaflet-0.7.3.min"],function(a){f&&(southWest=L.latLng(f[0],f[2]),northEast=L.latLng(f[1],f[3]),map_bounds=L.latLngBounds(southWest,northEast)),L.Icon.Default.imagePath="./static/themes/oscar/img/map";var h=L.map(b),i="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",j='Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors',k=new L.TileLayer(i,{minZoom:1,maxZoom:19,attribution:j}),l="https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png",m='Wikimedia maps beta | Maps data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';new L.TileLayer(l,{minZoom:1,maxZoom:19,attribution:m});map_bounds?setTimeout(function(){h.fitBounds(map_bounds,{maxZoom:17})},0):c&&d&&(e?h.setView(new L.LatLng(d,c),e):h.setView(new L.LatLng(d,c),8)),h.addLayer(k);var n={"OSM Mapnik":k};L.control.layers(n).addTo(h),g&&L.geoJson(g).addTo(h)}),$(this).off(a)})});
2+requirejs.config({baseUrl:"./static/themes/oscar/js",paths:{app:"../app"}}),window.searx=function(a){"use strict";var b=a.currentScript||function(){var b=a.getElementsByTagName("script");return b[b.length-1]}();return{autocompleter:"true"===b.getAttribute("data-autocompleter"),method:b.getAttribute("data-method")}}(document),searx.autocompleter&&(searx.searchResults=new Bloodhound({datumTokenizer:Bloodhound.tokenizers.obj.whitespace("value"),queryTokenizer:Bloodhound.tokenizers.whitespace,remote:"./autocompleter?q=%QUERY"}),searx.searchResults.initialize()),$(document).ready(function(){searx.autocompleter&&$("#q").typeahead(null,{name:"search-results",displayKey:function(a){return a},source:searx.searchResults.ttAdapter()})}),$(document).ready(function(){$("#q.autofocus").focus(),$(".select-all-on-click").click(function(){$(this).select()}),$(".btn-collapse").click(function(){var a=$(this).data("btn-text-collapsed"),b=$(this).data("btn-text-not-collapsed");""!==a&&""!==b&&($(this).hasClass("collapsed")?new_html=$(this).html().replace(a,b):new_html=$(this).html().replace(b,a),$(this).html(new_html))}),$(".btn-toggle .btn").click(function(){var a="btn-"+$(this).data("btn-class"),b=$(this).data("btn-label-default"),c=$(this).data("btn-label-toggled");""!==c&&($(this).hasClass("btn-default")?new_html=$(this).html().replace(b,c):new_html=$(this).html().replace(c,b),$(this).html(new_html)),$(this).toggleClass(a),$(this).toggleClass("btn-default")}),$(".media-loader").click(function(){var a=$(this).data("target"),b=$(a+" > iframe"),c=b.attr("src");void 0!==c&&!1!==c||b.attr("src",b.data("src"))}),$(".btn-sm").dblclick(function(){var a="btn-"+$(this).data("btn-class");$(this).hasClass("btn-default")?($(".btn-sm > input").attr("checked","checked"),$(".btn-sm > input").prop("checked",!0),$(".btn-sm").addClass(a),$(".btn-sm").addClass("active"),$(".btn-sm").removeClass("btn-default")):($(".btn-sm > input").attr("checked",""),$(".btn-sm > input").removeAttr("checked"),$(".btn-sm > input").checked=!1,$(".btn-sm").removeClass(a),$(".btn-sm").removeClass("active"),$(".btn-sm").addClass("btn-default"))})}),$(document).ready(function(){$(".searx_overpass_request").on("click",function(a){var b="https://overpass-api.de/api/interpreter?data=",c=b+"[out:json][timeout:25];(",d=");out meta;",e=$(this).data("osm-id"),f=$(this).data("osm-type"),g=$(this).data("result-table"),h="#"+$(this).data("result-table-loadicon"),i=["addr:city","addr:country","addr:housenumber","addr:postcode","addr:street"];if(e&&f&&g){g="#"+g;var j=null;switch(f){case"node":j=c+"node("+e+");"+d;break;case"way":j=c+"way("+e+");"+d;break;case"relation":j=c+"relation("+e+");"+d}if(j){$.ajax(j).done(function(a){if(a&&a.elements&&a.elements[0]){var b=a.elements[0],c=$(g).html();for(var d in b.tags)if(null===b.tags.name||-1==i.indexOf(d)){switch(c+="<tr><td>"+d+"</td><td>",d){case"phone":case"fax":c+='<a href="tel:'+b.tags[d].replace(/ /g,"")+'">'+b.tags[d]+"</a>";break;case"email":c+='<a href="mailto:'+b.tags[d]+'">'+b.tags[d]+"</a>";break;case"website":case"url":c+='<a href="'+b.tags[d]+'">'+b.tags[d]+"</a>";break;case"wikidata":c+='<a href="https://www.wikidata.org/wiki/'+b.tags[d]+'">'+b.tags[d]+"</a>";break;case"wikipedia":if(-1!=b.tags[d].indexOf(":")){c+='<a href="https://'+b.tags[d].substring(0,b.tags[d].indexOf(":"))+".wikipedia.org/wiki/"+b.tags[d].substring(b.tags[d].indexOf(":")+1)+'">'+b.tags[d]+"</a>";break}default:c+=b.tags[d]}c+="</td></tr>"}$(g).html(c),$(g).removeClass("hidden"),$(h).addClass("hidden")}}).fail(function(){$(h).html($(h).html()+'<p class="text-muted">could not load data!</p>')})}}$(this).off(a)}),$(".searx_init_map").on("click",function(a){var b=$(this).data("leaflet-target"),c=$(this).data("map-lon"),d=$(this).data("map-lat"),e=$(this).data("map-zoom"),f=$(this).data("map-boundingbox"),g=$(this).data("map-geojson");require(["leaflet-0.7.3.min"],function(a){f&&(southWest=L.latLng(f[0],f[2]),northEast=L.latLng(f[1],f[3]),map_bounds=L.latLngBounds(southWest,northEast)),L.Icon.Default.imagePath="./static/themes/oscar/img/map";var h=L.map(b),i="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",j='Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors',k=new L.TileLayer(i,{minZoom:1,maxZoom:19,attribution:j}),l="https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png",m='Wikimedia maps beta | Maps data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';new L.TileLayer(l,{minZoom:1,maxZoom:19,attribution:m});map_bounds?setTimeout(function(){h.fitBounds(map_bounds,{maxZoom:17})},0):c&&d&&(e?h.setView(new L.LatLng(d,c),e):h.setView(new L.LatLng(d,c),8)),h.addLayer(k);var n={"OSM Mapnik":k};L.control.layers(n).addTo(h),g&&L.geoJson(g).addTo(h)}),$(this).off(a)})});
searx/static/themes/oscar/js/searx_src/00_requirejs_config.js+23−23
@@ -1,23 +1,23 @@
1−/**
1+/**
2− * searx is free software: you can redistribute it and/or modify
2+ * searx is free software: you can redistribute it and/or modify
3− * it under the terms of the GNU Affero General Public License as published by
3+ * it under the terms of the GNU Affero General Public License as published by
4− * the Free Software Foundation, either version 3 of the License, or
4+ * the Free Software Foundation, either version 3 of the License, or
5− * (at your option) any later version.
5+ * (at your option) any later version.
6− *
6+ *
7− * searx is distributed in the hope that it will be useful,
7+ * searx is distributed in the hope that it will be useful,
8− * but WITHOUT ANY WARRANTY; without even the implied warranty of
8+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
9− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10− * GNU Affero General Public License for more details.
10+ * GNU Affero General Public License for more details.
11− *
11+ *
12− * You should have received a copy of the GNU Affero General Public License
12+ * You should have received a copy of the GNU Affero General Public License
13− * along with searx. If not, see < http://www.gnu.org/licenses/ >.
13+ * along with searx. If not, see < http://www.gnu.org/licenses/ >.
14− *
14+ *
15− * (C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
15+ * (C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
16− */
16+ */
17−
17+
18−requirejs.config({
18+requirejs.config({
19− baseUrl: './static/themes/oscar/js',
19+ baseUrl: './static/themes/oscar/js',
20− paths: {
20+ paths: {
21− app: '../app'
21+ app: '../app'
22− }
22+ }
23−});
23+});
searx/static/themes/oscar/js/searx_src/01_init.jsnew file+30
@@ -0,0 +1,30 @@
1+/**
2+ * searx is free software: you can redistribute it and/or modify
3+ * it under the terms of the GNU Affero General Public License as published by
4+ * the Free Software Foundation, either version 3 of the License, or
5+ * (at your option) any later version.
6+ *
7+ * searx is distributed in the hope that it will be useful,
8+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
9+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+ * GNU Affero General Public License for more details.
11+ *
12+ * You should have received a copy of the GNU Affero General Public License
13+ * along with searx. If not, see < http://www.gnu.org/licenses/ >.
14+ *
15+ * (C) 2019 by Alexandre Flament
16+ */
17+window.searx = (function(d) {
18+ 'use strict';
19+
20+ // add data- properties
21+ var script = d.currentScript || (function() {
22+ var scripts = d.getElementsByTagName('script');
23+ return scripts[scripts.length - 1];
24+ })();
25+
26+ return {
27+ autocompleter: script.getAttribute('data-autocompleter') === 'true',
28+ method: script.getAttribute('data-method')
29+ };
30+})(document);
searx/static/themes/oscar/js/searx_src/autocompleter.js+37−37
@@ -1,37 +1,37 @@
1−/**
1+/**
2− * searx is free software: you can redistribute it and/or modify
2+ * searx is free software: you can redistribute it and/or modify
3− * it under the terms of the GNU Affero General Public License as published by
3+ * it under the terms of the GNU Affero General Public License as published by
4− * the Free Software Foundation, either version 3 of the License, or
4+ * the Free Software Foundation, either version 3 of the License, or
5− * (at your option) any later version.
5+ * (at your option) any later version.
6− *
6+ *
7− * searx is distributed in the hope that it will be useful,
7+ * searx is distributed in the hope that it will be useful,
8− * but WITHOUT ANY WARRANTY; without even the implied warranty of
8+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
9− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10− * GNU Affero General Public License for more details.
10+ * GNU Affero General Public License for more details.
11− *
11+ *
12− * You should have received a copy of the GNU Affero General Public License
12+ * You should have received a copy of the GNU Affero General Public License
13− * along with searx. If not, see < http://www.gnu.org/licenses/ >.
13+ * along with searx. If not, see < http://www.gnu.org/licenses/ >.
14− *
14+ *
15− * (C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
15+ * (C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
16− */
16+ */
17−
17+
18−if(searx.autocompleter) {
18+if(searx.autocompleter) {
19− searx.searchResults = new Bloodhound({
19+ searx.searchResults = new Bloodhound({
20− datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
20+ datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
21− queryTokenizer: Bloodhound.tokenizers.whitespace,
21+ queryTokenizer: Bloodhound.tokenizers.whitespace,
22− remote: './autocompleter?q=%QUERY'
22+ remote: './autocompleter?q=%QUERY'
23− });
23+ });
24− searx.searchResults.initialize();
24+ searx.searchResults.initialize();
25−}
25+}
26−
26+
27−$(document).ready(function(){
27+$(document).ready(function(){
28− if(searx.autocompleter) {
28+ if(searx.autocompleter) {
29− $('#q').typeahead(null, {
29+ $('#q').typeahead(null, {
30− name: 'search-results',
30+ name: 'search-results',
31− displayKey: function(result) {
31+ displayKey: function(result) {
32− return result;
32+ return result;
33− },
33+ },
34− source: searx.searchResults.ttAdapter()
34+ source: searx.searchResults.ttAdapter()
35− });
35+ });
36− }
36+ }
37−});
37+});
searx/static/themes/oscar/js/searx_src/element_modifiers.js+99−99
@@ -1,99 +1,99 @@
1−/**
1+/**
2− * searx is free software: you can redistribute it and/or modify
2+ * searx is free software: you can redistribute it and/or modify
3− * it under the terms of the GNU Affero General Public License as published by
3+ * it under the terms of the GNU Affero General Public License as published by
4− * the Free Software Foundation, either version 3 of the License, or
4+ * the Free Software Foundation, either version 3 of the License, or
5− * (at your option) any later version.
5+ * (at your option) any later version.
6− *
6+ *
7− * searx is distributed in the hope that it will be useful,
7+ * searx is distributed in the hope that it will be useful,
8− * but WITHOUT ANY WARRANTY; without even the implied warranty of
8+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
9− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10− * GNU Affero General Public License for more details.
10+ * GNU Affero General Public License for more details.
11− *
11+ *
12− * You should have received a copy of the GNU Affero General Public License
12+ * You should have received a copy of the GNU Affero General Public License
13− * along with searx. If not, see < http://www.gnu.org/licenses/ >.
13+ * along with searx. If not, see < http://www.gnu.org/licenses/ >.
14− *
14+ *
15− * (C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
15+ * (C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
16− */
16+ */
17−
17+
18−$(document).ready(function(){
18+$(document).ready(function(){
19− /**
19+ /**
20− * focus element if class="autofocus" and id="q"
20+ * focus element if class="autofocus" and id="q"
21− */
21+ */
22− $('#q.autofocus').focus();
22+ $('#q.autofocus').focus();
23−
23+
24− /**
24+ /**
25− * select full content on click if class="select-all-on-click"
25+ * select full content on click if class="select-all-on-click"
26− */
26+ */
27− $(".select-all-on-click").click(function () {
27+ $(".select-all-on-click").click(function () {
28− $(this).select();
28+ $(this).select();
29− });
29+ });
30−
30+
31− /**
31+ /**
32− * change text during btn-collapse click if possible
32+ * change text during btn-collapse click if possible
33− */
33+ */
34− $('.btn-collapse').click(function() {
34+ $('.btn-collapse').click(function() {
35− var btnTextCollapsed = $(this).data('btn-text-collapsed');
35+ var btnTextCollapsed = $(this).data('btn-text-collapsed');
36− var btnTextNotCollapsed = $(this).data('btn-text-not-collapsed');
36+ var btnTextNotCollapsed = $(this).data('btn-text-not-collapsed');
37−
37+
38− if(btnTextCollapsed !== '' && btnTextNotCollapsed !== '') {
38+ if(btnTextCollapsed !== '' && btnTextNotCollapsed !== '') {
39− if($(this).hasClass('collapsed')) {
39+ if($(this).hasClass('collapsed')) {
40− new_html = $(this).html().replace(btnTextCollapsed, btnTextNotCollapsed);
40+ new_html = $(this).html().replace(btnTextCollapsed, btnTextNotCollapsed);
41− } else {
41+ } else {
42− new_html = $(this).html().replace(btnTextNotCollapsed, btnTextCollapsed);
42+ new_html = $(this).html().replace(btnTextNotCollapsed, btnTextCollapsed);
43− }
43+ }
44− $(this).html(new_html);
44+ $(this).html(new_html);
45− }
45+ }
46− });
46+ });
47−
47+
48− /**
48+ /**
49− * change text during btn-toggle click if possible
49+ * change text during btn-toggle click if possible
50− */
50+ */
51− $('.btn-toggle .btn').click(function() {
51+ $('.btn-toggle .btn').click(function() {
52− var btnClass = 'btn-' + $(this).data('btn-class');
52+ var btnClass = 'btn-' + $(this).data('btn-class');
53− var btnLabelDefault = $(this).data('btn-label-default');
53+ var btnLabelDefault = $(this).data('btn-label-default');
54− var btnLabelToggled = $(this).data('btn-label-toggled');
54+ var btnLabelToggled = $(this).data('btn-label-toggled');
55− if(btnLabelToggled !== '') {
55+ if(btnLabelToggled !== '') {
56− if($(this).hasClass('btn-default')) {
56+ if($(this).hasClass('btn-default')) {
57− new_html = $(this).html().replace(btnLabelDefault, btnLabelToggled);
57+ new_html = $(this).html().replace(btnLabelDefault, btnLabelToggled);
58− } else {
58+ } else {
59− new_html = $(this).html().replace(btnLabelToggled, btnLabelDefault);
59+ new_html = $(this).html().replace(btnLabelToggled, btnLabelDefault);
60− }
60+ }
61− $(this).html(new_html);
61+ $(this).html(new_html);
62− }
62+ }
63− $(this).toggleClass(btnClass);
63+ $(this).toggleClass(btnClass);
64− $(this).toggleClass('btn-default');
64+ $(this).toggleClass('btn-default');
65− });
65+ });
66−
66+
67− /**
67+ /**
68− * change text during btn-toggle click if possible
68+ * change text during btn-toggle click if possible
69− */
69+ */
70− $('.media-loader').click(function() {
70+ $('.media-loader').click(function() {
71− var target = $(this).data('target');
71+ var target = $(this).data('target');
72− var iframe_load = $(target + ' > iframe');
72+ var iframe_load = $(target + ' > iframe');
73− var srctest = iframe_load.attr('src');
73+ var srctest = iframe_load.attr('src');
74− if(srctest === undefined || srctest === false){
74+ if(srctest === undefined || srctest === false){
75− iframe_load.attr('src', iframe_load.data('src'));
75+ iframe_load.attr('src', iframe_load.data('src'));
76− }
76+ }
77− });
77+ });
78−
78+
79− /**
79+ /**
80− * Select or deselect every categories on double clic
80+ * Select or deselect every categories on double clic
81− */
81+ */
82− $(".btn-sm").dblclick(function() {
82+ $(".btn-sm").dblclick(function() {
83− var btnClass = 'btn-' + $(this).data('btn-class'); // primary
83+ var btnClass = 'btn-' + $(this).data('btn-class'); // primary
84− if($(this).hasClass('btn-default')) {
84+ if($(this).hasClass('btn-default')) {
85− $(".btn-sm > input").attr('checked', 'checked');
85+ $(".btn-sm > input").attr('checked', 'checked');
86− $(".btn-sm > input").prop("checked", true);
86+ $(".btn-sm > input").prop("checked", true);
87− $(".btn-sm").addClass(btnClass);
87+ $(".btn-sm").addClass(btnClass);
88− $(".btn-sm").addClass('active');
88+ $(".btn-sm").addClass('active');
89− $(".btn-sm").removeClass('btn-default');
89+ $(".btn-sm").removeClass('btn-default');
90− } else {
90+ } else {
91− $(".btn-sm > input").attr('checked', '');
91+ $(".btn-sm > input").attr('checked', '');
92− $(".btn-sm > input").removeAttr('checked');
92+ $(".btn-sm > input").removeAttr('checked');
93− $(".btn-sm > input").checked = false;
93+ $(".btn-sm > input").checked = false;
94− $(".btn-sm").removeClass(btnClass);
94+ $(".btn-sm").removeClass(btnClass);
95− $(".btn-sm").removeClass('active');
95+ $(".btn-sm").removeClass('active');
96− $(".btn-sm").addClass('btn-default');
96+ $(".btn-sm").addClass('btn-default');
97− }
97+ }
98− });
98+ });
99−});
99+});
searx/static/themes/oscar/js/searx_src/leaflet_map.js+167−167
@@ -1,167 +1,167 @@
1−/**
1+/**
2− * searx is free software: you can redistribute it and/or modify
2+ * searx is free software: you can redistribute it and/or modify
3− * it under the terms of the GNU Affero General Public License as published by
3+ * it under the terms of the GNU Affero General Public License as published by
4− * the Free Software Foundation, either version 3 of the License, or
4+ * the Free Software Foundation, either version 3 of the License, or
5− * (at your option) any later version.
5+ * (at your option) any later version.
6− *
6+ *
7− * searx is distributed in the hope that it will be useful,
7+ * searx is distributed in the hope that it will be useful,
8− * but WITHOUT ANY WARRANTY; without even the implied warranty of
8+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
9− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10− * GNU Affero General Public License for more details.
10+ * GNU Affero General Public License for more details.
11− *
11+ *
12− * You should have received a copy of the GNU Affero General Public License
12+ * You should have received a copy of the GNU Affero General Public License
13− * along with searx. If not, see < http://www.gnu.org/licenses/ >.
13+ * along with searx. If not, see < http://www.gnu.org/licenses/ >.
14− *
14+ *
15− * (C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
15+ * (C) 2014 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
16− */
16+ */
17−
17+
18−$(document).ready(function(){
18+$(document).ready(function(){
19− $(".searx_overpass_request").on( "click", function( event ) {
19+ $(".searx_overpass_request").on( "click", function( event ) {
20− var overpass_url = "https://overpass-api.de/api/interpreter?data=";
20+ var overpass_url = "https://overpass-api.de/api/interpreter?data=";
21− var query_start = overpass_url + "[out:json][timeout:25];(";
21+ var query_start = overpass_url + "[out:json][timeout:25];(";
22− var query_end = ");out meta;";
22+ var query_end = ");out meta;";
23−
23+
24− var osm_id = $(this).data('osm-id');
24+ var osm_id = $(this).data('osm-id');
25− var osm_type = $(this).data('osm-type');
25+ var osm_type = $(this).data('osm-type');
26− var result_table = $(this).data('result-table');
26+ var result_table = $(this).data('result-table');
27− var result_table_loadicon = "#" + $(this).data('result-table-loadicon');
27+ var result_table_loadicon = "#" + $(this).data('result-table-loadicon');
28−
28+
29− // tags which can be ignored
29+ // tags which can be ignored
30− var osm_ignore_tags = [ "addr:city", "addr:country", "addr:housenumber", "addr:postcode", "addr:street" ];
30+ var osm_ignore_tags = [ "addr:city", "addr:country", "addr:housenumber", "addr:postcode", "addr:street" ];
31−
31+
32− if(osm_id && osm_type && result_table) {
32+ if(osm_id && osm_type && result_table) {
33− result_table = "#" + result_table;
33+ result_table = "#" + result_table;
34− var query = null;
34+ var query = null;
35− switch(osm_type) {
35+ switch(osm_type) {
36− case 'node':
36+ case 'node':
37− query = query_start + "node(" + osm_id + ");" + query_end;
37+ query = query_start + "node(" + osm_id + ");" + query_end;
38− break;
38+ break;
39− case 'way':
39+ case 'way':
40− query = query_start + "way(" + osm_id + ");" + query_end;
40+ query = query_start + "way(" + osm_id + ");" + query_end;
41− break;
41+ break;
42− case 'relation':
42+ case 'relation':
43− query = query_start + "relation(" + osm_id + ");" + query_end;
43+ query = query_start + "relation(" + osm_id + ");" + query_end;
44− break;
44+ break;
45− default:
45+ default:
46− break;
46+ break;
47− }
47+ }
48− if(query) {
48+ if(query) {
49− //alert(query);
49+ //alert(query);
50− var ajaxRequest = $.ajax( query )
50+ var ajaxRequest = $.ajax( query )
51− .done(function( html) {
51+ .done(function( html) {
52− if(html && html.elements && html.elements[0]) {
52+ if(html && html.elements && html.elements[0]) {
53− var element = html.elements[0];
53+ var element = html.elements[0];
54− var newHtml = $(result_table).html();
54+ var newHtml = $(result_table).html();
55− for (var row in element.tags) {
55+ for (var row in element.tags) {
56− if(element.tags.name === null || osm_ignore_tags.indexOf(row) == -1) {
56+ if(element.tags.name === null || osm_ignore_tags.indexOf(row) == -1) {
57− newHtml += "<tr><td>" + row + "</td><td>";
57+ newHtml += "<tr><td>" + row + "</td><td>";
58− switch(row) {
58+ switch(row) {
59− case "phone":
59+ case "phone":
60− case "fax":
60+ case "fax":
61− newHtml += "<a href=\"tel:" + element.tags[row].replace(/ /g,'') + "\">" + element.tags[row] + "</a>";
61+ newHtml += "<a href=\"tel:" + element.tags[row].replace(/ /g,'') + "\">" + element.tags[row] + "</a>";
62− break;
62+ break;
63− case "email":
63+ case "email":
64− newHtml += "<a href=\"mailto:" + element.tags[row] + "\">" + element.tags[row] + "</a>";
64+ newHtml += "<a href=\"mailto:" + element.tags[row] + "\">" + element.tags[row] + "</a>";
65− break;
65+ break;
66− case "website":
66+ case "website":
67− case "url":
67+ case "url":
68− newHtml += "<a href=\"" + element.tags[row] + "\">" + element.tags[row] + "</a>";
68+ newHtml += "<a href=\"" + element.tags[row] + "\">" + element.tags[row] + "</a>";
69− break;
69+ break;
70− case "wikidata":
70+ case "wikidata":
71− newHtml += "<a href=\"https://www.wikidata.org/wiki/" + element.tags[row] + "\">" + element.tags[row] + "</a>";
71+ newHtml += "<a href=\"https://www.wikidata.org/wiki/" + element.tags[row] + "\">" + element.tags[row] + "</a>";
72− break;
72+ break;
73− case "wikipedia":
73+ case "wikipedia":
74− if(element.tags[row].indexOf(":") != -1) {
74+ if(element.tags[row].indexOf(":") != -1) {
75− newHtml += "<a href=\"https://" + element.tags[row].substring(0,element.tags[row].indexOf(":")) + ".wikipedia.org/wiki/" + element.tags[row].substring(element.tags[row].indexOf(":")+1) + "\">" + element.tags[row] + "</a>";
75+ newHtml += "<a href=\"https://" + element.tags[row].substring(0,element.tags[row].indexOf(":")) + ".wikipedia.org/wiki/" + element.tags[row].substring(element.tags[row].indexOf(":")+1) + "\">" + element.tags[row] + "</a>";
76− break;
76+ break;
77− }
77+ }
78− /* jshint ignore:start */
78+ /* jshint ignore:start */
79− default:
79+ default:
80− /* jshint ignore:end */
80+ /* jshint ignore:end */
81− newHtml += element.tags[row];
81+ newHtml += element.tags[row];
82− break;
82+ break;
83− }
83+ }
84− newHtml += "</td></tr>";
84+ newHtml += "</td></tr>";
85− }
85+ }
86− }
86+ }
87− $(result_table).html(newHtml);
87+ $(result_table).html(newHtml);
88− $(result_table).removeClass('hidden');
88+ $(result_table).removeClass('hidden');
89− $(result_table_loadicon).addClass('hidden');
89+ $(result_table_loadicon).addClass('hidden');
90− }
90+ }
91− })
91+ })
92− .fail(function() {
92+ .fail(function() {
93− $(result_table_loadicon).html($(result_table_loadicon).html() + "<p class=\"text-muted\">could not load data!</p>");
93+ $(result_table_loadicon).html($(result_table_loadicon).html() + "<p class=\"text-muted\">could not load data!</p>");
94− });
94+ });
95− }
95+ }
96− }
96+ }
97−
97+
98− // this event occour only once per element
98+ // this event occour only once per element
99− $( this ).off( event );
99+ $( this ).off( event );
100− });
100+ });
101−
101+
102− $(".searx_init_map").on( "click", function( event ) {
102+ $(".searx_init_map").on( "click", function( event ) {
103− var leaflet_target = $(this).data('leaflet-target');
103+ var leaflet_target = $(this).data('leaflet-target');
104− var map_lon = $(this).data('map-lon');
104+ var map_lon = $(this).data('map-lon');
105− var map_lat = $(this).data('map-lat');
105+ var map_lat = $(this).data('map-lat');
106− var map_zoom = $(this).data('map-zoom');
106+ var map_zoom = $(this).data('map-zoom');
107− var map_boundingbox = $(this).data('map-boundingbox');
107+ var map_boundingbox = $(this).data('map-boundingbox');
108− var map_geojson = $(this).data('map-geojson');
108+ var map_geojson = $(this).data('map-geojson');
109−
109+
110− require(['leaflet-0.7.3.min'], function(leaflet) {
110+ require(['leaflet-0.7.3.min'], function(leaflet) {
111− if(map_boundingbox) {
111+ if(map_boundingbox) {
112− southWest = L.latLng(map_boundingbox[0], map_boundingbox[2]);
112+ southWest = L.latLng(map_boundingbox[0], map_boundingbox[2]);
113− northEast = L.latLng(map_boundingbox[1], map_boundingbox[3]);
113+ northEast = L.latLng(map_boundingbox[1], map_boundingbox[3]);
114− map_bounds = L.latLngBounds(southWest, northEast);
114+ map_bounds = L.latLngBounds(southWest, northEast);
115− }
115+ }
116−
116+
117− // TODO hack
117+ // TODO hack
118− // change default imagePath
118+ // change default imagePath
119− L.Icon.Default.imagePath = "./static/themes/oscar/img/map";
119+ L.Icon.Default.imagePath = "./static/themes/oscar/img/map";
120−
120+
121− // init map
121+ // init map
122− var map = L.map(leaflet_target);
122+ var map = L.map(leaflet_target);
123−
123+
124− // create the tile layer with correct attribution
124+ // create the tile layer with correct attribution
125− var osmMapnikUrl='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
125+ var osmMapnikUrl='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
126− var osmMapnikAttrib='Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';
126+ var osmMapnikAttrib='Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';
127− var osmMapnik = new L.TileLayer(osmMapnikUrl, {minZoom: 1, maxZoom: 19, attribution: osmMapnikAttrib});
127+ var osmMapnik = new L.TileLayer(osmMapnikUrl, {minZoom: 1, maxZoom: 19, attribution: osmMapnikAttrib});
128−
128+
129− var osmWikimediaUrl='https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png';
129+ var osmWikimediaUrl='https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png';
130− var osmWikimediaAttrib = 'Wikimedia maps beta | Maps data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';
130+ var osmWikimediaAttrib = 'Wikimedia maps beta | Maps data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';
131− var osmWikimedia = new L.TileLayer(osmWikimediaUrl, {minZoom: 1, maxZoom: 19, attribution: osmWikimediaAttrib});
131+ var osmWikimedia = new L.TileLayer(osmWikimediaUrl, {minZoom: 1, maxZoom: 19, attribution: osmWikimediaAttrib});
132−
132+
133− // init map view
133+ // init map view
134− if(map_bounds) {
134+ if(map_bounds) {
135− // TODO hack: https://github.com/Leaflet/Leaflet/issues/2021
135+ // TODO hack: https://github.com/Leaflet/Leaflet/issues/2021
136− setTimeout(function () {
136+ setTimeout(function () {
137− map.fitBounds(map_bounds, {
137+ map.fitBounds(map_bounds, {
138− maxZoom:17
138+ maxZoom:17
139− });
139+ });
140− }, 0);
140+ }, 0);
141− } else if (map_lon && map_lat) {
141+ } else if (map_lon && map_lat) {
142− if(map_zoom)
142+ if(map_zoom)
143− map.setView(new L.LatLng(map_lat, map_lon),map_zoom);
143+ map.setView(new L.LatLng(map_lat, map_lon),map_zoom);
144− else
144+ else
145− map.setView(new L.LatLng(map_lat, map_lon),8);
145+ map.setView(new L.LatLng(map_lat, map_lon),8);
146− }
146+ }
147−
147+
148− map.addLayer(osmMapnik);
148+ map.addLayer(osmMapnik);
149−
149+
150− var baseLayers = {
150+ var baseLayers = {
151− "OSM Mapnik": osmMapnik/*,
151+ "OSM Mapnik": osmMapnik/*,
152− "OSM Wikimedia": osmWikimedia*/
152+ "OSM Wikimedia": osmWikimedia*/
153− };
153+ };
154−
154+
155− L.control.layers(baseLayers).addTo(map);
155+ L.control.layers(baseLayers).addTo(map);
156−
156+
157−
157+
158− if(map_geojson)
158+ if(map_geojson)
159− L.geoJson(map_geojson).addTo(map);
159+ L.geoJson(map_geojson).addTo(map);
160− /*else if(map_bounds)
160+ /*else if(map_bounds)
161− L.rectangle(map_bounds, {color: "#ff7800", weight: 3, fill:false}).addTo(map);*/
161+ L.rectangle(map_bounds, {color: "#ff7800", weight: 3, fill:false}).addTo(map);*/
162− });
162+ });
163−
163+
164− // this event occour only once per element
164+ // this event occour only once per element
165− $( this ).off( event );
165+ $( this ).off( event );
166− });
166+ });
167−});
167+});
searx/static/themes/oscar/less/logicodev-dark/oscar.less+3−3
@@ -59,7 +59,7 @@ ul.nav li a {
59 border-bottom: 4px solid #3d9f94 !important;
59 border-bottom: 4px solid #3d9f94 !important;
60}
60}
61
61
62−.result-content {
62+.result-content, .result-source, .result-format {
63 color:#B5B8B7 !important;
63 color:#B5B8B7 !important;
64}
64}
65
65
@@ -109,7 +109,7 @@ ul.nav li a {
109
109
110.btn:hover {
110.btn:hover {
111 color:#444 !important;
111 color:#444 !important;
112− background-color: #BBB !important;
112+ background-color: #BBB !important;
113}
113}
114
114
115.btn-primary.active {
115.btn-primary.active {
@@ -221,7 +221,7 @@ p.btn.btn-default{
221}
221}
222
222
223.table-hover > tbody > tr:hover > td, .table-hover > tbody > tr:hover > th {
223.table-hover > tbody > tr:hover > td, .table-hover > tbody > tr:hover > th {
224− background: rgb(102, 105, 110) !important;
224+ background: rgb(102, 105, 110) !important;
225}
225}
226
226
227.btn-success {
227.btn-success {
searx/static/themes/oscar/less/logicodev/code.less+1−3
@@ -78,7 +78,7 @@ pre, code{
78 user-select: none;
78 user-select: none;
79 cursor: default;
79 cursor: default;
80 color: #556366;
80 color: #556366;
81−
81+
82 &::selection {
82 &::selection {
83 background: transparent; /* WebKit/Blink Browsers */
83 background: transparent; /* WebKit/Blink Browsers */
84 }
84 }
@@ -99,5 +99,3 @@ pre, code{
99.highlight {
99.highlight {
100 font-weight: 700;
100 font-weight: 700;
101}
101}
102−
103−
searx/static/themes/oscar/less/logicodev/infobox.less+1−1
@@ -30,7 +30,7 @@
30 table-layout: fixed;
30 table-layout: fixed;
31
31
32 }
32 }
33−
33+
34 .infobox_part:last-child {
34 .infobox_part:last-child {
35 margin-bottom: 0;
35 margin-bottom: 0;
36 }
36 }
searx/static/themes/oscar/less/logicodev/navbar.less−1
@@ -28,4 +28,3 @@
28 width: 80%;
28 width: 80%;
29 }
29 }
30}
30}
31−
searx/static/themes/oscar/less/logicodev/results.less+11−1
@@ -27,7 +27,7 @@
27 }
27 }
28}
28}
29
29
30−.result-content {
30+.result-content, .result-format, .result-source {
31 margin-top: 2px;
31 margin-top: 2px;
32 margin-bottom: 0;
32 margin-bottom: 0;
33 word-wrap: break-word;
33 word-wrap: break-word;
@@ -41,6 +41,16 @@
41
41
42}
42}
43
43
44+.result-source {
45+ font-size: 10px;
46+ float: left;
47+}
48+
49+.result-format {
50+ font-size: 10px;
51+ float: right;
52+}
53+
44.external-link {
54.external-link {
45 color: @dark-green;
55 color: @dark-green;
46 font-size: 12px;
56 font-size: 12px;
searx/static/themes/oscar/less/pointhi/code.less+1−1
@@ -69,7 +69,7 @@
69 -ms-user-select: none;
69 -ms-user-select: none;
70 user-select: none;
70 user-select: none;
71 cursor: default;
71 cursor: default;
72−
72+
73 &::selection {
73 &::selection {
74 background: transparent; /* WebKit/Blink Browsers */
74 background: transparent; /* WebKit/Blink Browsers */
75 }
75 }
searx/static/themes/oscar/less/pointhi/infobox.less+1−1
@@ -4,7 +4,7 @@
4 word-wrap: break-word;
4 word-wrap: break-word;
5 table-layout: fixed;
5 table-layout: fixed;
6 }
6 }
7−
7+
8 .infobox_part:last-child {
8 .infobox_part:last-child {
9 margin-bottom: 0;
9 margin-bottom: 0;
10 }
10 }
searx/static/themes/oscar/package.json+4−5
@@ -2,12 +2,11 @@
2 "devDependencies": {
2 "devDependencies": {
3 "grunt": "~0.4.5",
3 "grunt": "~0.4.5",
4 "grunt-contrib-uglify": "~0.6.0",
4 "grunt-contrib-uglify": "~0.6.0",
5− "grunt-contrib-watch" : "~0.6.1",
5+ "grunt-contrib-watch": "~0.6.1",
6− "grunt-contrib-concat" : "~0.5.0",
6+ "grunt-contrib-concat": "~0.5.0",
7− "grunt-contrib-jshint" : "~0.10.0",
7+ "grunt-contrib-jshint": "~0.10.0",
8− "grunt-contrib-less" : "~0.11.0"
8+ "grunt-contrib-less": "~0.11.0"
9 },
9 },
10−
11 "scripts": {
10 "scripts": {
12 "build": "npm install && grunt",
11 "build": "npm install && grunt",
13 "start": "grunt watch",
12 "start": "grunt watch",
searx/static/themes/pix-art/css/style.css+1−1
@@ -1 +1 @@
1−html{font-family:"Courier New",Courier,monospace;font-size:.9em;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;color:#444;padding:0;margin:0}body,#container{padding:0;margin:0}canvas{image-rendering:optimizeSpeed;image-rendering:-moz-crisp-edges;image-rendering:-webkit-optimize-contrast;image-rendering:optimize-contrast;image-rendering:pixelated;-ms-interpolation-mode:nearest-neighbor;width:32px;height:32px}#container{width:100%;position:absolute;top:0}.search{padding:0;margin:0}#search_wrapper{position:relative;width:50em;padding:10px}.center #search_wrapper{margin-left:auto;margin-right:auto}.q{background:none repeat scroll 0 0 #fff;border:1px solid #3498db;color:#222;font-size:16px;font-family:"Courier New",Courier,monospace;height:28px;margin:0;outline:medium none;padding:2px;padding-left:8px;padding-right:0 !important;width:100%;z-index:2}#search_submit{position:absolute;top:15px;right:5px;padding:0;border:0;background:url('../img/search-icon-pixel.png') no-repeat;background-size:24px 24px;opacity:.8;width:24px;height:24px;font-size:0}@media screen and (max-width:50em){#search_wrapper{width:90%;clear:both;overflow:hidden}}.row{max-width:800px;margin:20px auto;text-align:justify}.row h1{font-size:3em;margin-top:50px}.row p{padding:0 10px;max-width:700px}.row h3,.row ul{margin:4px 8px}.hmarg{margin:0 20px;border:1px solid #3498db;padding:4px 10px}a:link.hmarg{color:#3498db}a:visited.hmarg{color:#3498db}a:active.hmarg{color:#3498db}a:hover.hmarg{color:#3498db}.top_margin{margin-top:60px}.center{text-align:center}h1{font-size:5em}div.title{background:url('../img/searx-pixel.png') no-repeat;width:100%;min-height:80px;background-position:center}div.title h1{visibility:hidden}input[type="button"],input[type="submit"]{font-family:"Courier New",Courier,monospace;padding:4px 12px;margin:2px 4px;display:inline-block;background:#3498db;color:#fff;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border:0;cursor:pointer}input[type="button"]:disabled{cursor:progress}input[type="checkbox"]{visibility:hidden}fieldset{margin:8px;border:1px solid #3498db}#logo{position:absolute;top:13px;left:10px}#categories{margin:0 10px;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.checkbox_container{display:inline-block;position:relative;margin:0 3px;padding:0}.checkbox_container input{display:none}.checkbox_container label,.engine_checkbox label{cursor:pointer;padding:4px 10px;margin:0;display:block;text-transform:capitalize;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.checkbox_container input[type="checkbox"]:checked+label{background:#3498db;color:#fff}.engine_checkbox{padding:4px}label.allow{background:#e74c3c;padding:4px 8px;color:#fff;display:none}label.deny{background:#2ecc71;padding:4px 8px;color:#444;display:inline}.engine_checkbox input[type="checkbox"]:checked+label:nth-child(2)+label{display:none}.engine_checkbox input[type="checkbox"]:checked+label.allow{display:inline}a{text-decoration:none;color:#1a11be}a:visited{color:#8e44ad}.engines{color:#888}.small_font{font-size:.8em}.small p{margin:2px 0}.right{float:right}.invisible{display:none}.left{float:left}.highlight{color:#094089}.content .highlight{color:#000}.percentage{position:relative;width:300px}.percentage div{background:#444}table{width:100%}td{padding:0 4px}tr:hover{background:#ddd}#results{margin:auto;padding:0;width:50em;margin-bottom:20px}#search_url{margin-top:8px}#search_url input{border:1px solid #888;padding:4px;color:#444;width:14em;display:block;margin:4px;font-size:.8em}#preferences{top:10px;padding:0;border:0;background:url('../img/preference-icon-pixel.png') no-repeat;background-size:28px 28px;opacity:.8;width:28px;height:30px;display:block}#preferences *{display:none}#pagination{clear:both;text-align:center}#pagination br{clear:both}#apis{margin-top:8px;clear:both}#categories_container{position:relative}@media screen and (max-width:50em){#results{margin:auto;padding:0;width:90%}.checkbox_container{display:block;width:90%}.checkbox_container label{border-bottom:0}.preferences_container{display:none;postion:fixed !important;top:100px;right:0}}@media screen and (max-width:75em){div.title h1{font-size:1em}html.touch #categories{width:95%;height:30px;text-align:left;overflow-x:scroll;overflow-y:hidden;-webkit-overflow-scrolling:touch}html.touch #categories #categories_container{width:1000px;width:-moz-max-content;width:-webkit-max-content;width:max-content}html.touch #categories #categories_container .checkbox_container{display:inline-block;width:auto}#categories{font-size:90%;clear:both}#categories .checkbox_container{margin-top:2px;margin:auto}#categories{font-size:90%;clear:both}#categories .checkbox_container{margin-top:2px;margin:auto}#apis{display:none}#search_url{display:none}#logo{display:none}}.favicon{float:left;margin-right:4px;margin-top:2px}.preferences_back{background:none repeat scroll 0 0 #3498db;border:0 none;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;cursor:pointer;display:inline-block;margin:2px 4px;padding:4px 6px}.preferences_back a{color:#fff}.hidden{opacity:0;overflow:hidden;font-size:.8em;position:absolute;bottom:-20px;width:100%;text-position:center;background:white;transition:opacity 1s ease}#categories_container:hover .hidden{transition:opacity 1s ease;opacity:.8}
1+#container,.search,body,html{padding:0;margin:0}.q,html{font-family:"Courier New",Courier,monospace}div.title h1,input[type=checkbox]{visibility:hidden}#container,#logo,#search_submit{position:absolute}#apis,#pagination,#pagination br{clear:both}#categories_container,#search_wrapper,.percentage{position:relative}html{font-size:.9em;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;color:#444}canvas{image-rendering:optimizeSpeed;image-rendering:-moz-crisp-edges;image-rendering:-webkit-optimize-contrast;image-rendering:optimize-contrast;image-rendering:pixelated;-ms-interpolation-mode:nearest-neighbor;width:32px;height:32px}#container{width:100%;top:0}#search_wrapper{width:50em;padding:10px}.center #search_wrapper{margin-left:auto;margin-right:auto}.q{background:#FFF;border:1px solid #3498DB;color:#222;font-size:16px;height:28px;margin:0;outline:0;padding:2px 2px 2px 8px;padding-right:0!important;width:100%;z-index:2}#search_submit{top:15px;right:5px;padding:0;border:0;background:url(../img/search-icon-pixel.png) no-repeat;background-size:24px 24px;opacity:.8;width:24px;height:24px;font-size:0}@media screen and (max-width:50em){#search_wrapper{width:90%;clear:both;overflow:hidden}}.row{max-width:800px;margin:20px auto;text-align:justify}#pagination,.center{text-align:center}.row h1{font-size:3em;margin-top:50px}.row p{padding:0 10px;max-width:700px}.row h3,.row ul{margin:4px 8px}.hmarg{margin:0 20px;border:1px solid #3498DB;padding:4px 10px}a:active.hmarg,a:hover.hmarg,a:link.hmarg,a:visited.hmarg{color:#3498DB}.top_margin{margin-top:60px}h1{font-size:5em}div.title{background:url(../img/searx-pixel.png) center no-repeat;width:100%;min-height:80px}input[type=button],input[type=submit]{font-family:"Courier New",Courier,monospace;padding:4px 12px;margin:2px 4px;display:inline-block;background:#3498DB;color:#FFF;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border:0;cursor:pointer}input[type=button]:disabled{cursor:progress}fieldset{margin:8px;border:1px solid #3498DB}#logo{top:13px;left:10px}#categories{margin:0 10px;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.checkbox_container{display:inline-block;position:relative;margin:0 3px;padding:0}.checkbox_container input{display:none}.checkbox_container label,.engine_checkbox label{cursor:pointer;padding:4px 10px;margin:0;display:block;text-transform:capitalize;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.checkbox_container input[type=checkbox]:checked+label{background:#3498DB;color:#FFF}.engine_checkbox{padding:4px}label.allow{background:#E74C3C;padding:4px 8px;color:#FFF;display:none}label.deny{background:#2ECC71;padding:4px 8px;color:#444;display:inline}.engine_checkbox input[type=checkbox]:checked+label:nth-child(2)+label{display:none}.engine_checkbox input[type=checkbox]:checked+label.allow{display:inline}#preferences *,.invisible{display:none}a{text-decoration:none;color:#1a11be}a:visited{color:#8E44AD}.engines{color:#888}.small_font{font-size:.8em}.small p{margin:2px 0}#apis,#search_url{margin-top:8px}.right{float:right}.favicon,.left{float:left}.highlight{color:#094089}.content .highlight{color:#000}.percentage{width:300px}.percentage div{background:#444}table{width:100%}td{padding:0 4px}tr:hover{background:#DDD}#results{margin:auto auto 20px;padding:0;width:50em}#search_url input{border:1px solid #888;padding:4px;color:#444;width:14em;display:block;margin:4px;font-size:.8em}#preferences{top:10px;padding:0;border:0;background:url(../img/preference-icon-pixel.png) no-repeat;background-size:28px 28px;opacity:.8;width:28px;height:30px;display:block}@media screen and (max-width:50em){#results{margin:auto;padding:0;width:90%}.checkbox_container{display:block;width:90%}.checkbox_container label{border-bottom:0}.preferences_container{display:none;postion:fixed!important;top:100px;right:0}}@media screen and (max-width:75em){div.title h1{font-size:1em}html.touch #categories{width:95%;height:30px;text-align:left;overflow-x:scroll;overflow-y:hidden;-webkit-overflow-scrolling:touch}html.touch #categories #categories_container{width:1000px;width:-moz-max-content;width:-webkit-max-content;width:max-content}html.touch #categories #categories_container .checkbox_container{display:inline-block;width:auto}#categories{font-size:90%;clear:both}#categories .checkbox_container{margin:auto}#apis,#logo,#search_url{display:none}}.favicon{margin-right:4px;margin-top:2px}.preferences_back{background:#3498DB;border:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;cursor:pointer;display:inline-block;margin:2px 4px;padding:4px 6px}.preferences_back a{color:#FFF}.hidden{opacity:0;overflow:hidden;font-size:.8em;position:absolute;bottom:-20px;width:100%;text-position:center;background:#fff;transition:opacity 1s ease}#categories_container:hover .hidden{transition:opacity 1s ease;opacity:.8}
searx/static/themes/simple/css/searx-rtl.css+1−1
@@ -1,4 +1,4 @@
1−/*! searx | 14-08-2018 | https://github.com/asciimoo/searx */
1+/*! searx | 06-08-2019 | https://github.com/asciimoo/searx */
2/*
2/*
3* searx, A privacy-respecting, hackable metasearch engine
3* searx, A privacy-respecting, hackable metasearch engine
4*
4*
searx/static/themes/simple/css/searx-rtl.min.css+1−1
@@ -1 +1 @@
1−/*! searx | 14-08-2018 | https://github.com/asciimoo/searx *//*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */button,hr,input{overflow:visible}[type=checkbox],[type=radio],legend{padding:0;box-sizing:border-box}.badge,.center{text-align:center}.badge,progress,sub,sup{vertical-align:baseline}.autocomplete>ul,.list-unstyled{list-style-type:none}.tabs>section,legend{box-sizing:border-box}#main_preferences h1 span,#main_stats h1 span,.index h1{visibility:hidden}#apis,#pagination,#pagination br,#sidebar .infobox .attributes,#sidebar .infobox .urls,#sidebar .infobox br,.result .break,footer{clear:both}html{line-height:1.15}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}.highlight pre,textarea{overflow:auto}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{color:inherit;display:table;max-width:100%;white-space:normal}.badge,.search_box{white-space:nowrap}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}.highlight .c,.highlight .cm,.highlight .ge,.highlight .sd{font-style:italic}.dialog-error:before,.dialog-modal:before,.dialog-warning:before,.ion-icon-big:before,.ion-icon:before{font-family:ion}details{display:block}summary{display:list-item}[hidden],html.js .show_if_nojs,html.no-js .hide_if_nojs,template{display:none}.highlight .hll{background-color:#ffc}.highlight .c{color:#408080}.highlight .err{border:1px solid red}.highlight .k{color:green;font-weight:700}.highlight .o{color:#666}.highlight .cm{color:#408080}.highlight .cp{color:#BC7A00}.highlight .c1,.highlight .cs{color:#408080;font-style:italic}.highlight .gd{color:#A00000}.highlight .gr{color:red}.highlight .gh{color:navy;font-weight:700}.highlight .gi{color:#00A000}.highlight .go{color:#888}.highlight .gp{color:navy;font-weight:700}.highlight .gs{font-weight:700}.highlight .gu{color:purple;font-weight:700}.highlight .gt{color:#04D}.highlight .kc,.highlight .kd,.highlight .kn{color:green;font-weight:700}.highlight .kp{color:green}.highlight .kr{color:green;font-weight:700}.highlight .kt{color:#B00040}.highlight .m{color:#666}.highlight .s{color:#BA2121}.highlight .na{color:#7D9029}.highlight .nb{color:green}.highlight .nc{color:#00F;font-weight:700}.highlight .no{color:#800}.highlight .nd{color:#A2F}.highlight .ni{color:#999;font-weight:700}.highlight .ne{color:#D2413A;font-weight:700}.highlight .nf{color:#00F}.highlight .nl{color:#A0A000}.highlight .nn{color:#00F;font-weight:700}.highlight .nt{color:green;font-weight:700}.highlight .nv{color:#19177C}.highlight .ow{color:#A2F;font-weight:700}.highlight .w{color:#bbb}.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:#666}.highlight .s2,.highlight .sb,.highlight .sc{color:#BA2121}.highlight .sd{color:#BA2121}.highlight .se{color:#B62;font-weight:700}.highlight .sh{color:#BA2121}.highlight .si{color:#B68;font-weight:700}.highlight .sx{color:green}.highlight .sr{color:#B68}.highlight .s1{color:#BA2121}.highlight .ss{color:#19177C}.highlight .bp{color:green}.highlight .vc,.highlight .vg,.highlight .vi{color:#19177C}.highlight .il{color:#666}.badge,kbd{color:#fff}.highlight .lineno{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.btn-collapse,.tabs>label,select:focus,select:hover{cursor:pointer}.highlight .lineno::selection{background:0 0}.highlight .lineno::-moz-selection{background:0 0}.right{float:right}.left{float:left}.invisible{display:none!important}.list-unstyled li{margin-top:4px;margin-bottom:4px}.danger{background-color:#fae1e1}.badge{display:inline-block;background-color:#777;min-width:10px;padding:1px 5px;border-radius:5px}.dialog-error tr,.dialog-modal tr,.dialog-warning tr{vertical-align:text-top}kbd{padding:2px 4px;margin:1px;font-size:90%;background:#000}table{width:100%}table.striped tr{border-bottom:1px solid #ececec}th{padding:.4em}td{padding:0 4px}tr:hover{background:#ececec}div.selectable_url{border:1px solid #888;padding:4px;color:#444;width:100%;display:block;margin:.1em;overflow:hidden;height:1.2em;line-height:1.2em}div.selectable_url pre{display:block;font-size:.8em;word-break:break-all;margin:.1em;-webkit-user-select:all;-moz-user-select:all;-ms-user-select:element;user-select:all}#categories,.tabs>label{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-touch-callout:none;-khtml-user-select:none}.dialog-error{position:relative;width:70%;padding:1em 1em 1em 2.7em;margin:0 8% 1em;border:1px solid #db3434;border-radius:4px;text-align:left;color:#db3434;background:#fae1e1}.dialog-error:before{position:absolute;top:.5em;left:.5em;font-size:1.5em;content:"\f110"}.dialog-error .close{float:right;position:relative;top:-3px;color:inherit;font-size:1.5em}.dialog-error ol,.dialog-error p,.dialog-error ul{margin:1px 0 0}.dialog-error table{width:auto}.dialog-error tr:hover{background:0 0}.dialog-error td{padding:0 1em 0 0}.dialog-error h4{margin-top:.3em;margin-bottom:.3em}.dialog-warning{position:relative;width:70%;padding:1em 1em 1em 2.7em;margin:0 8% 1em;border:1px solid #dbba34;border-radius:4px;text-align:left;color:#dbba34;background:#faf5e1}.dialog-warning:before{position:absolute;top:.5em;left:.5em;font-size:1.5em;content:"\f10f"}.dialog-warning .close{float:right;position:relative;top:-3px;color:inherit;font-size:1.5em}.dialog-warning ol,.dialog-warning p,.dialog-warning ul{margin:1px 0 0}.dialog-warning table{width:auto}.dialog-warning tr:hover{background:0 0}.dialog-warning td{padding:0 1em 0 0}.dialog-warning h4{margin-top:.3em;margin-bottom:.3em}.dialog-modal{width:70%;padding:1em 1em 1em 2.7em;border:1px solid #000;border-radius:4px;text-align:left;background:#fff;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:100000;margin:0 50% 0 0;box-shadow:0 0 1em}.dialog-modal:before{position:absolute;top:.5em;left:.5em;font-size:1.5em}.dialog-modal .close{float:right;position:relative;top:-3px;color:inherit;font-size:1.5em}.dialog-modal ol,.dialog-modal p,.dialog-modal ul{margin:1px 0 0}.dialog-modal table{width:auto}.dialog-modal tr:hover{background:0 0}.dialog-modal td{padding:0 1em 0 0}.dialog-modal h4{margin-top:.3em;margin-bottom:.3em}.scrollx{overflow-x:auto;overflow-y:hidden;display:block;padding:0;margin:0;border:none}.tabs .tabs>label{font-size:90%}.tabs{display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:flex;flex-wrap:wrap;width:100%;min-width:100%}.tabs>*{order:2}.tabs>input[type=radio]{display:none}.tabs>label{order:1;padding:.7em;margin:0 .7em;letter-spacing:.5px;text-transform:uppercase;border:solid #fff;border-width:0 0 2px;user-select:none}.tabs>label:hover,.tabs>label:last-of-type{border-bottom:2px solid #084999}.tabs>section{min-width:100%;padding:.7rem 0;border-top:1px solid #000;display:none}.tabs>label:last-of-type{background:#3498DB;color:#FFF;font-weight:700;letter-spacing:-.1px}.tabs>section:last-of-type{display:block}html body .tabs>input:checked~section{display:none}html body .tabs>input:checked~label{position:inherited;background:inherit;border-bottom:2px solid transparent;font-weight:400;color:inherit}html body .tabs>input:checked~label:hover{border-bottom:2px solid #084999}html body .tabs>input:checked+label{border-bottom:2px solid #084999;background:#3498DB;color:#FFF;font-weight:700;letter-spacing:-.1px}html body .tabs>input:checked+label+section{display:block}select{height:28px;margin:0 1em 0 0;padding:2px 8px 2px 0!important;color:#222;font-size:12px;z-index:2}@supports ((background-position-x:100%) and ((appearance:none) or (-webkit-appearance:none) or (-moz-appearance:none))){select{appearance:none;-webkit-appearance:none;-moz-appearance:none;border:none;border-bottom:1px solid #d7d7d7;background:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCIgdmlld0JveD0iMCAwIDUxMiA1MTIiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDUxMiA1MTIiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwb2x5Z29uIHBvaW50cz0iMTI4LDE5MiAyNTYsMzIwIDM4NCwxOTIiLz48L2c+PC9zdmc+Cg==) no-repeat;background-position-x:105%;background-size:2em;background-origin:content-box;outline:0}select:focus,select:hover{border-bottom:1px solid #3498DB}}@supports (border-radius:50px){.checkbox-onoff{display:inline-block;width:40px;height:10px;background:#dcdcdc;margin:8px auto;position:relative;border-radius:50px}.checkbox-onoff label{display:block;width:20px;height:20px;position:absolute;top:-5px;cursor:pointer;border-radius:50px;box-shadow:0 3px 5px 0 rgba(0,0,0,.3);transition:all .4s ease;left:27px;background-color:#3498DB}.checkbox-onoff input[type=checkbox]{visibility:hidden}.checkbox-onoff input[type=checkbox]:checked+label{left:-5px;background:#dcdcdc}}@supports (transform:rotate(-45deg)){.checkbox{width:20px;position:relative;margin:20px auto}.checkbox label{width:20px;height:20px;cursor:pointer;position:absolute;top:0;left:0;background:#fff;border-radius:4px;box-shadow:inset 0 1px 1px #fff,0 1px 4px rgba(0,0,0,.5)}.checkbox label:after{content:'';width:9px;height:5px;position:absolute;top:4px;left:4px;border:3px solid #333;border-top:none;border-right:none;background:0 0;opacity:0;transform:rotate(-45deg)}.checkbox input[type=checkbox]{visibility:hidden}.checkbox input[type=checkbox]:checked+label:after{border-color:#3498DB;opacity:1}.checkbox input[disabled]+label{background-color:transparent!important;box-shadow:none!important;cursor:inherit}.checkbox input:not(:checked):not([readonly]):not([disabled])+label:hover::after{opacity:.5}}@media screen and (max-width:50em){.tabs>label{width:100%}}.loader,.loader:after{border-radius:50%;width:2em;height:2em}.loader{margin:1em auto;font-size:10px;position:relative;text-indent:-9999em;border-top:.5em solid rgba(0,0,0,.2);border-right:.5em solid rgba(0,0,0,.2);border-bottom:.5em solid rgba(0,0,0,.2);border-left:.5em solid rgba(255,255,255,0);-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:load8 1.2s infinite linear;animation:load8 1.2s infinite linear}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load8{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}/*! Autocomplete.js v2.6.3 | license MIT | (c) 2017, Baptiste Donaux | http://autocomplete-js.com */.autocomplete{position:absolute;max-height:0;overflow-y:hidden;text-align:left}#categories_container,.category{position:relative}.autocomplete:active,.autocomplete:focus,.autocomplete:hover{background-color:#fff}#send_search:hover,.autocomplete>ul>li.active,.autocomplete>ul>li:active,.autocomplete>ul>li:focus{background-color:#3498DB}.autocomplete:empty{display:none}.autocomplete>ul{margin:0;padding:0}.autocomplete>ul>li{cursor:pointer;padding:5px 0 5px 10px}.autocomplete>ul>li.active a:active,.autocomplete>ul>li.active a:focus,.autocomplete>ul>li.active a:hover,.autocomplete>ul>li:active a:active,.autocomplete>ul>li:active a:focus,.autocomplete>ul>li:active a:hover,.autocomplete>ul>li:focus a:active,.autocomplete>ul>li:focus a:focus,.autocomplete>ul>li:focus a:hover{text-decoration:none}.autocomplete>ul>li.locked{cursor:inherit}.autocomplete.open{display:block;background-color:#fff;border:1px solid #3498DB;max-height:500px;overflow-y:auto;z-index:100}.autocomplete.open:empty{display:none}.ion-icon,.ion-icon-big{display:inline-block;line-height:1;font-weight:400;font-style:normal;speak:none;text-decoration:inherit;text-transform:none;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;vertical-align:middle}@media screen and (max-width:50em){.autocomplete{bottom:0}.autocomplete>ul>li{padding:7px 0 7px 10px;border-bottom:1px solid #E8E7E6;text-align:left}}#main_preferences table td,.index{text-align:center}@font-face{font-family:ion;src:url(../fonts/ion.eot?ce7a0ead692560b4405a96d5b8471f51);src:url(../fonts/ion.eot?#iefix) format("embedded-opentype"),url(../fonts/ion.woff2?ce7a0ead692560b4405a96d5b8471f51) format("woff2"),url(../fonts/ion.woff?ce7a0ead692560b4405a96d5b8471f51) format("woff"),url(../fonts/ion.ttf?ce7a0ead692560b4405a96d5b8471f51) format("truetype"),url(../fonts/ion.svg?ce7a0ead692560b4405a96d5b8471f51#ion) format("svg");font-weight:400;font-style:normal}.ion-navicon-round:before{content:"\f101"}.ion-search:before{content:"\f102"}.ion-play:before{content:"\f103"}.ion-link:before{content:"\f104"}.ion-chevron-up:before{content:"\f105"}.ion-chevron-left:before{content:"\f106"}.ion-chevron-right:before{content:"\f107"}.ion-arrow-down-a:before{content:"\f108"}.ion-arrow-up-a:before{content:"\f109"}.ion-arrow-swap:before{content:"\f10a"}.ion-arrow-dropdown:before{content:"\f10b"}.ion-globe:before{content:"\f10c"}.ion-time:before{content:"\f10d"}.ion-location:before{content:"\f10e"}.ion-warning:before{content:"\f10f"}.ion-error:before{content:"\f110"}.ion-film-outline:before{content:"\f111"}.ion-music-note:before{content:"\f112"}.ion-more-vertical:before{content:"\f113"}.ion-magnet:before{content:"\f114"}.ion-close:before{content:"\f115"}.ion-icon-big{font-size:149%}.index .title{background:url(../img/searx.png) center no-repeat;width:100%;min-height:80px}.index h1{font-size:5em}.index #search{margin:0 auto;background:inherit;border:inherit}.index .search_filters{display:block;margin:1em 0}.index .category label{padding:6px 10px;border-bottom:initial!important}@media screen and (max-width:75em){div.title h1{font-size:1em}.preferences_back{clear:both}}#main_preferences form{width:100%}#main_preferences fieldset{margin:8px;border:none}#main_preferences legend{margin:0;padding:5px 0 0;display:block;float:left;width:300px}#main_preferences .value{margin:0;padding:0;float:left;width:15em}#main_preferences .description{margin:0;padding:5px 0 0;float:left;width:50%;color:#909090;font-size:90%}#main_preferences select{width:200px;font-size:inherit!important}#main_preferences table{border-collapse:collapse}#main_preferences table.cookies{width:auto}#main_preferences div.selectable_url pre,footer,main{width:100%}#main_preferences table.cookies td,#main_preferences table.cookies th{text-align:left;padding:.25em}#main_preferences table.cookies td:first-child,#main_preferences table.cookies th:first-child{padding-right:4em}#main_preferences table.cookies>tbody>tr:nth-child(even)>td,#main_preferences table.cookies>tbody>tr:nth-child(even)>th{background-color:#ececec}#main_preferences .name,#main_preferences .shortcut{text-align:left}#main_preferences .preferences_back{background:#3498DB;color:#fff;border:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;cursor:pointer;display:inline-block;margin:2px 4px;padding:.5em}#main_preferences .preferences_back a{display:block;color:#FFF}#main_preferences .preferences_back a::first-letter{text-transform:uppercase}#search{padding:0 2em;margin:0;background:#f7f7f7;border-bottom:1px solid #d7d7d7}#search_wrapper{padding:10px 0}.search_box{margin:0 12px 0 0;display:inline-flex;flex-direction:row}#clear_search,#q,#send_search{border-collapse:separate;box-sizing:border-box;margin:0;padding:2px;height:2.2em;background:#FFF;color:#222;font-size:16px;outline:0}#clear_search{display:block;width:1.8em;border-top:1px solid #3498DB;border-bottom:1px solid #3498DB;border-right:none;border-left:none;border-radius:0;z-index:10000}#clear_search:hover{color:#3498DB}#clear_search.empty *{display:none}#q::-ms-clear,#q::-webkit-search-cancel-button{display:none}#q,#send_search{display:block!important;border:1px solid #3498DB;border-radius:0;z-index:2}#q{outline:0;padding-left:8px;padding-right:0!important;border-right:none;width:40em}#send_search{border-left:none;width:2.2em}#send_search:hover{cursor:pointer;color:#ECF0F1}.no-js #send_search{width:auto!important}.search_filters{display:inline-block;vertical-align:middle}@media screen and (max-width:75em){#categories{font-size:90%;clear:both}#categories .checkbox_container{margin:auto}html.touch #main_index #categories_container,html.touch #main_results #categories_container{width:1000px;width:-moz-max-content;width:-webkit-max-content;width:max-content}html.touch #main_index #categories_container .category,html.touch #main_results #categories_container .category{display:inline-block;width:auto}html.touch #main_index #categories,html.touch #main_results #categories{width:100%;margin:0;text-align:left;overflow-x:scroll;overflow-y:hidden;-webkit-overflow-scrolling:touch}}@media screen and (max-width:50em){#search{width:100%;margin:0;padding:.1em 0 0}#search_wrapper{width:100%;margin:0 0 .7em;padding:0}.search_box{width:99%;margin:.1em;padding:0 .1em 0 0;display:flex;flex-direction:row}#q{width:auto!important;flex:1}.search_filters{display:block;margin:.5em}.language,.time_range{width:45%}.category{display:block;width:90%}.category label{border-bottom:0}}#categories{margin:0 10px 0 0;user-select:none}#categories::-webkit-scrollbar{width:0;height:0}.category{display:inline-block;margin:0 3px;padding:0}.category input{display:none}.category label{cursor:pointer;padding:4px 10px;margin:0;display:block;text-transform:capitalize;font-size:.9em;border-bottom:2px solid transparent;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body,html,main{padding:0;margin:0}.category input[type=checkbox]:focus+label{box-shadow:0 0 8px #3498DB}.category input[type=checkbox]:checked+label{background:#3498DB;color:#FFF;border-bottom:2px solid #084999}#categories_container .help{position:absolute;width:100%;bottom:-20px;overflow:hidden;opacity:0;transition:opacity 1s ease;font-size:.8em;text-position:center;background:#fff}footer p,html{font-size:.9em}#categories_container:hover .help{opacity:.8;transition:opacity 1s ease}html{font-family:arial,sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;color:#444}#main_about,#main_preferences,#main_stats{margin:3em;width:auto}footer{bottom:0;height:3em;margin:1em 0;padding:1em 0;text-align:center}#main_preferences h1,#main_stats h1{background:url(../img/searx.png) no-repeat;background-size:auto 75%;min-height:40px;margin:0 auto}#results button[type=submit],input[type=submit]{padding:.5rem;margin:2px 4px;display:inline-block;background:#3498DB;color:#FFF;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border:0;cursor:pointer}a{text-decoration:none;color:#29314d}a:visited,a:visited .highlight{color:#684898}article[data-vim-selected]{background:#f7f7f7}article[data-vim-selected]::before{position:absolute;left:1em;padding:2px;content:">";font-weight:700;color:#3498DB}article.result-images[data-vim-selected]{background:#3498DB}article.result-images[data-vim-selected]::before{display:none;content:""}.result{margin:19px 0 18px;padding:0}.result h3{font-size:1.1em;word-wrap:break-word;margin:5px 0 0;padding:0}.result h3 a{color:#084999;font-weight:400;font-size:1.1em}.result h3 a:visited{color:#684898}.result h3 a:focus,.result h3 a:hover{text-decoration:underline;border:none;-webkit-box-shadow:none;box-shadow:none;outline:0}.result .cache_link,.result .proxyfied_link{font-size:.9em!important}.result .altlink,.result .content,.result .stat,.result .url{font-size:.9em;padding:0;max-width:54em;word-wrap:break-word}.result .altlink,.result .content,.result .stat{margin:0;line-height:1.24}.result .altlink .highlight,.result .content .highlight,.result .stat .highlight{color:#000;background:inherit;font-weight:700}.result .codelines .highlight{color:inherit;background:inherit;font-weight:400}.result .url{margin:0 0 3px;color:#25a55b}.result .published_date{font-size:.8em;color:#888}.result img.thumbnail{float:left;padding:0 5px 10px 0;width:20em;min-width:20em;min-height:8em}.result img.image{float:left;padding:0 5px 10px 0;width:100px;max-height:100px;object-fit:scale-down;object-position:right top}.category-social .image{width:auto!important;min-width:48px;min-height:48px;padding:0 5px 25px 0!important}.result-videos .content{overflow:hidden}.engines{float:right;color:#888}.engines span{font-size:smaller;margin:0 .5em 0 0}.result-images,.result-images img{margin:0;padding:0;max-height:200px}.small_font{font-size:.8em}.highlight{color:#094089;background:inherit;font-weight:700}.result-images{display:inline-block;position:relative}.result-images img{float:inherit;border:none;background:#084999}.result-images span a{display:none;color:#FFF}.result-images:hover span a{display:block;position:absolute;bottom:0;right:0;padding:4px;margin:0 0 4px 4px;background-color:rgba(0,0,0,.6);font-size:.7em}.torrent_result{border-left:10px solid #d3d3d3;padding-left:3px}#answers,#backToTop,#sidebar .infobox{border:1px solid #ddd;box-shadow:0 0 5px #CCC}.torrent_result p{margin:3px;font-size:.8em}.torrent_result a{color:#084999}.torrent_result a:hover{text-decoration:underline}.torrent_result a:visited{color:#684898}#results{margin:2em 2em 20px;padding:0;width:50em}#suggestions .wrapper{display:flex;flex-flow:row wrap;justify-content:flex-end}#suggestions .wrapper form{display:inline-block;flex:1 1 50%}#answers,#corrections,#suggestions{max-width:50em}#answers input,#corrections input,#infoboxes input,#suggestions input{padding:0;margin:3px;font-size:.9em;display:inline-block;background:0 0;color:#444;cursor:pointer}#answers .infobox .url a,#answers input[type=submit],#corrections .infobox .url a,#corrections input[type=submit],#infoboxes .infobox .url a,#infoboxes input[type=submit],#suggestions .infobox .url a,#suggestions input[type=submit]{color:#084999;text-decoration:none;font-size:.9rem}#answers .infobox .url a:hover,#answers input[type=submit]:hover,#corrections .infobox .url a:hover,#corrections input[type=submit]:hover,#infoboxes .infobox .url a:hover,#infoboxes input[type=submit]:hover,#suggestions .infobox .url a:hover,#suggestions input[type=submit]:hover{text-decoration:underline}#corrections{display:flex;flex-flow:row wrap;margin:1em 0}#corrections h4,#corrections input[type=submit]{display:inline-block;margin:0 .5em 0 0}#corrections input[type=submit]::after{content:", "}#apis .title,#search_url .title,#suggestions .title{margin:2em 0 .5em;color:#444}#answers{margin:10px 8px;padding:.9em}#answers h4{display:none}#answers .answer{display:block;font-size:1.2em;font-weight:700}#answers form,#infoboxes form{min-width:210px}#sidebar{position:absolute;top:100px;left:57em;margin:0 2px 5px 5px;padding:0 2px 2px;max-width:25em;word-wrap:break-word}#sidebar .infobox{margin:10px 0;padding:.9em;font-size:.9em}#sidebar .infobox h2{margin:0 0 .5em}#sidebar .infobox img{max-width:100%;max-height:12em;display:block;margin:0;padding:0}#sidebar .infobox dl{margin:.5em 0}#sidebar .infobox dt{display:inline;margin:.5em .25em .5em 0;padding:0;font-weight:700}#sidebar .infobox dd{display:inline;margin:.5em 0;padding:0}#apis,#search_url{margin-top:8px}#sidebar .infobox input{font-size:1em}#search_url div.selectable_url pre{width:200em}#linkto_preferences{position:absolute;right:10px;top:.9em;padding:0;border:0;display:block;font-size:1.2em;color:#222}#linkto_preferences a:active *,#linkto_preferences a:hover *,#linkto_preferences a:link *,#linkto_preferences a:visited *{color:#222}#backToTop{margin:0 0 0 2em;padding:0;font-size:1em;background:#fff;position:fixed;bottom:85px;left:50em;transition:opacity .5s;opacity:0}#backToTop a{display:block;margin:0;padding:.6em}@media screen and (max-width:75em){#main_about,#main_preferences,#main_stats{margin:.5em;width:auto}#answers,#suggestions{margin-top:1em}#infoboxes{position:inherit;max-width:inherit}#infoboxes .infobox{clear:both}#infoboxes .infobox img{float:left;max-width:10em;margin:.5em .5em .5em 0}#sidebar{position:static;max-width:50em;margin:0 0 2px;padding:0;float:none;border:none;width:auto}.image_result,.image_result img,.result .thumbnail{max-width:98%}#sidebar input{border:0}#apis,#search_url{display:none}.result{border-bottom:1px solid #E8E7E6;margin:0;padding-top:8px;padding-bottom:6px}.result h3{margin:0 0 1px}.result .url span.url{display:block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;width:100%}.result .url a{float:right;padding:0 .5em}.result .engines{float:right;padding:0 0 3px}.result-images{border-bottom:none!important}}#main_results div#results.only_template_images{flex-direction:column;width:auto;display:flex}#main_results div#results.only_template_images #sidebar{position:relative;top:auto;order:2}#main_results div#results.only_template_images #urls{position:relative;order:1}#main_results div#results.only_template_images #backToTop{right:.5em;left:auto}#main_results div#results.only_template_images #pagination{position:relative;order:3}@media screen and (max-width:50em){article[data-vim-selected]::before{display:none;content:""}#linkto_preferences{display:none;postion:fixed!important;top:100px;right:0}#sidebar{margin:0 5px 2px}#corrections{margin:1em 5px}#results{margin:0;padding:0;width:initial}#backToTop{left:40em;bottom:35px}.result{padding:8px 10px 6px}.result-images{margin:0;padding:0;border:none}}@media screen and (max-width:35em){.result-videos img.thumbnail{float:none!important}.result-videos .content{overflow:inherit}}#search_submit{left:1px;right:auto}
1+/*! searx | 06-08-2019 | https://github.com/asciimoo/searx *//*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */button,hr,input{overflow:visible}[type=checkbox],[type=radio],legend{padding:0;box-sizing:border-box}.badge,.center{text-align:center}.badge,progress,sub,sup{vertical-align:baseline}.autocomplete>ul,.list-unstyled{list-style-type:none}.tabs>section,legend{box-sizing:border-box}#main_preferences h1 span,#main_stats h1 span,.index h1{visibility:hidden}#apis,#pagination,#pagination br,#sidebar .infobox .attributes,#sidebar .infobox .urls,#sidebar .infobox br,.result .break,footer{clear:both}html{line-height:1.15}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}.highlight pre,textarea{overflow:auto}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{color:inherit;display:table;max-width:100%;white-space:normal}.badge,.search_box{white-space:nowrap}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}.highlight .c,.highlight .cm,.highlight .ge,.highlight .sd{font-style:italic}.dialog-error:before,.dialog-modal:before,.dialog-warning:before,.ion-icon-big:before,.ion-icon:before{font-family:ion}details{display:block}summary{display:list-item}[hidden],html.js .show_if_nojs,html.no-js .hide_if_nojs,template{display:none}.highlight .hll{background-color:#ffc}.highlight .c{color:#408080}.highlight .err{border:1px solid red}.highlight .k{color:green;font-weight:700}.highlight .o{color:#666}.highlight .cm{color:#408080}.highlight .cp{color:#BC7A00}.highlight .c1,.highlight .cs{color:#408080;font-style:italic}.highlight .gd{color:#A00000}.highlight .gr{color:red}.highlight .gh{color:navy;font-weight:700}.highlight .gi{color:#00A000}.highlight .go{color:#888}.highlight .gp{color:navy;font-weight:700}.highlight .gs{font-weight:700}.highlight .gu{color:purple;font-weight:700}.highlight .gt{color:#04D}.highlight .kc,.highlight .kd,.highlight .kn{color:green;font-weight:700}.highlight .kp{color:green}.highlight .kr{color:green;font-weight:700}.highlight .kt{color:#B00040}.highlight .m{color:#666}.highlight .s{color:#BA2121}.highlight .na{color:#7D9029}.highlight .nb{color:green}.highlight .nc{color:#00F;font-weight:700}.highlight .no{color:#800}.highlight .nd{color:#A2F}.highlight .ni{color:#999;font-weight:700}.highlight .ne{color:#D2413A;font-weight:700}.highlight .nf{color:#00F}.highlight .nl{color:#A0A000}.highlight .nn{color:#00F;font-weight:700}.highlight .nt{color:green;font-weight:700}.highlight .nv{color:#19177C}.highlight .ow{color:#A2F;font-weight:700}.highlight .w{color:#bbb}.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:#666}.highlight .s2,.highlight .sb,.highlight .sc{color:#BA2121}.highlight .sd{color:#BA2121}.highlight .se{color:#B62;font-weight:700}.highlight .sh{color:#BA2121}.highlight .si{color:#B68;font-weight:700}.highlight .sx{color:green}.highlight .sr{color:#B68}.highlight .s1{color:#BA2121}.highlight .ss{color:#19177C}.highlight .bp{color:green}.highlight .vc,.highlight .vg,.highlight .vi{color:#19177C}.highlight .il{color:#666}.badge,kbd{color:#fff}.highlight .lineno{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.btn-collapse,.tabs>label,select:focus,select:hover{cursor:pointer}.highlight .lineno::selection{background:0 0}.highlight .lineno::-moz-selection{background:0 0}.right{float:right}.left{float:left}.invisible{display:none!important}.list-unstyled li{margin-top:4px;margin-bottom:4px}.danger{background-color:#fae1e1}.badge{display:inline-block;background-color:#777;min-width:10px;padding:1px 5px;border-radius:5px}.dialog-error tr,.dialog-modal tr,.dialog-warning tr{vertical-align:text-top}kbd{padding:2px 4px;margin:1px;font-size:90%;background:#000}table{width:100%}table.striped tr{border-bottom:1px solid #ececec}th{padding:.4em}td{padding:0 4px}tr:hover{background:#ececec}div.selectable_url{border:1px solid #888;padding:4px;color:#444;width:100%;display:block;margin:.1em;overflow:hidden;height:1.2em;line-height:1.2em}div.selectable_url pre{display:block;font-size:.8em;word-break:break-all;margin:.1em;-webkit-user-select:all;-moz-user-select:all;-ms-user-select:element;user-select:all}#categories,.tabs>label{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-touch-callout:none;-khtml-user-select:none}.dialog-error{position:relative;width:70%;padding:1em 1em 1em 2.7em;margin:0 8% 1em;border:1px solid #db3434;border-radius:4px;text-align:left;color:#db3434;background:#fae1e1}.dialog-error:before{position:absolute;top:.5em;left:.5em;font-size:1.5em;content:"\f110"}.dialog-error .close{float:right;position:relative;top:-3px;color:inherit;font-size:1.5em}.dialog-error ol,.dialog-error p,.dialog-error ul{margin:1px 0 0}.dialog-error table{width:auto}.dialog-error tr:hover{background:0 0}.dialog-error td{padding:0 1em 0 0}.dialog-error h4{margin-top:.3em;margin-bottom:.3em}.dialog-warning{position:relative;width:70%;padding:1em 1em 1em 2.7em;margin:0 8% 1em;border:1px solid #dbba34;border-radius:4px;text-align:left;color:#dbba34;background:#faf5e1}.dialog-warning:before{position:absolute;top:.5em;left:.5em;font-size:1.5em;content:"\f10f"}.dialog-warning .close{float:right;position:relative;top:-3px;color:inherit;font-size:1.5em}.dialog-warning ol,.dialog-warning p,.dialog-warning ul{margin:1px 0 0}.dialog-warning table{width:auto}.dialog-warning tr:hover{background:0 0}.dialog-warning td{padding:0 1em 0 0}.dialog-warning h4{margin-top:.3em;margin-bottom:.3em}.dialog-modal{width:70%;padding:1em 1em 1em 2.7em;border:1px solid #000;border-radius:4px;text-align:left;background:#fff;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:100000;margin:0 50% 0 0;box-shadow:0 0 1em}.dialog-modal:before{position:absolute;top:.5em;left:.5em;font-size:1.5em}.dialog-modal .close{float:right;position:relative;top:-3px;color:inherit;font-size:1.5em}.dialog-modal ol,.dialog-modal p,.dialog-modal ul{margin:1px 0 0}.dialog-modal table{width:auto}.dialog-modal tr:hover{background:0 0}.dialog-modal td{padding:0 1em 0 0}.dialog-modal h4{margin-top:.3em;margin-bottom:.3em}.scrollx{overflow-x:auto;overflow-y:hidden;display:block;padding:0;margin:0;border:none}.tabs .tabs>label{font-size:90%}.tabs{display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:flex;flex-wrap:wrap;width:100%;min-width:100%}.tabs>*{order:2}.tabs>input[type=radio]{display:none}.tabs>label{order:1;padding:.7em;margin:0 .7em;letter-spacing:.5px;text-transform:uppercase;border:solid #fff;border-width:0 0 2px;user-select:none}.tabs>label:hover,.tabs>label:last-of-type{border-bottom:2px solid #084999}.tabs>section{min-width:100%;padding:.7rem 0;border-top:1px solid #000;display:none}.tabs>label:last-of-type{background:#3498DB;color:#FFF;font-weight:700;letter-spacing:-.1px}.tabs>section:last-of-type{display:block}html body .tabs>input:checked~section{display:none}html body .tabs>input:checked~label{position:inherited;background:inherit;border-bottom:2px solid transparent;font-weight:400;color:inherit}html body .tabs>input:checked~label:hover{border-bottom:2px solid #084999}html body .tabs>input:checked+label{border-bottom:2px solid #084999;background:#3498DB;color:#FFF;font-weight:700;letter-spacing:-.1px}html body .tabs>input:checked+label+section{display:block}select{height:28px;margin:0 1em 0 0;padding:2px 8px 2px 0!important;color:#222;font-size:12px;z-index:2}@supports ((background-position-x:100%) and ((appearance:none) or (-webkit-appearance:none) or (-moz-appearance:none))){select{appearance:none;-webkit-appearance:none;-moz-appearance:none;border:none;border-bottom:1px solid #d7d7d7;background:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCIgdmlld0JveD0iMCAwIDUxMiA1MTIiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDUxMiA1MTIiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwb2x5Z29uIHBvaW50cz0iMTI4LDE5MiAyNTYsMzIwIDM4NCwxOTIiLz48L2c+PC9zdmc+Cg==) no-repeat;background-position-x:105%;background-size:2em;background-origin:content-box;outline:0}select:focus,select:hover{border-bottom:1px solid #3498DB}}@supports (border-radius:50px){.checkbox-onoff{display:inline-block;width:40px;height:10px;background:#dcdcdc;margin:8px auto;position:relative;border-radius:50px}.checkbox-onoff label{display:block;width:20px;height:20px;position:absolute;top:-5px;cursor:pointer;border-radius:50px;box-shadow:0 3px 5px 0 rgba(0,0,0,.3);transition:all .4s ease;left:27px;background-color:#3498DB}.checkbox-onoff input[type=checkbox]{visibility:hidden}.checkbox-onoff input[type=checkbox]:checked+label{left:-5px;background:#dcdcdc}}@supports (transform:rotate(-45deg)){.checkbox{width:20px;position:relative;margin:20px auto}.checkbox label{width:20px;height:20px;cursor:pointer;position:absolute;top:0;left:0;background:#fff;border-radius:4px;box-shadow:inset 0 1px 1px #fff,0 1px 4px rgba(0,0,0,.5)}.checkbox label:after{content:'';width:9px;height:5px;position:absolute;top:4px;left:4px;border:3px solid #333;border-top:none;border-right:none;background:0 0;opacity:0;transform:rotate(-45deg)}.checkbox input[type=checkbox]{visibility:hidden}.checkbox input[type=checkbox]:checked+label:after{border-color:#3498DB;opacity:1}.checkbox input[disabled]+label{background-color:transparent!important;box-shadow:none!important;cursor:inherit}.checkbox input:not(:checked):not([readonly]):not([disabled])+label:hover::after{opacity:.5}}@media screen and (max-width:50em){.tabs>label{width:100%}}.loader,.loader:after{border-radius:50%;width:2em;height:2em}.loader{margin:1em auto;font-size:10px;position:relative;text-indent:-9999em;border-top:.5em solid rgba(0,0,0,.2);border-right:.5em solid rgba(0,0,0,.2);border-bottom:.5em solid rgba(0,0,0,.2);border-left:.5em solid rgba(255,255,255,0);-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:load8 1.2s infinite linear;animation:load8 1.2s infinite linear}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load8{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}/*! Autocomplete.js v2.6.3 | license MIT | (c) 2017, Baptiste Donaux | http://autocomplete-js.com */.autocomplete{position:absolute;max-height:0;overflow-y:hidden;text-align:left}#categories_container,.category{position:relative}.autocomplete:active,.autocomplete:focus,.autocomplete:hover{background-color:#fff}#send_search:hover,.autocomplete>ul>li.active,.autocomplete>ul>li:active,.autocomplete>ul>li:focus{background-color:#3498DB}.autocomplete:empty{display:none}.autocomplete>ul{margin:0;padding:0}.autocomplete>ul>li{cursor:pointer;padding:5px 0 5px 10px}.autocomplete>ul>li.active a:active,.autocomplete>ul>li.active a:focus,.autocomplete>ul>li.active a:hover,.autocomplete>ul>li:active a:active,.autocomplete>ul>li:active a:focus,.autocomplete>ul>li:active a:hover,.autocomplete>ul>li:focus a:active,.autocomplete>ul>li:focus a:focus,.autocomplete>ul>li:focus a:hover{text-decoration:none}.autocomplete>ul>li.locked{cursor:inherit}.autocomplete.open{display:block;background-color:#fff;border:1px solid #3498DB;max-height:500px;overflow-y:auto;z-index:100}.autocomplete.open:empty{display:none}.ion-icon,.ion-icon-big{display:inline-block;line-height:1;font-weight:400;font-style:normal;speak:none;text-decoration:inherit;text-transform:none;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;vertical-align:middle}@media screen and (max-width:50em){.autocomplete{bottom:0}.autocomplete>ul>li{padding:7px 0 7px 10px;border-bottom:1px solid #E8E7E6;text-align:left}}#main_preferences table td,.index{text-align:center}@font-face{font-family:ion;src:url(../fonts/ion.eot?ce7a0ead692560b4405a96d5b8471f51);src:url(../fonts/ion.eot?#iefix) format("embedded-opentype"),url(../fonts/ion.woff2?ce7a0ead692560b4405a96d5b8471f51) format("woff2"),url(../fonts/ion.woff?ce7a0ead692560b4405a96d5b8471f51) format("woff"),url(../fonts/ion.ttf?ce7a0ead692560b4405a96d5b8471f51) format("truetype"),url(../fonts/ion.svg?ce7a0ead692560b4405a96d5b8471f51#ion) format("svg");font-weight:400;font-style:normal}.ion-navicon-round:before{content:"\f101"}.ion-search:before{content:"\f102"}.ion-play:before{content:"\f103"}.ion-link:before{content:"\f104"}.ion-chevron-up:before{content:"\f105"}.ion-chevron-left:before{content:"\f106"}.ion-chevron-right:before{content:"\f107"}.ion-arrow-down-a:before{content:"\f108"}.ion-arrow-up-a:before{content:"\f109"}.ion-arrow-swap:before{content:"\f10a"}.ion-arrow-dropdown:before{content:"\f10b"}.ion-globe:before{content:"\f10c"}.ion-time:before{content:"\f10d"}.ion-location:before{content:"\f10e"}.ion-warning:before{content:"\f10f"}.ion-error:before{content:"\f110"}.ion-film-outline:before{content:"\f111"}.ion-music-note:before{content:"\f112"}.ion-more-vertical:before{content:"\f113"}.ion-magnet:before{content:"\f114"}.ion-close:before{content:"\f115"}.ion-icon-big{font-size:149%}.index .title{background:url(../img/searx.png) center no-repeat;width:100%;min-height:80px}.index h1{font-size:5em}.index #search{margin:0 auto;background:inherit;border:inherit}.index .search_filters{display:block;margin:1em 0}.index .category label{padding:6px 10px;border-bottom:initial!important}@media screen and (max-width:75em){div.title h1{font-size:1em}.preferences_back{clear:both}}#main_preferences form{width:100%}#main_preferences fieldset{margin:8px;border:none}#main_preferences legend{margin:0;padding:5px 0 0;display:block;float:left;width:300px}#main_preferences .value{margin:0;padding:0;float:left;width:15em}#main_preferences .description{margin:0;padding:5px 0 0;float:left;width:50%;color:#909090;font-size:90%}#main_preferences select{width:200px;font-size:inherit!important}#main_preferences table{border-collapse:collapse}#main_preferences table.cookies{width:auto}#main_preferences div.selectable_url pre,footer,main{width:100%}#main_preferences table.cookies td,#main_preferences table.cookies th{text-align:left;padding:.25em}#main_preferences table.cookies td:first-child,#main_preferences table.cookies th:first-child{padding-right:4em}#main_preferences table.cookies>tbody>tr:nth-child(even)>td,#main_preferences table.cookies>tbody>tr:nth-child(even)>th{background-color:#ececec}#main_preferences .name,#main_preferences .shortcut{text-align:left}#main_preferences .preferences_back{background:#3498DB;color:#fff;border:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;cursor:pointer;display:inline-block;margin:2px 4px;padding:.5em}#main_preferences .preferences_back a{display:block;color:#FFF}#main_preferences .preferences_back a::first-letter{text-transform:uppercase}#search{padding:0 2em;margin:0;background:#f7f7f7;border-bottom:1px solid #d7d7d7}#search_wrapper{padding:10px 0}.search_box{margin:0 12px 0 0;display:inline-flex;flex-direction:row}#clear_search,#q,#send_search{border-collapse:separate;box-sizing:border-box;margin:0;padding:2px;height:2.2em;background:#FFF;color:#222;font-size:16px;outline:0}#clear_search{display:block;width:1.8em;border-top:1px solid #3498DB;border-bottom:1px solid #3498DB;border-right:none;border-left:none;border-radius:0;z-index:10000}#clear_search:hover{color:#3498DB}#clear_search.empty *{display:none}#q::-ms-clear,#q::-webkit-search-cancel-button{display:none}#q,#send_search{display:block!important;border:1px solid #3498DB;border-radius:0;z-index:2}#q{outline:0;padding-left:8px;padding-right:0!important;border-right:none;width:40em}#send_search{border-left:none;width:2.2em}#send_search:hover{cursor:pointer;color:#ECF0F1}.no-js #send_search{width:auto!important}.search_filters{display:inline-block;vertical-align:middle}@media screen and (max-width:75em){#categories{font-size:90%;clear:both}#categories .checkbox_container{margin:auto}html.touch #main_index #categories_container,html.touch #main_results #categories_container{width:1000px;width:-moz-max-content;width:-webkit-max-content;width:max-content}html.touch #main_index #categories_container .category,html.touch #main_results #categories_container .category{display:inline-block;width:auto}html.touch #main_index #categories,html.touch #main_results #categories{width:100%;margin:0;text-align:left;overflow-x:scroll;overflow-y:hidden;-webkit-overflow-scrolling:touch}}@media screen and (max-width:50em){#search{width:100%;margin:0;padding:.1em 0 0}#search_wrapper{width:100%;margin:0 0 .7em;padding:0}.search_box{width:99%;margin:.1em;padding:0 .1em 0 0;display:flex;flex-direction:row}#q{width:auto!important;flex:1}.search_filters{display:block;margin:.5em}.language,.time_range{width:45%}.category{display:block;width:90%}.category label{border-bottom:0}}#categories{margin:0 10px 0 0;user-select:none}#categories::-webkit-scrollbar{width:0;height:0}.category{display:inline-block;margin:0 3px;padding:0}.category input{display:none}.category label{cursor:pointer;padding:4px 10px;margin:0;display:block;text-transform:capitalize;font-size:.9em;border-bottom:2px solid transparent;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body,html,main{padding:0;margin:0}.category input[type=checkbox]:focus+label{box-shadow:0 0 8px #3498DB}.category input[type=checkbox]:checked+label{background:#3498DB;color:#FFF;border-bottom:2px solid #084999}#categories_container .help{position:absolute;width:100%;bottom:-20px;overflow:hidden;opacity:0;transition:opacity 1s ease;font-size:.8em;text-position:center;background:#fff}footer p,html{font-size:.9em}#categories_container:hover .help{opacity:.8;transition:opacity 1s ease}html{font-family:arial,sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;color:#444}#main_about,#main_preferences,#main_stats{margin:3em;width:auto}footer{bottom:0;height:3em;margin:1em 0;padding:1em 0;text-align:center}#main_preferences h1,#main_stats h1{background:url(../img/searx.png) no-repeat;background-size:auto 75%;min-height:40px;margin:0 auto}#results button[type=submit],input[type=submit]{padding:.5rem;margin:2px 4px;display:inline-block;background:#3498DB;color:#FFF;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border:0;cursor:pointer}a{text-decoration:none;color:#29314d}a:visited,a:visited .highlight{color:#684898}article[data-vim-selected]{background:#f7f7f7}article[data-vim-selected]::before{position:absolute;left:1em;padding:2px;content:">";font-weight:700;color:#3498DB}article.result-images[data-vim-selected]{background:#3498DB}article.result-images[data-vim-selected]::before{display:none;content:""}.result{margin:19px 0 18px;padding:0}.result h3{font-size:1.1em;word-wrap:break-word;margin:5px 0 0;padding:0}.result h3 a{color:#084999;font-weight:400;font-size:1.1em}.result h3 a:visited{color:#684898}.result h3 a:focus,.result h3 a:hover{text-decoration:underline;border:none;-webkit-box-shadow:none;box-shadow:none;outline:0}.result .cache_link,.result .proxyfied_link{font-size:.9em!important}.result .altlink,.result .content,.result .stat,.result .url{font-size:.9em;padding:0;max-width:54em;word-wrap:break-word}.result .altlink,.result .content,.result .stat{margin:0;line-height:1.24}.result .altlink .highlight,.result .content .highlight,.result .stat .highlight{color:#000;background:inherit;font-weight:700}.result .codelines .highlight{color:inherit;background:inherit;font-weight:400}.result .url{margin:0 0 3px;color:#25a55b}.result .published_date{font-size:.8em;color:#888}.result img.thumbnail{float:left;padding:0 5px 10px 0;width:20em;min-width:20em;min-height:8em}.result img.image{float:left;padding:0 5px 10px 0;width:100px;max-height:100px;object-fit:scale-down;object-position:right top}.category-social .image{width:auto!important;min-width:48px;min-height:48px;padding:0 5px 25px 0!important}.result-videos .content{overflow:hidden}.engines{float:right;color:#888}.engines span{font-size:smaller;margin:0 .5em 0 0}.result-images,.result-images img{margin:0;padding:0;max-height:200px}.small_font{font-size:.8em}.highlight{color:#094089;background:inherit;font-weight:700}.result-images{display:inline-block;position:relative}.result-images img{float:inherit;border:none;background:#084999}.result-images span a{display:none;color:#FFF}.result-images:hover span a{display:block;position:absolute;bottom:0;right:0;padding:4px;margin:0 0 4px 4px;background-color:rgba(0,0,0,.6);font-size:.7em}.torrent_result{border-left:10px solid #d3d3d3;padding-left:3px}#answers,#backToTop,#sidebar .infobox{border:1px solid #ddd;box-shadow:0 0 5px #CCC}.torrent_result p{margin:3px;font-size:.8em}.torrent_result a{color:#084999}.torrent_result a:hover{text-decoration:underline}.torrent_result a:visited{color:#684898}#results{margin:2em 2em 20px;padding:0;width:50em}#suggestions .wrapper{display:flex;flex-flow:row wrap;justify-content:flex-end}#suggestions .wrapper form{display:inline-block;flex:1 1 50%}#answers,#corrections,#suggestions{max-width:50em}#answers input,#corrections input,#infoboxes input,#suggestions input{padding:0;margin:3px;font-size:.9em;display:inline-block;background:0 0;color:#444;cursor:pointer}#answers .infobox .url a,#answers input[type=submit],#corrections .infobox .url a,#corrections input[type=submit],#infoboxes .infobox .url a,#infoboxes input[type=submit],#suggestions .infobox .url a,#suggestions input[type=submit]{color:#084999;text-decoration:none;font-size:.9rem}#answers .infobox .url a:hover,#answers input[type=submit]:hover,#corrections .infobox .url a:hover,#corrections input[type=submit]:hover,#infoboxes .infobox .url a:hover,#infoboxes input[type=submit]:hover,#suggestions .infobox .url a:hover,#suggestions input[type=submit]:hover{text-decoration:underline}#corrections{display:flex;flex-flow:row wrap;margin:1em 0}#corrections h4,#corrections input[type=submit]{display:inline-block;margin:0 .5em 0 0}#corrections input[type=submit]::after{content:", "}#apis .title,#search_url .title,#suggestions .title{margin:2em 0 .5em;color:#444}#answers{margin:10px 8px;padding:.9em}#answers h4{display:none}#answers .answer{display:block;font-size:1.2em;font-weight:700}#answers form,#infoboxes form{min-width:210px}#sidebar{position:absolute;top:100px;left:57em;margin:0 2px 5px 5px;padding:0 2px 2px;max-width:25em;word-wrap:break-word}#sidebar .infobox{margin:10px 0;padding:.9em;font-size:.9em}#sidebar .infobox h2{margin:0 0 .5em}#sidebar .infobox img{max-width:100%;max-height:12em;display:block;margin:0;padding:0}#sidebar .infobox dl{margin:.5em 0}#sidebar .infobox dt{display:inline;margin:.5em .25em .5em 0;padding:0;font-weight:700}#sidebar .infobox dd{display:inline;margin:.5em 0;padding:0}#apis,#search_url{margin-top:8px}#sidebar .infobox input{font-size:1em}#search_url div.selectable_url pre{width:200em}#linkto_preferences{position:absolute;right:10px;top:.9em;padding:0;border:0;display:block;font-size:1.2em;color:#222}#linkto_preferences a:active *,#linkto_preferences a:hover *,#linkto_preferences a:link *,#linkto_preferences a:visited *{color:#222}#backToTop{margin:0 0 0 2em;padding:0;font-size:1em;background:#fff;position:fixed;bottom:85px;left:50em;transition:opacity .5s;opacity:0}#backToTop a{display:block;margin:0;padding:.6em}@media screen and (max-width:75em){#main_about,#main_preferences,#main_stats{margin:.5em;width:auto}#answers,#suggestions{margin-top:1em}#infoboxes{position:inherit;max-width:inherit}#infoboxes .infobox{clear:both}#infoboxes .infobox img{float:left;max-width:10em;margin:.5em .5em .5em 0}#sidebar{position:static;max-width:50em;margin:0 0 2px;padding:0;float:none;border:none;width:auto}.image_result,.image_result img,.result .thumbnail{max-width:98%}#sidebar input{border:0}#apis,#search_url{display:none}.result{border-bottom:1px solid #E8E7E6;margin:0;padding-top:8px;padding-bottom:6px}.result h3{margin:0 0 1px}.result .url span.url{display:block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;width:100%}.result .url a{float:right;padding:0 .5em}.result .engines{float:right;padding:0 0 3px}.result-images{border-bottom:none!important}}#main_results div#results.only_template_images{flex-direction:column;width:auto;display:flex}#main_results div#results.only_template_images #sidebar{position:relative;top:auto;order:2}#main_results div#results.only_template_images #urls{position:relative;order:1}#main_results div#results.only_template_images #backToTop{right:.5em;left:auto}#main_results div#results.only_template_images #pagination{position:relative;order:3}@media screen and (max-width:50em){article[data-vim-selected]::before{display:none;content:""}#linkto_preferences{display:none;postion:fixed!important;top:100px;right:0}#sidebar{margin:0 5px 2px}#corrections{margin:1em 5px}#results{margin:0;padding:0;width:initial}#backToTop{left:40em;bottom:35px}.result{padding:8px 10px 6px}.result-images{margin:0;padding:0;border:none}}@media screen and (max-width:35em){.result-videos img.thumbnail{float:none!important}.result-videos .content{overflow:inherit}}#search_submit{left:1px;right:auto}
searx/static/themes/simple/css/searx.css+1−1
@@ -1,4 +1,4 @@
1−/*! searx | 14-08-2018 | https://github.com/asciimoo/searx */
1+/*! searx | 06-08-2019 | https://github.com/asciimoo/searx */
2/*
2/*
3* searx, A privacy-respecting, hackable metasearch engine
3* searx, A privacy-respecting, hackable metasearch engine
4*
4*
searx/static/themes/simple/css/searx.min.css+1−1
@@ -1 +1 @@
1−/*! searx | 14-08-2018 | https://github.com/asciimoo/searx *//*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */button,hr,input{overflow:visible}[type=checkbox],[type=radio],legend{padding:0;box-sizing:border-box}.badge,.center{text-align:center}.badge,progress,sub,sup{vertical-align:baseline}.autocomplete>ul,.list-unstyled{list-style-type:none}.tabs>section,legend{box-sizing:border-box}#main_preferences h1 span,#main_stats h1 span,.index h1{visibility:hidden}#apis,#pagination,#pagination br,#sidebar .infobox .attributes,#sidebar .infobox .urls,#sidebar .infobox br,.result .break,footer{clear:both}html{line-height:1.15}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}.highlight pre,textarea{overflow:auto}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{color:inherit;display:table;max-width:100%;white-space:normal}.badge,.search_box{white-space:nowrap}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}.highlight .c,.highlight .cm,.highlight .ge,.highlight .sd{font-style:italic}.dialog-error:before,.dialog-modal:before,.dialog-warning:before,.ion-icon-big:before,.ion-icon:before{font-family:ion}details{display:block}summary{display:list-item}[hidden],html.js .show_if_nojs,html.no-js .hide_if_nojs,template{display:none}.highlight .hll{background-color:#ffc}.highlight .c{color:#408080}.highlight .err{border:1px solid red}.highlight .k{color:green;font-weight:700}.highlight .o{color:#666}.highlight .cm{color:#408080}.highlight .cp{color:#BC7A00}.highlight .c1,.highlight .cs{color:#408080;font-style:italic}.highlight .gd{color:#A00000}.highlight .gr{color:red}.highlight .gh{color:navy;font-weight:700}.highlight .gi{color:#00A000}.highlight .go{color:#888}.highlight .gp{color:navy;font-weight:700}.highlight .gs{font-weight:700}.highlight .gu{color:purple;font-weight:700}.highlight .gt{color:#04D}.highlight .kc,.highlight .kd,.highlight .kn{color:green;font-weight:700}.highlight .kp{color:green}.highlight .kr{color:green;font-weight:700}.highlight .kt{color:#B00040}.highlight .m{color:#666}.highlight .s{color:#BA2121}.highlight .na{color:#7D9029}.highlight .nb{color:green}.highlight .nc{color:#00F;font-weight:700}.highlight .no{color:#800}.highlight .nd{color:#A2F}.highlight .ni{color:#999;font-weight:700}.highlight .ne{color:#D2413A;font-weight:700}.highlight .nf{color:#00F}.highlight .nl{color:#A0A000}.highlight .nn{color:#00F;font-weight:700}.highlight .nt{color:green;font-weight:700}.highlight .nv{color:#19177C}.highlight .ow{color:#A2F;font-weight:700}.highlight .w{color:#bbb}.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:#666}.highlight .s2,.highlight .sb,.highlight .sc{color:#BA2121}.highlight .sd{color:#BA2121}.highlight .se{color:#B62;font-weight:700}.highlight .sh{color:#BA2121}.highlight .si{color:#B68;font-weight:700}.highlight .sx{color:green}.highlight .sr{color:#B68}.highlight .s1{color:#BA2121}.highlight .ss{color:#19177C}.highlight .bp{color:green}.highlight .vc,.highlight .vg,.highlight .vi{color:#19177C}.highlight .il{color:#666}.badge,kbd{color:#fff}.highlight .lineno{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.btn-collapse,.tabs>label,select:focus,select:hover{cursor:pointer}.highlight .lineno::selection{background:0 0}.highlight .lineno::-moz-selection{background:0 0}.right{float:right}.left{float:left}.invisible{display:none!important}.list-unstyled li{margin-top:4px;margin-bottom:4px}.danger{background-color:#fae1e1}.badge{display:inline-block;background-color:#777;min-width:10px;padding:1px 5px;border-radius:5px}.dialog-error tr,.dialog-modal tr,.dialog-warning tr{vertical-align:text-top}kbd{padding:2px 4px;margin:1px;font-size:90%;background:#000}table{width:100%}table.striped tr{border-bottom:1px solid #ececec}th{padding:.4em}td{padding:0 4px}tr:hover{background:#ececec}div.selectable_url{border:1px solid #888;padding:4px;color:#444;width:100%;display:block;margin:.1em;overflow:hidden;height:1.2em;line-height:1.2em}div.selectable_url pre{display:block;font-size:.8em;word-break:break-all;margin:.1em;-webkit-user-select:all;-moz-user-select:all;-ms-user-select:element;user-select:all}#categories,.tabs>label{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-touch-callout:none;-khtml-user-select:none}.dialog-error{position:relative;width:70%;padding:1em 1em 1em 2.7em;margin:0 8% 1em;border:1px solid #db3434;border-radius:4px;text-align:left;color:#db3434;background:#fae1e1}.dialog-error:before{position:absolute;top:.5em;left:.5em;font-size:1.5em;content:"\f110"}.dialog-error .close{float:right;position:relative;top:-3px;color:inherit;font-size:1.5em}.dialog-error ol,.dialog-error p,.dialog-error ul{margin:1px 0 0}.dialog-error table{width:auto}.dialog-error tr:hover{background:0 0}.dialog-error td{padding:0 1em 0 0}.dialog-error h4{margin-top:.3em;margin-bottom:.3em}.dialog-warning{position:relative;width:70%;padding:1em 1em 1em 2.7em;margin:0 8% 1em;border:1px solid #dbba34;border-radius:4px;text-align:left;color:#dbba34;background:#faf5e1}.dialog-warning:before{position:absolute;top:.5em;left:.5em;font-size:1.5em;content:"\f10f"}.dialog-warning .close{float:right;position:relative;top:-3px;color:inherit;font-size:1.5em}.dialog-warning ol,.dialog-warning p,.dialog-warning ul{margin:1px 0 0}.dialog-warning table{width:auto}.dialog-warning tr:hover{background:0 0}.dialog-warning td{padding:0 1em 0 0}.dialog-warning h4{margin-top:.3em;margin-bottom:.3em}.dialog-modal{width:70%;padding:1em 1em 1em 2.7em;border:1px solid #000;border-radius:4px;text-align:left;background:#fff;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:100000;margin:0 50% 0 0;box-shadow:0 0 1em}.dialog-modal:before{position:absolute;top:.5em;left:.5em;font-size:1.5em}.dialog-modal .close{float:right;position:relative;top:-3px;color:inherit;font-size:1.5em}.dialog-modal ol,.dialog-modal p,.dialog-modal ul{margin:1px 0 0}.dialog-modal table{width:auto}.dialog-modal tr:hover{background:0 0}.dialog-modal td{padding:0 1em 0 0}.dialog-modal h4{margin-top:.3em;margin-bottom:.3em}.scrollx{overflow-x:auto;overflow-y:hidden;display:block;padding:0;margin:0;border:none}.tabs .tabs>label{font-size:90%}.tabs{display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:flex;flex-wrap:wrap;width:100%;min-width:100%}.tabs>*{order:2}.tabs>input[type=radio]{display:none}.tabs>label{order:1;padding:.7em;margin:0 .7em;letter-spacing:.5px;text-transform:uppercase;border:solid #fff;border-width:0 0 2px;user-select:none}.tabs>label:hover,.tabs>label:last-of-type{border-bottom:2px solid #084999}.tabs>section{min-width:100%;padding:.7rem 0;border-top:1px solid #000;display:none}.tabs>label:last-of-type{background:#3498DB;color:#FFF;font-weight:700;letter-spacing:-.1px}.tabs>section:last-of-type{display:block}html body .tabs>input:checked~section{display:none}html body .tabs>input:checked~label{position:inherited;background:inherit;border-bottom:2px solid transparent;font-weight:400;color:inherit}html body .tabs>input:checked~label:hover{border-bottom:2px solid #084999}html body .tabs>input:checked+label{border-bottom:2px solid #084999;background:#3498DB;color:#FFF;font-weight:700;letter-spacing:-.1px}html body .tabs>input:checked+label+section{display:block}select{height:28px;margin:0 1em 0 0;padding:2px 8px 2px 0!important;color:#222;font-size:12px;z-index:2}@supports ((background-position-x:100%) and ((appearance:none) or (-webkit-appearance:none) or (-moz-appearance:none))){select{appearance:none;-webkit-appearance:none;-moz-appearance:none;border:none;border-bottom:1px solid #d7d7d7;background:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCIgdmlld0JveD0iMCAwIDUxMiA1MTIiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDUxMiA1MTIiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwb2x5Z29uIHBvaW50cz0iMTI4LDE5MiAyNTYsMzIwIDM4NCwxOTIiLz48L2c+PC9zdmc+Cg==) no-repeat;background-position-x:105%;background-size:2em;background-origin:content-box;outline:0}select:focus,select:hover{border-bottom:1px solid #3498DB}}@supports (border-radius:50px){.checkbox-onoff{display:inline-block;width:40px;height:10px;background:#dcdcdc;margin:8px auto;position:relative;border-radius:50px}.checkbox-onoff label{display:block;width:20px;height:20px;position:absolute;top:-5px;cursor:pointer;border-radius:50px;box-shadow:0 3px 5px 0 rgba(0,0,0,.3);transition:all .4s ease;left:27px;background-color:#3498DB}.checkbox-onoff input[type=checkbox]{visibility:hidden}.checkbox-onoff input[type=checkbox]:checked+label{left:-5px;background:#dcdcdc}}@supports (transform:rotate(-45deg)){.checkbox{width:20px;position:relative;margin:20px auto}.checkbox label{width:20px;height:20px;cursor:pointer;position:absolute;top:0;left:0;background:#fff;border-radius:4px;box-shadow:inset 0 1px 1px #fff,0 1px 4px rgba(0,0,0,.5)}.checkbox label:after{content:'';width:9px;height:5px;position:absolute;top:4px;left:4px;border:3px solid #333;border-top:none;border-right:none;background:0 0;opacity:0;transform:rotate(-45deg)}.checkbox input[type=checkbox]{visibility:hidden}.checkbox input[type=checkbox]:checked+label:after{border-color:#3498DB;opacity:1}.checkbox input[disabled]+label{background-color:transparent!important;box-shadow:none!important;cursor:inherit}.checkbox input:not(:checked):not([readonly]):not([disabled])+label:hover::after{opacity:.5}}@media screen and (max-width:50em){.tabs>label{width:100%}}.loader,.loader:after{border-radius:50%;width:2em;height:2em}.loader{margin:1em auto;font-size:10px;position:relative;text-indent:-9999em;border-top:.5em solid rgba(0,0,0,.2);border-right:.5em solid rgba(0,0,0,.2);border-bottom:.5em solid rgba(0,0,0,.2);border-left:.5em solid rgba(255,255,255,0);-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:load8 1.2s infinite linear;animation:load8 1.2s infinite linear}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load8{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}/*! Autocomplete.js v2.6.3 | license MIT | (c) 2017, Baptiste Donaux | http://autocomplete-js.com */.autocomplete{position:absolute;max-height:0;overflow-y:hidden;text-align:left}#categories_container,.category{position:relative}.autocomplete:active,.autocomplete:focus,.autocomplete:hover{background-color:#fff}#send_search:hover,.autocomplete>ul>li.active,.autocomplete>ul>li:active,.autocomplete>ul>li:focus{background-color:#3498DB}.autocomplete:empty{display:none}.autocomplete>ul{margin:0;padding:0}.autocomplete>ul>li{cursor:pointer;padding:5px 0 5px 10px}.autocomplete>ul>li.active a:active,.autocomplete>ul>li.active a:focus,.autocomplete>ul>li.active a:hover,.autocomplete>ul>li:active a:active,.autocomplete>ul>li:active a:focus,.autocomplete>ul>li:active a:hover,.autocomplete>ul>li:focus a:active,.autocomplete>ul>li:focus a:focus,.autocomplete>ul>li:focus a:hover{text-decoration:none}.autocomplete>ul>li.locked{cursor:inherit}.autocomplete.open{display:block;background-color:#fff;border:1px solid #3498DB;max-height:500px;overflow-y:auto;z-index:100}.autocomplete.open:empty{display:none}.ion-icon,.ion-icon-big{display:inline-block;line-height:1;font-weight:400;font-style:normal;speak:none;text-decoration:inherit;text-transform:none;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;vertical-align:middle}@media screen and (max-width:50em){.autocomplete{bottom:0}.autocomplete>ul>li{padding:7px 0 7px 10px;border-bottom:1px solid #E8E7E6;text-align:left}}#main_preferences table td,.index{text-align:center}@font-face{font-family:ion;src:url(../fonts/ion.eot?ce7a0ead692560b4405a96d5b8471f51);src:url(../fonts/ion.eot?#iefix) format("embedded-opentype"),url(../fonts/ion.woff2?ce7a0ead692560b4405a96d5b8471f51) format("woff2"),url(../fonts/ion.woff?ce7a0ead692560b4405a96d5b8471f51) format("woff"),url(../fonts/ion.ttf?ce7a0ead692560b4405a96d5b8471f51) format("truetype"),url(../fonts/ion.svg?ce7a0ead692560b4405a96d5b8471f51#ion) format("svg");font-weight:400;font-style:normal}.ion-navicon-round:before{content:"\f101"}.ion-search:before{content:"\f102"}.ion-play:before{content:"\f103"}.ion-link:before{content:"\f104"}.ion-chevron-up:before{content:"\f105"}.ion-chevron-left:before{content:"\f106"}.ion-chevron-right:before{content:"\f107"}.ion-arrow-down-a:before{content:"\f108"}.ion-arrow-up-a:before{content:"\f109"}.ion-arrow-swap:before{content:"\f10a"}.ion-arrow-dropdown:before{content:"\f10b"}.ion-globe:before{content:"\f10c"}.ion-time:before{content:"\f10d"}.ion-location:before{content:"\f10e"}.ion-warning:before{content:"\f10f"}.ion-error:before{content:"\f110"}.ion-film-outline:before{content:"\f111"}.ion-music-note:before{content:"\f112"}.ion-more-vertical:before{content:"\f113"}.ion-magnet:before{content:"\f114"}.ion-close:before{content:"\f115"}.ion-icon-big{font-size:149%}.index .title{background:url(../img/searx.png) center no-repeat;width:100%;min-height:80px}.index h1{font-size:5em}.index #search{margin:0 auto;background:inherit;border:inherit}.index .search_filters{display:block;margin:1em 0}.index .category label{padding:6px 10px;border-bottom:initial!important}@media screen and (max-width:75em){div.title h1{font-size:1em}.preferences_back{clear:both}}#main_preferences form{width:100%}#main_preferences fieldset{margin:8px;border:none}#main_preferences legend{margin:0;padding:5px 0 0;display:block;float:left;width:300px}#main_preferences .value{margin:0;padding:0;float:left;width:15em}#main_preferences .description{margin:0;padding:5px 0 0;float:left;width:50%;color:#909090;font-size:90%}#main_preferences select{width:200px;font-size:inherit!important}#main_preferences table{border-collapse:collapse}#main_preferences table.cookies{width:auto}#main_preferences div.selectable_url pre,footer,main{width:100%}#main_preferences table.cookies td,#main_preferences table.cookies th{text-align:left;padding:.25em}#main_preferences table.cookies td:first-child,#main_preferences table.cookies th:first-child{padding-right:4em}#main_preferences table.cookies>tbody>tr:nth-child(even)>td,#main_preferences table.cookies>tbody>tr:nth-child(even)>th{background-color:#ececec}#main_preferences .name,#main_preferences .shortcut{text-align:left}#main_preferences .preferences_back{background:#3498DB;color:#fff;border:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;cursor:pointer;display:inline-block;margin:2px 4px;padding:.5em}#main_preferences .preferences_back a{display:block;color:#FFF}#main_preferences .preferences_back a::first-letter{text-transform:uppercase}#search{padding:0 2em;margin:0;background:#f7f7f7;border-bottom:1px solid #d7d7d7}#search_wrapper{padding:10px 0}.search_box{margin:0 12px 0 0;display:inline-flex;flex-direction:row}#clear_search,#q,#send_search{border-collapse:separate;box-sizing:border-box;margin:0;padding:2px;height:2.2em;background:#FFF;color:#222;font-size:16px;outline:0}#clear_search{display:block;width:1.8em;border-top:1px solid #3498DB;border-bottom:1px solid #3498DB;border-right:none;border-left:none;border-radius:0;z-index:10000}#clear_search:hover{color:#3498DB}#clear_search.empty *{display:none}#q::-ms-clear,#q::-webkit-search-cancel-button{display:none}#q,#send_search{display:block!important;border:1px solid #3498DB;border-radius:0;z-index:2}#q{outline:0;padding-left:8px;padding-right:0!important;border-right:none;width:40em}#send_search{border-left:none;width:2.2em}#send_search:hover{cursor:pointer;color:#ECF0F1}.no-js #send_search{width:auto!important}.search_filters{display:inline-block;vertical-align:middle}@media screen and (max-width:75em){#categories{font-size:90%;clear:both}#categories .checkbox_container{margin:auto}html.touch #main_index #categories_container,html.touch #main_results #categories_container{width:1000px;width:-moz-max-content;width:-webkit-max-content;width:max-content}html.touch #main_index #categories_container .category,html.touch #main_results #categories_container .category{display:inline-block;width:auto}html.touch #main_index #categories,html.touch #main_results #categories{width:100%;margin:0;text-align:left;overflow-x:scroll;overflow-y:hidden;-webkit-overflow-scrolling:touch}}@media screen and (max-width:50em){#search{width:100%;margin:0;padding:.1em 0 0}#search_wrapper{width:100%;margin:0 0 .7em;padding:0}.search_box{width:99%;margin:.1em;padding:0 .1em 0 0;display:flex;flex-direction:row}#q{width:auto!important;flex:1}.search_filters{display:block;margin:.5em}.language,.time_range{width:45%}.category{display:block;width:90%}.category label{border-bottom:0}}#categories{margin:0 10px 0 0;user-select:none}#categories::-webkit-scrollbar{width:0;height:0}.category{display:inline-block;margin:0 3px;padding:0}.category input{display:none}.category label{cursor:pointer;padding:4px 10px;margin:0;display:block;text-transform:capitalize;font-size:.9em;border-bottom:2px solid transparent;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body,html,main{padding:0;margin:0}.category input[type=checkbox]:focus+label{box-shadow:0 0 8px #3498DB}.category input[type=checkbox]:checked+label{background:#3498DB;color:#FFF;border-bottom:2px solid #084999}#categories_container .help{position:absolute;width:100%;bottom:-20px;overflow:hidden;opacity:0;transition:opacity 1s ease;font-size:.8em;text-position:center;background:#fff}footer p,html{font-size:.9em}#categories_container:hover .help{opacity:.8;transition:opacity 1s ease}html{font-family:arial,sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;color:#444}#main_about,#main_preferences,#main_stats{margin:3em;width:auto}footer{bottom:0;height:3em;margin:1em 0;padding:1em 0;text-align:center}#main_preferences h1,#main_stats h1{background:url(../img/searx.png) no-repeat;background-size:auto 75%;min-height:40px;margin:0 auto}#results button[type=submit],input[type=submit]{padding:.5rem;margin:2px 4px;display:inline-block;background:#3498DB;color:#FFF;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border:0;cursor:pointer}a{text-decoration:none;color:#29314d}a:visited,a:visited .highlight{color:#684898}article[data-vim-selected]{background:#f7f7f7}article[data-vim-selected]::before{position:absolute;left:1em;padding:2px;content:">";font-weight:700;color:#3498DB}article.result-images[data-vim-selected]{background:#3498DB}article.result-images[data-vim-selected]::before{display:none;content:""}.result{margin:19px 0 18px;padding:0}.result h3{font-size:1.1em;word-wrap:break-word;margin:5px 0 0;padding:0}.result h3 a{color:#084999;font-weight:400;font-size:1.1em}.result h3 a:visited{color:#684898}.result h3 a:focus,.result h3 a:hover{text-decoration:underline;border:none;-webkit-box-shadow:none;box-shadow:none;outline:0}.result .cache_link,.result .proxyfied_link{font-size:.9em!important}.result .altlink,.result .content,.result .stat,.result .url{font-size:.9em;padding:0;max-width:54em;word-wrap:break-word}.result .altlink,.result .content,.result .stat{margin:0;line-height:1.24}.result .altlink .highlight,.result .content .highlight,.result .stat .highlight{color:#000;background:inherit;font-weight:700}.result .codelines .highlight{color:inherit;background:inherit;font-weight:400}.result .url{margin:0 0 3px;color:#25a55b}.result .published_date{font-size:.8em;color:#888}.result img.thumbnail{float:left;padding:0 5px 10px 0;width:20em;min-width:20em;min-height:8em}.result img.image{float:left;padding:0 5px 10px 0;width:100px;max-height:100px;object-fit:scale-down;object-position:right top}.category-social .image{width:auto!important;min-width:48px;min-height:48px;padding:0 5px 25px 0!important}.result-videos .content{overflow:hidden}.engines{float:right;color:#888}.engines span{font-size:smaller;margin:0 .5em 0 0}.result-images,.result-images img{margin:0;padding:0;max-height:200px}.small_font{font-size:.8em}.highlight{color:#094089;background:inherit;font-weight:700}.result-images{display:inline-block;position:relative}.result-images img{float:inherit;border:none;background:#084999}.result-images span a{display:none;color:#FFF}.result-images:hover span a{display:block;position:absolute;bottom:0;right:0;padding:4px;margin:0 0 4px 4px;background-color:rgba(0,0,0,.6);font-size:.7em}.torrent_result{border-left:10px solid #d3d3d3;padding-left:3px}#answers,#backToTop,#sidebar .infobox{border:1px solid #ddd;box-shadow:0 0 5px #CCC}.torrent_result p{margin:3px;font-size:.8em}.torrent_result a{color:#084999}.torrent_result a:hover{text-decoration:underline}.torrent_result a:visited{color:#684898}#results{margin:2em 2em 20px;padding:0;width:50em}#suggestions .wrapper{display:flex;flex-flow:row wrap;justify-content:flex-end}#suggestions .wrapper form{display:inline-block;flex:1 1 50%}#answers,#corrections,#suggestions{max-width:50em}#answers input,#corrections input,#infoboxes input,#suggestions input{padding:0;margin:3px;font-size:.9em;display:inline-block;background:0 0;color:#444;cursor:pointer}#answers .infobox .url a,#answers input[type=submit],#corrections .infobox .url a,#corrections input[type=submit],#infoboxes .infobox .url a,#infoboxes input[type=submit],#suggestions .infobox .url a,#suggestions input[type=submit]{color:#084999;text-decoration:none;font-size:.9rem}#answers .infobox .url a:hover,#answers input[type=submit]:hover,#corrections .infobox .url a:hover,#corrections input[type=submit]:hover,#infoboxes .infobox .url a:hover,#infoboxes input[type=submit]:hover,#suggestions .infobox .url a:hover,#suggestions input[type=submit]:hover{text-decoration:underline}#corrections{display:flex;flex-flow:row wrap;margin:1em 0}#corrections h4,#corrections input[type=submit]{display:inline-block;margin:0 .5em 0 0}#corrections input[type=submit]::after{content:", "}#apis .title,#search_url .title,#suggestions .title{margin:2em 0 .5em;color:#444}#answers{margin:10px 8px;padding:.9em}#answers h4{display:none}#answers .answer{display:block;font-size:1.2em;font-weight:700}#answers form,#infoboxes form{min-width:210px}#sidebar{position:absolute;top:100px;left:57em;margin:0 2px 5px 5px;padding:0 2px 2px;max-width:25em;word-wrap:break-word}#sidebar .infobox{margin:10px 0;padding:.9em;font-size:.9em}#sidebar .infobox h2{margin:0 0 .5em}#sidebar .infobox img{max-width:100%;max-height:12em;display:block;margin:0;padding:0}#sidebar .infobox dl{margin:.5em 0}#sidebar .infobox dt{display:inline;margin:.5em .25em .5em 0;padding:0;font-weight:700}#sidebar .infobox dd{display:inline;margin:.5em 0;padding:0}#apis,#search_url{margin-top:8px}#sidebar .infobox input{font-size:1em}#search_url div.selectable_url pre{width:200em}#linkto_preferences{position:absolute;right:10px;top:.9em;padding:0;border:0;display:block;font-size:1.2em;color:#222}#linkto_preferences a:active *,#linkto_preferences a:hover *,#linkto_preferences a:link *,#linkto_preferences a:visited *{color:#222}#backToTop{margin:0 0 0 2em;padding:0;font-size:1em;background:#fff;position:fixed;bottom:85px;left:50em;transition:opacity .5s;opacity:0}#backToTop a{display:block;margin:0;padding:.6em}@media screen and (max-width:75em){#main_about,#main_preferences,#main_stats{margin:.5em;width:auto}#answers,#suggestions{margin-top:1em}#infoboxes{position:inherit;max-width:inherit}#infoboxes .infobox{clear:both}#infoboxes .infobox img{float:left;max-width:10em;margin:.5em .5em .5em 0}#sidebar{position:static;max-width:50em;margin:0 0 2px;padding:0;float:none;border:none;width:auto}.image_result,.image_result img,.result .thumbnail{max-width:98%}#sidebar input{border:0}#apis,#search_url{display:none}.result{border-bottom:1px solid #E8E7E6;margin:0;padding-top:8px;padding-bottom:6px}.result h3{margin:0 0 1px}.result .url span.url{display:block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;width:100%}.result .url a{float:right;padding:0 .5em}.result .engines{float:right;padding:0 0 3px}.result-images{border-bottom:none!important}}#main_results div#results.only_template_images{flex-direction:column;width:auto;display:flex}#main_results div#results.only_template_images #sidebar{position:relative;top:auto;order:2}#main_results div#results.only_template_images #urls{position:relative;order:1}#main_results div#results.only_template_images #backToTop{right:.5em;left:auto}#main_results div#results.only_template_images #pagination{position:relative;order:3}@media screen and (max-width:50em){article[data-vim-selected]::before{display:none;content:""}#linkto_preferences{display:none;postion:fixed!important;top:100px;right:0}#sidebar{margin:0 5px 2px}#corrections{margin:1em 5px}#results{margin:0;padding:0;width:initial}#backToTop{left:40em;bottom:35px}.result{padding:8px 10px 6px}.result-images{margin:0;padding:0;border:none}}@media screen and (max-width:35em){.result-videos img.thumbnail{float:none!important}.result-videos .content{overflow:inherit}}
1+/*! searx | 06-08-2019 | https://github.com/asciimoo/searx *//*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */button,hr,input{overflow:visible}[type=checkbox],[type=radio],legend{padding:0;box-sizing:border-box}.badge,.center{text-align:center}.badge,progress,sub,sup{vertical-align:baseline}.autocomplete>ul,.list-unstyled{list-style-type:none}.tabs>section,legend{box-sizing:border-box}#main_preferences h1 span,#main_stats h1 span,.index h1{visibility:hidden}#apis,#pagination,#pagination br,#sidebar .infobox .attributes,#sidebar .infobox .urls,#sidebar .infobox br,.result .break,footer{clear:both}html{line-height:1.15}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}.highlight pre,textarea{overflow:auto}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{color:inherit;display:table;max-width:100%;white-space:normal}.badge,.search_box{white-space:nowrap}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}.highlight .c,.highlight .cm,.highlight .ge,.highlight .sd{font-style:italic}.dialog-error:before,.dialog-modal:before,.dialog-warning:before,.ion-icon-big:before,.ion-icon:before{font-family:ion}details{display:block}summary{display:list-item}[hidden],html.js .show_if_nojs,html.no-js .hide_if_nojs,template{display:none}.highlight .hll{background-color:#ffc}.highlight .c{color:#408080}.highlight .err{border:1px solid red}.highlight .k{color:green;font-weight:700}.highlight .o{color:#666}.highlight .cm{color:#408080}.highlight .cp{color:#BC7A00}.highlight .c1,.highlight .cs{color:#408080;font-style:italic}.highlight .gd{color:#A00000}.highlight .gr{color:red}.highlight .gh{color:navy;font-weight:700}.highlight .gi{color:#00A000}.highlight .go{color:#888}.highlight .gp{color:navy;font-weight:700}.highlight .gs{font-weight:700}.highlight .gu{color:purple;font-weight:700}.highlight .gt{color:#04D}.highlight .kc,.highlight .kd,.highlight .kn{color:green;font-weight:700}.highlight .kp{color:green}.highlight .kr{color:green;font-weight:700}.highlight .kt{color:#B00040}.highlight .m{color:#666}.highlight .s{color:#BA2121}.highlight .na{color:#7D9029}.highlight .nb{color:green}.highlight .nc{color:#00F;font-weight:700}.highlight .no{color:#800}.highlight .nd{color:#A2F}.highlight .ni{color:#999;font-weight:700}.highlight .ne{color:#D2413A;font-weight:700}.highlight .nf{color:#00F}.highlight .nl{color:#A0A000}.highlight .nn{color:#00F;font-weight:700}.highlight .nt{color:green;font-weight:700}.highlight .nv{color:#19177C}.highlight .ow{color:#A2F;font-weight:700}.highlight .w{color:#bbb}.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:#666}.highlight .s2,.highlight .sb,.highlight .sc{color:#BA2121}.highlight .sd{color:#BA2121}.highlight .se{color:#B62;font-weight:700}.highlight .sh{color:#BA2121}.highlight .si{color:#B68;font-weight:700}.highlight .sx{color:green}.highlight .sr{color:#B68}.highlight .s1{color:#BA2121}.highlight .ss{color:#19177C}.highlight .bp{color:green}.highlight .vc,.highlight .vg,.highlight .vi{color:#19177C}.highlight .il{color:#666}.badge,kbd{color:#fff}.highlight .lineno{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.btn-collapse,.tabs>label,select:focus,select:hover{cursor:pointer}.highlight .lineno::selection{background:0 0}.highlight .lineno::-moz-selection{background:0 0}.right{float:right}.left{float:left}.invisible{display:none!important}.list-unstyled li{margin-top:4px;margin-bottom:4px}.danger{background-color:#fae1e1}.badge{display:inline-block;background-color:#777;min-width:10px;padding:1px 5px;border-radius:5px}.dialog-error tr,.dialog-modal tr,.dialog-warning tr{vertical-align:text-top}kbd{padding:2px 4px;margin:1px;font-size:90%;background:#000}table{width:100%}table.striped tr{border-bottom:1px solid #ececec}th{padding:.4em}td{padding:0 4px}tr:hover{background:#ececec}div.selectable_url{border:1px solid #888;padding:4px;color:#444;width:100%;display:block;margin:.1em;overflow:hidden;height:1.2em;line-height:1.2em}div.selectable_url pre{display:block;font-size:.8em;word-break:break-all;margin:.1em;-webkit-user-select:all;-moz-user-select:all;-ms-user-select:element;user-select:all}#categories,.tabs>label{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-touch-callout:none;-khtml-user-select:none}.dialog-error{position:relative;width:70%;padding:1em 1em 1em 2.7em;margin:0 8% 1em;border:1px solid #db3434;border-radius:4px;text-align:left;color:#db3434;background:#fae1e1}.dialog-error:before{position:absolute;top:.5em;left:.5em;font-size:1.5em;content:"\f110"}.dialog-error .close{float:right;position:relative;top:-3px;color:inherit;font-size:1.5em}.dialog-error ol,.dialog-error p,.dialog-error ul{margin:1px 0 0}.dialog-error table{width:auto}.dialog-error tr:hover{background:0 0}.dialog-error td{padding:0 1em 0 0}.dialog-error h4{margin-top:.3em;margin-bottom:.3em}.dialog-warning{position:relative;width:70%;padding:1em 1em 1em 2.7em;margin:0 8% 1em;border:1px solid #dbba34;border-radius:4px;text-align:left;color:#dbba34;background:#faf5e1}.dialog-warning:before{position:absolute;top:.5em;left:.5em;font-size:1.5em;content:"\f10f"}.dialog-warning .close{float:right;position:relative;top:-3px;color:inherit;font-size:1.5em}.dialog-warning ol,.dialog-warning p,.dialog-warning ul{margin:1px 0 0}.dialog-warning table{width:auto}.dialog-warning tr:hover{background:0 0}.dialog-warning td{padding:0 1em 0 0}.dialog-warning h4{margin-top:.3em;margin-bottom:.3em}.dialog-modal{width:70%;padding:1em 1em 1em 2.7em;border:1px solid #000;border-radius:4px;text-align:left;background:#fff;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:100000;margin:0 50% 0 0;box-shadow:0 0 1em}.dialog-modal:before{position:absolute;top:.5em;left:.5em;font-size:1.5em}.dialog-modal .close{float:right;position:relative;top:-3px;color:inherit;font-size:1.5em}.dialog-modal ol,.dialog-modal p,.dialog-modal ul{margin:1px 0 0}.dialog-modal table{width:auto}.dialog-modal tr:hover{background:0 0}.dialog-modal td{padding:0 1em 0 0}.dialog-modal h4{margin-top:.3em;margin-bottom:.3em}.scrollx{overflow-x:auto;overflow-y:hidden;display:block;padding:0;margin:0;border:none}.tabs .tabs>label{font-size:90%}.tabs{display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:flex;flex-wrap:wrap;width:100%;min-width:100%}.tabs>*{order:2}.tabs>input[type=radio]{display:none}.tabs>label{order:1;padding:.7em;margin:0 .7em;letter-spacing:.5px;text-transform:uppercase;border:solid #fff;border-width:0 0 2px;user-select:none}.tabs>label:hover,.tabs>label:last-of-type{border-bottom:2px solid #084999}.tabs>section{min-width:100%;padding:.7rem 0;border-top:1px solid #000;display:none}.tabs>label:last-of-type{background:#3498DB;color:#FFF;font-weight:700;letter-spacing:-.1px}.tabs>section:last-of-type{display:block}html body .tabs>input:checked~section{display:none}html body .tabs>input:checked~label{position:inherited;background:inherit;border-bottom:2px solid transparent;font-weight:400;color:inherit}html body .tabs>input:checked~label:hover{border-bottom:2px solid #084999}html body .tabs>input:checked+label{border-bottom:2px solid #084999;background:#3498DB;color:#FFF;font-weight:700;letter-spacing:-.1px}html body .tabs>input:checked+label+section{display:block}select{height:28px;margin:0 1em 0 0;padding:2px 8px 2px 0!important;color:#222;font-size:12px;z-index:2}@supports ((background-position-x:100%) and ((appearance:none) or (-webkit-appearance:none) or (-moz-appearance:none))){select{appearance:none;-webkit-appearance:none;-moz-appearance:none;border:none;border-bottom:1px solid #d7d7d7;background:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCIgdmlld0JveD0iMCAwIDUxMiA1MTIiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDUxMiA1MTIiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwb2x5Z29uIHBvaW50cz0iMTI4LDE5MiAyNTYsMzIwIDM4NCwxOTIiLz48L2c+PC9zdmc+Cg==) no-repeat;background-position-x:105%;background-size:2em;background-origin:content-box;outline:0}select:focus,select:hover{border-bottom:1px solid #3498DB}}@supports (border-radius:50px){.checkbox-onoff{display:inline-block;width:40px;height:10px;background:#dcdcdc;margin:8px auto;position:relative;border-radius:50px}.checkbox-onoff label{display:block;width:20px;height:20px;position:absolute;top:-5px;cursor:pointer;border-radius:50px;box-shadow:0 3px 5px 0 rgba(0,0,0,.3);transition:all .4s ease;left:27px;background-color:#3498DB}.checkbox-onoff input[type=checkbox]{visibility:hidden}.checkbox-onoff input[type=checkbox]:checked+label{left:-5px;background:#dcdcdc}}@supports (transform:rotate(-45deg)){.checkbox{width:20px;position:relative;margin:20px auto}.checkbox label{width:20px;height:20px;cursor:pointer;position:absolute;top:0;left:0;background:#fff;border-radius:4px;box-shadow:inset 0 1px 1px #fff,0 1px 4px rgba(0,0,0,.5)}.checkbox label:after{content:'';width:9px;height:5px;position:absolute;top:4px;left:4px;border:3px solid #333;border-top:none;border-right:none;background:0 0;opacity:0;transform:rotate(-45deg)}.checkbox input[type=checkbox]{visibility:hidden}.checkbox input[type=checkbox]:checked+label:after{border-color:#3498DB;opacity:1}.checkbox input[disabled]+label{background-color:transparent!important;box-shadow:none!important;cursor:inherit}.checkbox input:not(:checked):not([readonly]):not([disabled])+label:hover::after{opacity:.5}}@media screen and (max-width:50em){.tabs>label{width:100%}}.loader,.loader:after{border-radius:50%;width:2em;height:2em}.loader{margin:1em auto;font-size:10px;position:relative;text-indent:-9999em;border-top:.5em solid rgba(0,0,0,.2);border-right:.5em solid rgba(0,0,0,.2);border-bottom:.5em solid rgba(0,0,0,.2);border-left:.5em solid rgba(255,255,255,0);-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:load8 1.2s infinite linear;animation:load8 1.2s infinite linear}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load8{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}/*! Autocomplete.js v2.6.3 | license MIT | (c) 2017, Baptiste Donaux | http://autocomplete-js.com */.autocomplete{position:absolute;max-height:0;overflow-y:hidden;text-align:left}#categories_container,.category{position:relative}.autocomplete:active,.autocomplete:focus,.autocomplete:hover{background-color:#fff}#send_search:hover,.autocomplete>ul>li.active,.autocomplete>ul>li:active,.autocomplete>ul>li:focus{background-color:#3498DB}.autocomplete:empty{display:none}.autocomplete>ul{margin:0;padding:0}.autocomplete>ul>li{cursor:pointer;padding:5px 0 5px 10px}.autocomplete>ul>li.active a:active,.autocomplete>ul>li.active a:focus,.autocomplete>ul>li.active a:hover,.autocomplete>ul>li:active a:active,.autocomplete>ul>li:active a:focus,.autocomplete>ul>li:active a:hover,.autocomplete>ul>li:focus a:active,.autocomplete>ul>li:focus a:focus,.autocomplete>ul>li:focus a:hover{text-decoration:none}.autocomplete>ul>li.locked{cursor:inherit}.autocomplete.open{display:block;background-color:#fff;border:1px solid #3498DB;max-height:500px;overflow-y:auto;z-index:100}.autocomplete.open:empty{display:none}.ion-icon,.ion-icon-big{display:inline-block;line-height:1;font-weight:400;font-style:normal;speak:none;text-decoration:inherit;text-transform:none;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;vertical-align:middle}@media screen and (max-width:50em){.autocomplete{bottom:0}.autocomplete>ul>li{padding:7px 0 7px 10px;border-bottom:1px solid #E8E7E6;text-align:left}}#main_preferences table td,.index{text-align:center}@font-face{font-family:ion;src:url(../fonts/ion.eot?ce7a0ead692560b4405a96d5b8471f51);src:url(../fonts/ion.eot?#iefix) format("embedded-opentype"),url(../fonts/ion.woff2?ce7a0ead692560b4405a96d5b8471f51) format("woff2"),url(../fonts/ion.woff?ce7a0ead692560b4405a96d5b8471f51) format("woff"),url(../fonts/ion.ttf?ce7a0ead692560b4405a96d5b8471f51) format("truetype"),url(../fonts/ion.svg?ce7a0ead692560b4405a96d5b8471f51#ion) format("svg");font-weight:400;font-style:normal}.ion-navicon-round:before{content:"\f101"}.ion-search:before{content:"\f102"}.ion-play:before{content:"\f103"}.ion-link:before{content:"\f104"}.ion-chevron-up:before{content:"\f105"}.ion-chevron-left:before{content:"\f106"}.ion-chevron-right:before{content:"\f107"}.ion-arrow-down-a:before{content:"\f108"}.ion-arrow-up-a:before{content:"\f109"}.ion-arrow-swap:before{content:"\f10a"}.ion-arrow-dropdown:before{content:"\f10b"}.ion-globe:before{content:"\f10c"}.ion-time:before{content:"\f10d"}.ion-location:before{content:"\f10e"}.ion-warning:before{content:"\f10f"}.ion-error:before{content:"\f110"}.ion-film-outline:before{content:"\f111"}.ion-music-note:before{content:"\f112"}.ion-more-vertical:before{content:"\f113"}.ion-magnet:before{content:"\f114"}.ion-close:before{content:"\f115"}.ion-icon-big{font-size:149%}.index .title{background:url(../img/searx.png) center no-repeat;width:100%;min-height:80px}.index h1{font-size:5em}.index #search{margin:0 auto;background:inherit;border:inherit}.index .search_filters{display:block;margin:1em 0}.index .category label{padding:6px 10px;border-bottom:initial!important}@media screen and (max-width:75em){div.title h1{font-size:1em}.preferences_back{clear:both}}#main_preferences form{width:100%}#main_preferences fieldset{margin:8px;border:none}#main_preferences legend{margin:0;padding:5px 0 0;display:block;float:left;width:300px}#main_preferences .value{margin:0;padding:0;float:left;width:15em}#main_preferences .description{margin:0;padding:5px 0 0;float:left;width:50%;color:#909090;font-size:90%}#main_preferences select{width:200px;font-size:inherit!important}#main_preferences table{border-collapse:collapse}#main_preferences table.cookies{width:auto}#main_preferences div.selectable_url pre,footer,main{width:100%}#main_preferences table.cookies td,#main_preferences table.cookies th{text-align:left;padding:.25em}#main_preferences table.cookies td:first-child,#main_preferences table.cookies th:first-child{padding-right:4em}#main_preferences table.cookies>tbody>tr:nth-child(even)>td,#main_preferences table.cookies>tbody>tr:nth-child(even)>th{background-color:#ececec}#main_preferences .name,#main_preferences .shortcut{text-align:left}#main_preferences .preferences_back{background:#3498DB;color:#fff;border:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;cursor:pointer;display:inline-block;margin:2px 4px;padding:.5em}#main_preferences .preferences_back a{display:block;color:#FFF}#main_preferences .preferences_back a::first-letter{text-transform:uppercase}#search{padding:0 2em;margin:0;background:#f7f7f7;border-bottom:1px solid #d7d7d7}#search_wrapper{padding:10px 0}.search_box{margin:0 12px 0 0;display:inline-flex;flex-direction:row}#clear_search,#q,#send_search{border-collapse:separate;box-sizing:border-box;margin:0;padding:2px;height:2.2em;background:#FFF;color:#222;font-size:16px;outline:0}#clear_search{display:block;width:1.8em;border-top:1px solid #3498DB;border-bottom:1px solid #3498DB;border-right:none;border-left:none;border-radius:0;z-index:10000}#clear_search:hover{color:#3498DB}#clear_search.empty *{display:none}#q::-ms-clear,#q::-webkit-search-cancel-button{display:none}#q,#send_search{display:block!important;border:1px solid #3498DB;border-radius:0;z-index:2}#q{outline:0;padding-left:8px;padding-right:0!important;border-right:none;width:40em}#send_search{border-left:none;width:2.2em}#send_search:hover{cursor:pointer;color:#ECF0F1}.no-js #send_search{width:auto!important}.search_filters{display:inline-block;vertical-align:middle}@media screen and (max-width:75em){#categories{font-size:90%;clear:both}#categories .checkbox_container{margin:auto}html.touch #main_index #categories_container,html.touch #main_results #categories_container{width:1000px;width:-moz-max-content;width:-webkit-max-content;width:max-content}html.touch #main_index #categories_container .category,html.touch #main_results #categories_container .category{display:inline-block;width:auto}html.touch #main_index #categories,html.touch #main_results #categories{width:100%;margin:0;text-align:left;overflow-x:scroll;overflow-y:hidden;-webkit-overflow-scrolling:touch}}@media screen and (max-width:50em){#search{width:100%;margin:0;padding:.1em 0 0}#search_wrapper{width:100%;margin:0 0 .7em;padding:0}.search_box{width:99%;margin:.1em;padding:0 .1em 0 0;display:flex;flex-direction:row}#q{width:auto!important;flex:1}.search_filters{display:block;margin:.5em}.language,.time_range{width:45%}.category{display:block;width:90%}.category label{border-bottom:0}}#categories{margin:0 10px 0 0;user-select:none}#categories::-webkit-scrollbar{width:0;height:0}.category{display:inline-block;margin:0 3px;padding:0}.category input{display:none}.category label{cursor:pointer;padding:4px 10px;margin:0;display:block;text-transform:capitalize;font-size:.9em;border-bottom:2px solid transparent;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body,html,main{padding:0;margin:0}.category input[type=checkbox]:focus+label{box-shadow:0 0 8px #3498DB}.category input[type=checkbox]:checked+label{background:#3498DB;color:#FFF;border-bottom:2px solid #084999}#categories_container .help{position:absolute;width:100%;bottom:-20px;overflow:hidden;opacity:0;transition:opacity 1s ease;font-size:.8em;text-position:center;background:#fff}footer p,html{font-size:.9em}#categories_container:hover .help{opacity:.8;transition:opacity 1s ease}html{font-family:arial,sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;color:#444}#main_about,#main_preferences,#main_stats{margin:3em;width:auto}footer{bottom:0;height:3em;margin:1em 0;padding:1em 0;text-align:center}#main_preferences h1,#main_stats h1{background:url(../img/searx.png) no-repeat;background-size:auto 75%;min-height:40px;margin:0 auto}#results button[type=submit],input[type=submit]{padding:.5rem;margin:2px 4px;display:inline-block;background:#3498DB;color:#FFF;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border:0;cursor:pointer}a{text-decoration:none;color:#29314d}a:visited,a:visited .highlight{color:#684898}article[data-vim-selected]{background:#f7f7f7}article[data-vim-selected]::before{position:absolute;left:1em;padding:2px;content:">";font-weight:700;color:#3498DB}article.result-images[data-vim-selected]{background:#3498DB}article.result-images[data-vim-selected]::before{display:none;content:""}.result{margin:19px 0 18px;padding:0}.result h3{font-size:1.1em;word-wrap:break-word;margin:5px 0 0;padding:0}.result h3 a{color:#084999;font-weight:400;font-size:1.1em}.result h3 a:visited{color:#684898}.result h3 a:focus,.result h3 a:hover{text-decoration:underline;border:none;-webkit-box-shadow:none;box-shadow:none;outline:0}.result .cache_link,.result .proxyfied_link{font-size:.9em!important}.result .altlink,.result .content,.result .stat,.result .url{font-size:.9em;padding:0;max-width:54em;word-wrap:break-word}.result .altlink,.result .content,.result .stat{margin:0;line-height:1.24}.result .altlink .highlight,.result .content .highlight,.result .stat .highlight{color:#000;background:inherit;font-weight:700}.result .codelines .highlight{color:inherit;background:inherit;font-weight:400}.result .url{margin:0 0 3px;color:#25a55b}.result .published_date{font-size:.8em;color:#888}.result img.thumbnail{float:left;padding:0 5px 10px 0;width:20em;min-width:20em;min-height:8em}.result img.image{float:left;padding:0 5px 10px 0;width:100px;max-height:100px;object-fit:scale-down;object-position:right top}.category-social .image{width:auto!important;min-width:48px;min-height:48px;padding:0 5px 25px 0!important}.result-videos .content{overflow:hidden}.engines{float:right;color:#888}.engines span{font-size:smaller;margin:0 .5em 0 0}.result-images,.result-images img{margin:0;padding:0;max-height:200px}.small_font{font-size:.8em}.highlight{color:#094089;background:inherit;font-weight:700}.result-images{display:inline-block;position:relative}.result-images img{float:inherit;border:none;background:#084999}.result-images span a{display:none;color:#FFF}.result-images:hover span a{display:block;position:absolute;bottom:0;right:0;padding:4px;margin:0 0 4px 4px;background-color:rgba(0,0,0,.6);font-size:.7em}.torrent_result{border-left:10px solid #d3d3d3;padding-left:3px}#answers,#backToTop,#sidebar .infobox{border:1px solid #ddd;box-shadow:0 0 5px #CCC}.torrent_result p{margin:3px;font-size:.8em}.torrent_result a{color:#084999}.torrent_result a:hover{text-decoration:underline}.torrent_result a:visited{color:#684898}#results{margin:2em 2em 20px;padding:0;width:50em}#suggestions .wrapper{display:flex;flex-flow:row wrap;justify-content:flex-end}#suggestions .wrapper form{display:inline-block;flex:1 1 50%}#answers,#corrections,#suggestions{max-width:50em}#answers input,#corrections input,#infoboxes input,#suggestions input{padding:0;margin:3px;font-size:.9em;display:inline-block;background:0 0;color:#444;cursor:pointer}#answers .infobox .url a,#answers input[type=submit],#corrections .infobox .url a,#corrections input[type=submit],#infoboxes .infobox .url a,#infoboxes input[type=submit],#suggestions .infobox .url a,#suggestions input[type=submit]{color:#084999;text-decoration:none;font-size:.9rem}#answers .infobox .url a:hover,#answers input[type=submit]:hover,#corrections .infobox .url a:hover,#corrections input[type=submit]:hover,#infoboxes .infobox .url a:hover,#infoboxes input[type=submit]:hover,#suggestions .infobox .url a:hover,#suggestions input[type=submit]:hover{text-decoration:underline}#corrections{display:flex;flex-flow:row wrap;margin:1em 0}#corrections h4,#corrections input[type=submit]{display:inline-block;margin:0 .5em 0 0}#corrections input[type=submit]::after{content:", "}#apis .title,#search_url .title,#suggestions .title{margin:2em 0 .5em;color:#444}#answers{margin:10px 8px;padding:.9em}#answers h4{display:none}#answers .answer{display:block;font-size:1.2em;font-weight:700}#answers form,#infoboxes form{min-width:210px}#sidebar{position:absolute;top:100px;left:57em;margin:0 2px 5px 5px;padding:0 2px 2px;max-width:25em;word-wrap:break-word}#sidebar .infobox{margin:10px 0;padding:.9em;font-size:.9em}#sidebar .infobox h2{margin:0 0 .5em}#sidebar .infobox img{max-width:100%;max-height:12em;display:block;margin:0;padding:0}#sidebar .infobox dl{margin:.5em 0}#sidebar .infobox dt{display:inline;margin:.5em .25em .5em 0;padding:0;font-weight:700}#sidebar .infobox dd{display:inline;margin:.5em 0;padding:0}#apis,#search_url{margin-top:8px}#sidebar .infobox input{font-size:1em}#search_url div.selectable_url pre{width:200em}#linkto_preferences{position:absolute;right:10px;top:.9em;padding:0;border:0;display:block;font-size:1.2em;color:#222}#linkto_preferences a:active *,#linkto_preferences a:hover *,#linkto_preferences a:link *,#linkto_preferences a:visited *{color:#222}#backToTop{margin:0 0 0 2em;padding:0;font-size:1em;background:#fff;position:fixed;bottom:85px;left:50em;transition:opacity .5s;opacity:0}#backToTop a{display:block;margin:0;padding:.6em}@media screen and (max-width:75em){#main_about,#main_preferences,#main_stats{margin:.5em;width:auto}#answers,#suggestions{margin-top:1em}#infoboxes{position:inherit;max-width:inherit}#infoboxes .infobox{clear:both}#infoboxes .infobox img{float:left;max-width:10em;margin:.5em .5em .5em 0}#sidebar{position:static;max-width:50em;margin:0 0 2px;padding:0;float:none;border:none;width:auto}.image_result,.image_result img,.result .thumbnail{max-width:98%}#sidebar input{border:0}#apis,#search_url{display:none}.result{border-bottom:1px solid #E8E7E6;margin:0;padding-top:8px;padding-bottom:6px}.result h3{margin:0 0 1px}.result .url span.url{display:block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;width:100%}.result .url a{float:right;padding:0 .5em}.result .engines{float:right;padding:0 0 3px}.result-images{border-bottom:none!important}}#main_results div#results.only_template_images{flex-direction:column;width:auto;display:flex}#main_results div#results.only_template_images #sidebar{position:relative;top:auto;order:2}#main_results div#results.only_template_images #urls{position:relative;order:1}#main_results div#results.only_template_images #backToTop{right:.5em;left:auto}#main_results div#results.only_template_images #pagination{position:relative;order:3}@media screen and (max-width:50em){article[data-vim-selected]::before{display:none;content:""}#linkto_preferences{display:none;postion:fixed!important;top:100px;right:0}#sidebar{margin:0 5px 2px}#corrections{margin:1em 5px}#results{margin:0;padding:0;width:initial}#backToTop{left:40em;bottom:35px}.result{padding:8px 10px 6px}.result-images{margin:0;padding:0;border:none}}@media screen and (max-width:35em){.result-videos img.thumbnail{float:none!important}.result-videos .content{overflow:inherit}}
searx/static/themes/simple/gruntfile.js+26−23
@@ -10,21 +10,36 @@ module.exports = function(grunt) {
10 tasks: ['jshint', 'concat', 'uglify', 'webfont', 'less:development', 'less:production']
10 tasks: ['jshint', 'concat', 'uglify', 'webfont', 'less:development', 'less:production']
11 }
11 }
12 },
12 },
13− concat: {
13+ jshint: {
14+ files: ['js/searx_src/*.js', 'js/searx_header/*.js'],
14 options: {
15 options: {
16+ reporterOutput: "",
17+ proto: true,
18+ // options here to override JSHint defaults
19+ globals: {
20+ browser: true,
21+ jQuery: false,
22+ devel: true
23+ }
24+ }
25+ },
26+ concat: {
27+ head_and_body: {
28+ options: {
15− separator: ';'
29+ separator: ';'
16− },
30+ },
17− dist: {
31+ files: {
32+ 'js/searx.head.js': ['js/searx_head/*.js'],
18− src: ['js/searx_src/*.js'],
33+ 'js/searx.js': ['js/searx_src/*.js']
19− dest: 'js/searx.js'
34+ }
20 }
35 }
21 },
36 },
22 uglify: {
37 uglify: {
23 options: {
38 options: {
24 banner: '/*! simple/searx.min.js | <%= grunt.template.today("dd-mm-yyyy") %> | https://github.com/asciimoo/searx */\n',
39 banner: '/*! simple/searx.min.js | <%= grunt.template.today("dd-mm-yyyy") %> | https://github.com/asciimoo/searx */\n',
25− output: {
40+ output: {
26− comments: 'some'
41+ comments: 'some'
27− },
42+ },
28 ie8: false,
43 ie8: false,
29 warnings: true,
44 warnings: true,
30 compress: false,
45 compress: false,
@@ -33,20 +48,8 @@ module.exports = function(grunt) {
33 },
48 },
34 dist: {
49 dist: {
35 files: {
50 files: {
36− 'js/searx.min.js': ['<%= concat.dist.dest %>']
51+ 'js/searx.head.min.js': ['js/searx.head.js'],
37− }
52+ 'js/searx.min.js': ['js/searx.js']
38− }
39− },
40− jshint: {
41− files: ['js/searx_src/*.js'],
42− options: {
43− reporterOutput: "",
44− proto: true,
45− // options here to override JSHint defaults
46− globals: {
47− browser: true,
48− jQuery: false,
49− devel: true
50 }
53 }
51 }
54 }
52 },
55 },
searx/static/themes/simple/js/searx.head.jsnew file+40
@@ -0,0 +1,40 @@
1+/**
2+* searx is free software: you can redistribute it and/or modify
3+* it under the terms of the GNU Affero General Public License as published by
4+* the Free Software Foundation, either version 3 of the License, or
5+* (at your option) any later version.
6+*
7+* searx is distributed in the hope that it will be useful,
8+* but WITHOUT ANY WARRANTY; without even the implied warranty of
9+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+* GNU Affero General Public License for more details.
11+*
12+* You should have received a copy of the GNU Affero General Public License
13+* along with searx. If not, see < http://www.gnu.org/licenses/ >.
14+*
15+* (C) 2019 by Alexandre Flament
16+*
17+*/
18+(function(w, d) {
19+ 'use strict';
20+
21+ // add data- properties
22+ var script = d.currentScript || (function() {
23+ var scripts = d.getElementsByTagName('script');
24+ return scripts[scripts.length - 1];
25+ })();
26+
27+ // try to detect touch screen
28+ w.searx = {
29+ touch: (("ontouchstart" in w) || w.DocumentTouch && document instanceof DocumentTouch) || false,
30+ method: script.getAttribute('data-method'),
31+ autocompleter: script.getAttribute('data-autocompleter') === 'true',
32+ search_on_category_select: script.getAttribute('data-search-on-category-select') === 'true',
33+ infinite_scroll: script.getAttribute('data-infinite-scroll') === 'true',
34+ static_path: script.getAttribute('data-static-path'),
35+ no_item_found: script.getAttribute('data-no-item-found')
36+ }
37+
38+ // update the css
39+ d.getElementsByTagName("html")[0].className = (w.searx.touch)?"js touch":"js";
40+})(window, document);
searx/static/themes/simple/js/searx.head.min.jsnew file+4
@@ -0,0 +1,4 @@
1+/*! simple/searx.min.js | 06-08-2019 | https://github.com/asciimoo/searx */
2+
3+(function(t,e){"use strict";var a=e.currentScript||function(){var t=e.getElementsByTagName("script");return t[t.length-1]}();t.searx={touch:"ontouchstart"in t||t.DocumentTouch&&document instanceof DocumentTouch||false,method:a.getAttribute("data-method"),autocompleter:a.getAttribute("data-autocompleter")==="true",search_on_category_select:a.getAttribute("data-search-on-category-select")==="true",infinite_scroll:a.getAttribute("data-infinite-scroll")==="true",static_path:a.getAttribute("data-static-path"),no_item_found:a.getAttribute("data-no-item-found")};e.getElementsByTagName("html")[0].className=t.searx.touch?"js touch":"js"})(window,document);
4+//# sourceMappingURL=searx.head.min.js.map
searx/static/themes/simple/js/searx.head.min.js.mapnew file+1
@@ -0,0 +1 @@
1+{"version":3,"sources":["searx.head.js"],"names":["w","d","script","currentScript","scripts","getElementsByTagName","length","searx","touch","DocumentTouch","document","method","getAttribute","autocompleter","search_on_category_select","infinite_scroll","static_path","no_item_found","className","window"],"mappings":";;CAiBA,SAAUA,EAAGC,GACT,aAGA,IAAIC,EAASD,EAAEE,eAAkB,WAC7B,IAAIC,EAAUH,EAAEI,qBAAqB,UACrC,OAAOD,EAAQA,EAAQE,OAAS,GAFH,GAMjCN,EAAEO,MAAQ,CACNC,MAAS,iBAAkBR,GAAMA,EAAES,eAAiBC,oBAAoBD,eAAkB,MAC1FE,OAAQT,EAAOU,aAAa,eAC5BC,cAAeX,EAAOU,aAAa,wBAA0B,OAC7DE,0BAA2BZ,EAAOU,aAAa,oCAAsC,OACrFG,gBAAiBb,EAAOU,aAAa,0BAA4B,OACjEI,YAAad,EAAOU,aAAa,oBACjCK,cAAef,EAAOU,aAAa,uBAIvCX,EAAEI,qBAAqB,QAAQ,GAAGa,UAAalB,EAAEO,MAAW,MAAE,WAAW,MArB7E,CAsBGY,OAAQT","file":"searx.head.min.js"}
searx/static/themes/simple/js/searx.js+6−6
@@ -15,7 +15,7 @@
15* (C) 2017 by Alexandre Flament, <alex@al-f.net>
15* (C) 2017 by Alexandre Flament, <alex@al-f.net>
16*
16*
17*/
17*/
18−(function(w, d, searx) {
18+window.searx = (function(w, d) {
19
19
20 'use strict';
20 'use strict';
21
21
@@ -45,7 +45,7 @@
45 }
45 }
46 }
46 }
47
47
48− searx = searx || {};
48+ var searx = window.searx || {};
49
49
50 searx.on = function(obj, eventType, callback, useCapture) {
50 searx.on = function(obj, eventType, callback, useCapture) {
51 useCapture = useCapture || false;
51 useCapture = useCapture || false;
@@ -110,7 +110,7 @@
110 };
110 };
111
111
112 searx.loadStyle = function(src) {
112 searx.loadStyle = function(src) {
113− var path = searx.staticPath + src,
113+ var path = searx.static_path + src,
114 id = "style_" + src.replace('.', '_'),
114 id = "style_" + src.replace('.', '_'),
115 s = d.getElementById(id);
115 s = d.getElementById(id);
116 if (s === null) {
116 if (s === null) {
@@ -124,7 +124,7 @@
124 };
124 };
125
125
126 searx.loadScript = function(src, callback) {
126 searx.loadScript = function(src, callback) {
127− var path = searx.staticPath + src,
127+ var path = searx.static_path + src,
128 id = "script_" + src.replace('.', '_'),
128 id = "script_" + src.replace('.', '_'),
129 s = d.getElementById(id);
129 s = d.getElementById(id);
130 if (s === null) {
130 if (s === null) {
@@ -161,7 +161,7 @@
161 });
161 });
162
162
163 return searx;
163 return searx;
164−})(window, document, window.searx);
164+})(window, document);
165;(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.AutoComplete = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
165;(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.AutoComplete = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
166/*
166/*
167 * @license MIT
167 * @license MIT
@@ -1529,7 +1529,7 @@ module.exports = AutoComplete;
1529 if (searx.autocompleter) {
1529 if (searx.autocompleter) {
1530 searx.autocomplete = AutoComplete.call(w, {
1530 searx.autocomplete = AutoComplete.call(w, {
1531 Url: "./autocompleter",
1531 Url: "./autocompleter",
1532− EmptyMessage: searx.noItemFound,
1532+ EmptyMessage: searx.no_item_found,
1533 HttpMethod: searx.method,
1533 HttpMethod: searx.method,
1534 MinChars: 4,
1534 MinChars: 4,
1535 Delay: 300,
1535 Delay: 300,
searx/static/themes/simple/js/searx.min.js+6−4
@@ -1,6 +1,7 @@
1−/*! simple/searx.min.js | 14-08-2018 | https://github.com/asciimoo/searx */
1+/*! simple/searx.min.js | 06-08-2019 | https://github.com/asciimoo/searx */
2
2
3−(function(e,t,n){"use strict";if(e.Element){(function(e){e.matches=e.matches||e.matchesSelector||e.webkitMatchesSelector||e.msMatchesSelector||function(e){var t=this,n=(t.parentNode||t.document).querySelectorAll(e),i=-1;while(n[++i]&&n[i]!=t);return!!n[i]}})(Element.prototype)}function i(e,t,n){try{e.call(t,n)}catch(e){console.log(e)}}n=n||{};n.on=function(e,n,r,a){a=a||false;if(typeof e!=="string"){e.addEventListener(n,r,a)}else{t.addEventListener(n,function(n){var a=n.target||n.srcElement,o=false;while(a&&a.matches&&a!==t&&!(o=a.matches(e)))a=a.parentElement;if(o)i(r,a,n)},a)}};n.ready=function(t){if(document.readyState!="loading"){t.call(e)}else{e.addEventListener("DOMContentLoaded",t.bind(e))}};n.http=function(e,t,n){var i=new XMLHttpRequest,r=function(){},a=function(){},o={then:function(e){r=e;return o},catch:function(e){a=e;return o}};try{i.open(e,t,true);i.onload=function(){if(i.status==200){r(i.response,i.responseType)}else{a(Error(i.statusText))}};i.onerror=function(){a(Error("Network Error"))};i.onabort=function(){a(Error("Transaction is aborted"))};i.send()}catch(e){a(e)}return o};n.loadStyle=function(e){var i=n.staticPath+e,r="style_"+e.replace(".","_"),a=t.getElementById(r);if(a===null){a=t.createElement("link");a.setAttribute("id",r);a.setAttribute("rel","stylesheet");a.setAttribute("type","text/css");a.setAttribute("href",i);t.body.appendChild(a)}};n.loadScript=function(e,i){var r=n.staticPath+e,a="script_"+e.replace(".","_"),o=t.getElementById(a);if(o===null){o=t.createElement("script");o.setAttribute("id",a);o.setAttribute("src",r);o.onload=i;o.onerror=function(){o.setAttribute("error","1")};t.body.appendChild(o)}else if(!o.hasAttribute("error")){try{i.apply(o,[])}catch(e){console.log(e)}}else{console.log("callback not executed : script '"+r+"' not loaded.")}};n.insertBefore=function(e,t){element.parentNode.insertBefore(e,t)};n.insertAfter=function(e,t){t.parentNode.insertBefore(e,t.nextSibling)};n.on(".close","click",function(e){var t=e.target||e.srcElement;this.parentNode.classList.add("invisible")});return n})(window,document,window.searx);(function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e()}else if(typeof define==="function"&&define.amd){define([],e)}else{var t;if(typeof window!=="undefined"){t=window}else if(typeof global!=="undefined"){t=global}else if(typeof self!=="undefined"){t=self}else{t=this}t.AutoComplete=e()}})(function(){var e,t,n;return function e(t,n,i){function r(o,s){if(!n[o]){if(!t[o]){var l=typeof require=="function"&&require;if(!s&&l)return l(o,!0);if(a)return a(o,!0);var u=new Error("Cannot find module '"+o+"'");throw u.code="MODULE_NOT_FOUND",u}var c=n[o]={exports:{}};t[o][0].call(c.exports,function(e){var n=t[o][1][e];return r(n?n:e)},c,c.exports,e,t,n,i)}return n[o].exports}var a=typeof require=="function"&&require;for(var o=0;o<i.length;o++)r(i[o]);return r}({1:[function(e,t,n){/*
3+window.searx=function(t,a){"use strict";if(t.Element){(function(e){e.matches=e.matches||e.matchesSelector||e.webkitMatchesSelector||e.msMatchesSelector||function(e){var t=this,n=(t.parentNode||t.document).querySelectorAll(e),i=-1;while(n[++i]&&n[i]!=t);return!!n[i]}})(Element.prototype)}function o(e,t,n){try{e.call(t,n)}catch(e){console.log(e)}}var s=window.searx||{};s.on=function(i,e,r,t){t=t||false;if(typeof i!=="string"){i.addEventListener(e,r,t)}else{a.addEventListener(e,function(e){var t=e.target||e.srcElement,n=false;while(t&&t.matches&&t!==a&&!(n=t.matches(i)))t=t.parentElement;if(n)o(r,t,e)},t)}};s.ready=function(e){if(document.readyState!="loading"){e.call(t)}else{t.addEventListener("DOMContentLoaded",e.bind(t))}};s.http=function(e,t,n){var i=new XMLHttpRequest,r=function(){},a=function(){},o={then:function(e){r=e;return o},catch:function(e){a=e;return o}};try{i.open(e,t,true);i.onload=function(){if(i.status==200){r(i.response,i.responseType)}else{a(Error(i.statusText))}};i.onerror=function(){a(Error("Network Error"))};i.onabort=function(){a(Error("Transaction is aborted"))};i.send()}catch(e){a(e)}return o};s.loadStyle=function(e){var t=s.static_path+e,n="style_"+e.replace(".","_"),i=a.getElementById(n);if(i===null){i=a.createElement("link");i.setAttribute("id",n);i.setAttribute("rel","stylesheet");i.setAttribute("type","text/css");i.setAttribute("href",t);a.body.appendChild(i)}};s.loadScript=function(e,t){var n=s.static_path+e,i="script_"+e.replace(".","_"),r=a.getElementById(i);if(r===null){r=a.createElement("script");r.setAttribute("id",i);r.setAttribute("src",n);r.onload=t;r.onerror=function(){r.setAttribute("error","1")};a.body.appendChild(r)}else if(!r.hasAttribute("error")){try{t.apply(r,[])}catch(e){console.log(e)}}else{console.log("callback not executed : script '"+n+"' not loaded.")}};s.insertBefore=function(e,t){element.parentNode.insertBefore(e,t)};s.insertAfter=function(e,t){t.parentNode.insertBefore(e,t.nextSibling)};s.on(".close","click",function(e){var t=e.target||e.srcElement;this.parentNode.classList.add("invisible")});return s}(window,document);(function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e()}else if(typeof define==="function"&&define.amd){define([],e)}else{var t;if(typeof window!=="undefined"){t=window}else if(typeof global!=="undefined"){t=global}else if(typeof self!=="undefined"){t=self}else{t=this}t.AutoComplete=e()}})(function(){var e,t,n;return function a(o,s,l){function u(n,e){if(!s[n]){if(!o[n]){var t=typeof require=="function"&&require;if(!e&&t)return t(n,!0);if(c)return c(n,!0);var i=new Error("Cannot find module '"+n+"'");throw i.code="MODULE_NOT_FOUND",i}var r=s[n]={exports:{}};o[n][0].call(r.exports,function(e){var t=o[n][1][e];return u(t?t:e)},r,r.exports,a,o,s,l)}return s[n].exports}var c=typeof require=="function"&&require;for(var e=0;e<l.length;e++)u(l[e]);return u}({1:[function(e,t,n){
4+/*
4 * @license MIT
5 * @license MIT
5 *
6 *
6 * Autocomplete.js v2.6.3
7 * Autocomplete.js v2.6.3
@@ -9,7 +10,8 @@
9 *
10 *
10 * (c) 2017, Baptiste Donaux
11 * (c) 2017, Baptiste Donaux
11 */
12 */
12−"use strict";var i;(function(e){e[e["AND"]=0]="AND";e[e["OR"]=1]="OR"})(i||(i={}));var r;(function(e){e[e["KEYDOWN"]=0]="KEYDOWN";e[e["KEYUP"]=1]="KEYUP"})(r||(r={}));var a=function(){function e(t,n){if(t===void 0){t={}}if(n===void 0){n="[data-autocomplete]"}if(Array.isArray(n)){n.forEach(function(n){new e(t,n)})}else if(typeof n=="string"){var i=document.querySelectorAll(n);Array.prototype.forEach.call(i,function(n){new e(t,n)})}else{var r=e.merge(e.defaults,t,{DOMResults:document.createElement("div")});e.prototype.create(r,n);return r}}e.prototype.create=function(t,n){t.Input=n;if(t.Input.nodeName.match(/^INPUT$/i)&&(t.Input.hasAttribute("type")===false||t.Input.getAttribute("type").match(/^TEXT|SEARCH$/i))){t.Input.setAttribute("autocomplete","off");t._Position(t);t.Input.parentNode.appendChild(t.DOMResults);t.$Listeners={blur:t._Blur.bind(t),destroy:e.prototype.destroy.bind(null,t),focus:t._Focus.bind(t),keyup:e.prototype.event.bind(null,t,r.KEYUP),keydown:e.prototype.event.bind(null,t,r.KEYDOWN),position:t._Position.bind(t)};for(var i in t.$Listeners){t.Input.addEventListener(i,t.$Listeners[i])}}};e.prototype.getEventsByType=function(e,t){var n={};for(var i in e.KeyboardMappings){var a=r.KEYUP;if(e.KeyboardMappings[i].Event!==undefined){a=e.KeyboardMappings[i].Event}if(a==t){n[i]=e.KeyboardMappings[i]}}return n};e.prototype.event=function(t,n,r){var a=function(t){if(l===true&&s.Operator==i.AND||l===false&&s.Operator==i.OR){t=e.merge({Not:false},t);if(t.hasOwnProperty("Is")){if(t.Is==r.keyCode){l=!t.Not}else{l=t.Not}}else if(t.hasOwnProperty("From")&&t.hasOwnProperty("To")){if(r.keyCode>=t.From&&r.keyCode<=t.To){l=!t.Not}else{l=t.Not}}}};for(var o in e.prototype.getEventsByType(t,n)){var s=e.merge({Operator:i.AND},t.KeyboardMappings[o]),l=i.AND==s.Operator;s.Conditions.forEach(a);if(l===true){s.Callback.call(t,r)}}};e.prototype.makeRequest=function(e,t){var n=Object.getOwnPropertyNames(e.HttpHeaders),i=new XMLHttpRequest,r=e._HttpMethod(),a=e._Url(),o=e._Pre(),s=encodeURIComponent(e._QueryArg())+"="+encodeURIComponent(o);if(r.match(/^GET$/i)){if(a.indexOf("?")!==-1){a+="&"+s}else{a+="?"+s}}i.open(r,a,true);for(var l=n.length-1;l>=0;l--){i.setRequestHeader(n[l],e.HttpHeaders[n[l]])}i.onreadystatechange=function(){if(i.readyState==4&&i.status==200){e.$Cache[o]=i.response;t(i.response)}};return i};e.prototype.ajax=function(t,n,i){if(i===void 0){i=true}if(t.$AjaxTimer){window.clearTimeout(t.$AjaxTimer)}if(i===true){t.$AjaxTimer=window.setTimeout(e.prototype.ajax.bind(null,t,n,false),t.Delay)}else{if(t.Request){t.Request.abort()}t.Request=n;t.Request.send(t._QueryArg()+"="+t._Pre())}};e.prototype.cache=function(t,n){var i=t._Cache(t._Pre());if(i===undefined){var r=e.prototype.makeRequest(t,n);e.prototype.ajax(t,r)}else{n(i)}};e.prototype.destroy=function(e){for(var t in e.$Listeners){e.Input.removeEventListener(t,e.$Listeners[t])}e.DOMResults.parentNode.removeChild(e.DOMResults)};return e}();a.merge=function(){var e={},t;for(var n=0;n<arguments.length;n++){for(t in arguments[n]){e[t]=arguments[n][t]}}return e};a.defaults={Delay:150,EmptyMessage:"No result here",Highlight:{getRegex:function(e){return new RegExp(e,"ig")},transform:function(e){return"<strong>"+e+"</strong>"}},HttpHeaders:{"Content-type":"application/x-www-form-urlencoded"},Limit:0,MinChars:0,HttpMethod:"GET",QueryArg:"q",Url:null,KeyboardMappings:{Enter:{Conditions:[{Is:13,Not:false}],Callback:function(e){if(this.DOMResults.getAttribute("class").indexOf("open")!=-1){var t=this.DOMResults.querySelector("li.active");if(t!==null){e.preventDefault();this._Select(t);this.DOMResults.setAttribute("class","autocomplete")}}},Operator:i.AND,Event:r.KEYDOWN},KeyUpAndDown_down:{Conditions:[{Is:38,Not:false},{Is:40,Not:false}],Callback:function(e){e.preventDefault()},Operator:i.OR,Event:r.KEYDOWN},KeyUpAndDown_up:{Conditions:[{Is:38,Not:false},{Is:40,Not:false}],Callback:function(e){e.preventDefault();var t=this.DOMResults.querySelector("li:first-child:not(.locked)"),n=this.DOMResults.querySelector("li:last-child:not(.locked)"),i=this.DOMResults.querySelector("li.active");if(i){var r=Array.prototype.indexOf.call(i.parentNode.children,i),a=r+(e.keyCode-39),o=this.DOMResults.getElementsByTagName("li").length;if(a<0){a=o-1}else if(a>=o){a=0}i.classList.remove("active");i.parentElement.children.item(a).classList.add("active")}else if(n&&e.keyCode==38){n.classList.add("active")}else if(t){t.classList.add("active")}},Operator:i.OR,Event:r.KEYUP},AlphaNum:{Conditions:[{Is:13,Not:true},{From:35,To:40,Not:true}],Callback:function(){var e=this.Input.getAttribute("data-autocomplete-old-value"),t=this._Pre();if(t!==""&&t.length>=this._MinChars()){if(!e||t!=e){this.DOMResults.setAttribute("class","autocomplete open")}a.prototype.cache(this,function(e){this._Render(this._Post(e));this._Open()}.bind(this))}},Operator:i.AND,Event:r.KEYUP}},DOMResults:null,Request:null,Input:null,_EmptyMessage:function(){var e="";if(this.Input.hasAttribute("data-autocomplete-empty-message")){e=this.Input.getAttribute("data-autocomplete-empty-message")}else if(this.EmptyMessage!==false){e=this.EmptyMessage}else{e=""}return e},_Limit:function(){var e=this.Input.getAttribute("data-autocomplete-limit");if(isNaN(e)||e===null){return this.Limit}return parseInt(e,10)},_MinChars:function(){var e=this.Input.getAttribute("data-autocomplete-minchars");if(isNaN(e)||e===null){return this.MinChars}return parseInt(e,10)},_Highlight:function(e){return e.replace(this.Highlight.getRegex(this._Pre()),this.Highlight.transform)},_HttpMethod:function(){if(this.Input.hasAttribute("data-autocomplete-method")){return this.Input.getAttribute("data-autocomplete-method")}return this.HttpMethod},_QueryArg:function(){if(this.Input.hasAttribute("data-autocomplete-param-name")){return this.Input.getAttribute("data-autocomplete-param-name")}return this.QueryArg},_Url:function(){if(this.Input.hasAttribute("data-autocomplete")){return this.Input.getAttribute("data-autocomplete")}return this.Url},_Blur:function(e){if(e===true){this.DOMResults.setAttribute("class","autocomplete");this.Input.setAttribute("data-autocomplete-old-value",this.Input.value)}else{var t=this;setTimeout(function(){t._Blur(true)},150)}},_Cache:function(e){return this.$Cache[e]},_Focus:function(){var e=this.Input.getAttribute("data-autocomplete-old-value");if((!e||this.Input.value!=e)&&this._MinChars()<=this.Input.value.length){this.DOMResults.setAttribute("class","autocomplete open")}},_Open:function(){var e=this;Array.prototype.forEach.call(this.DOMResults.getElementsByTagName("li"),function(t){if(t.getAttribute("class")!="locked"){t.onclick=function(n){e._Select(t)};t.onmouseenter=function(){var n=e.DOMResults.querySelector("li.active");if(n!==t){if(n!==null){n.classList.remove("active")}t.classList.add("active")}}}})},_Position:function(){this.DOMResults.setAttribute("class","autocomplete");this.DOMResults.setAttribute("style","top:"+(this.Input.offsetTop+this.Input.offsetHeight)+"px;left:"+this.Input.offsetLeft+"px;width:"+this.Input.clientWidth+"px;")},_Render:function(e){var t;if(typeof e=="string"){t=this._RenderRaw(e)}else{t=this._RenderResponseItems(e)}if(this.DOMResults.hasChildNodes()){this.DOMResults.removeChild(this.DOMResults.childNodes[0])}this.DOMResults.appendChild(t)},_RenderResponseItems:function(e){var t=document.createElement("ul"),n=document.createElement("li"),i=this._Limit();if(i<0){e=e.reverse()}else if(i===0){i=e.length}for(var r=0;r<Math.min(Math.abs(i),e.length);r++){n.innerHTML=e[r].Label;n.setAttribute("data-autocomplete-value",e[r].Value);t.appendChild(n);n=document.createElement("li")}return t},_RenderRaw:function(e){var t=document.createElement("ul"),n=document.createElement("li");if(e.length>0){this.DOMResults.innerHTML=e}else{var i=this._EmptyMessage();if(i!==""){n.innerHTML=i;n.setAttribute("class","locked");t.appendChild(n)}}return t},_Post:function(e){try{var t=[];var n=JSON.parse(e);if(Object.keys(n).length===0){return""}if(Array.isArray(n)){for(var i=0;i<Object.keys(n).length;i++){t[t.length]={Value:n[i],Label:this._Highlight(n[i])}}}else{for(var r in n){t.push({Value:r,Label:this._Highlight(n[r])})}}return t}catch(t){return e}},_Pre:function(){return this.Input.value},_Select:function(e){console.log("test test test");if(e.hasAttribute("data-autocomplete-value")){this.Input.value=e.getAttribute("data-autocomplete-value")}else{this.Input.value=e.innerHTML}this.Input.setAttribute("data-autocomplete-old-value",this.Input.value)},$AjaxTimer:null,$Cache:{},$Listeners:{}};t.exports=a},{}]},{},[1])(1)});/**
13+"use strict";var l;(function(e){e[e["AND"]=0]="AND";e[e["OR"]=1]="OR"})(l||(l={}));var a;(function(e){e[e["KEYDOWN"]=0]="KEYDOWN";e[e["KEYUP"]=1]="KEYUP"})(a||(a={}));var i=function(){function s(t,e){if(t===void 0){t={}}if(e===void 0){e="[data-autocomplete]"}if(Array.isArray(e)){e.forEach(function(e){new s(t,e)})}else if(typeof e=="string"){var n=document.querySelectorAll(e);Array.prototype.forEach.call(n,function(e){new s(t,e)})}else{var i=s.merge(s.defaults,t,{DOMResults:document.createElement("div")});s.prototype.create(i,e);return i}}s.prototype.create=function(e,t){e.Input=t;if(e.Input.nodeName.match(/^INPUT$/i)&&(e.Input.hasAttribute("type")===false||e.Input.getAttribute("type").match(/^TEXT|SEARCH$/i))){e.Input.setAttribute("autocomplete","off");e._Position(e);e.Input.parentNode.appendChild(e.DOMResults);e.$Listeners={blur:e._Blur.bind(e),destroy:s.prototype.destroy.bind(null,e),focus:e._Focus.bind(e),keyup:s.prototype.event.bind(null,e,a.KEYUP),keydown:s.prototype.event.bind(null,e,a.KEYDOWN),position:e._Position.bind(e)};for(var n in e.$Listeners){e.Input.addEventListener(n,e.$Listeners[n])}}};s.prototype.getEventsByType=function(e,t){var n={};for(var i in e.KeyboardMappings){var r=a.KEYUP;if(e.KeyboardMappings[i].Event!==undefined){r=e.KeyboardMappings[i].Event}if(r==t){n[i]=e.KeyboardMappings[i]}}return n};s.prototype.event=function(e,t,n){var i=function(e){if(o===true&&a.Operator==l.AND||o===false&&a.Operator==l.OR){e=s.merge({Not:false},e);if(e.hasOwnProperty("Is")){if(e.Is==n.keyCode){o=!e.Not}else{o=e.Not}}else if(e.hasOwnProperty("From")&&e.hasOwnProperty("To")){if(n.keyCode>=e.From&&n.keyCode<=e.To){o=!e.Not}else{o=e.Not}}}};for(var r in s.prototype.getEventsByType(e,t)){var a=s.merge({Operator:l.AND},e.KeyboardMappings[r]),o=l.AND==a.Operator;a.Conditions.forEach(i);if(o===true){a.Callback.call(e,n)}}};s.prototype.makeRequest=function(e,t){var n=Object.getOwnPropertyNames(e.HttpHeaders),i=new XMLHttpRequest,r=e._HttpMethod(),a=e._Url(),o=e._Pre(),s=encodeURIComponent(e._QueryArg())+"="+encodeURIComponent(o);if(r.match(/^GET$/i)){if(a.indexOf("?")!==-1){a+="&"+s}else{a+="?"+s}}i.open(r,a,true);for(var l=n.length-1;l>=0;l--){i.setRequestHeader(n[l],e.HttpHeaders[n[l]])}i.onreadystatechange=function(){if(i.readyState==4&&i.status==200){e.$Cache[o]=i.response;t(i.response)}};return i};s.prototype.ajax=function(e,t,n){if(n===void 0){n=true}if(e.$AjaxTimer){window.clearTimeout(e.$AjaxTimer)}if(n===true){e.$AjaxTimer=window.setTimeout(s.prototype.ajax.bind(null,e,t,false),e.Delay)}else{if(e.Request){e.Request.abort()}e.Request=t;e.Request.send(e._QueryArg()+"="+e._Pre())}};s.prototype.cache=function(e,t){var n=e._Cache(e._Pre());if(n===undefined){var i=s.prototype.makeRequest(e,t);s.prototype.ajax(e,i)}else{t(n)}};s.prototype.destroy=function(e){for(var t in e.$Listeners){e.Input.removeEventListener(t,e.$Listeners[t])}e.DOMResults.parentNode.removeChild(e.DOMResults)};return s}();i.merge=function(){var e={},t;for(var n=0;n<arguments.length;n++){for(t in arguments[n]){e[t]=arguments[n][t]}}return e};i.defaults={Delay:150,EmptyMessage:"No result here",Highlight:{getRegex:function(e){return new RegExp(e,"ig")},transform:function(e){return"<strong>"+e+"</strong>"}},HttpHeaders:{"Content-type":"application/x-www-form-urlencoded"},Limit:0,MinChars:0,HttpMethod:"GET",QueryArg:"q",Url:null,KeyboardMappings:{Enter:{Conditions:[{Is:13,Not:false}],Callback:function(e){if(this.DOMResults.getAttribute("class").indexOf("open")!=-1){var t=this.DOMResults.querySelector("li.active");if(t!==null){e.preventDefault();this._Select(t);this.DOMResults.setAttribute("class","autocomplete")}}},Operator:l.AND,Event:a.KEYDOWN},KeyUpAndDown_down:{Conditions:[{Is:38,Not:false},{Is:40,Not:false}],Callback:function(e){e.preventDefault()},Operator:l.OR,Event:a.KEYDOWN},KeyUpAndDown_up:{Conditions:[{Is:38,Not:false},{Is:40,Not:false}],Callback:function(e){e.preventDefault();var t=this.DOMResults.querySelector("li:first-child:not(.locked)"),n=this.DOMResults.querySelector("li:last-child:not(.locked)"),i=this.DOMResults.querySelector("li.active");if(i){var r=Array.prototype.indexOf.call(i.parentNode.children,i),a=r+(e.keyCode-39),o=this.DOMResults.getElementsByTagName("li").length;if(a<0){a=o-1}else if(a>=o){a=0}i.classList.remove("active");i.parentElement.children.item(a).classList.add("active")}else if(n&&e.keyCode==38){n.classList.add("active")}else if(t){t.classList.add("active")}},Operator:l.OR,Event:a.KEYUP},AlphaNum:{Conditions:[{Is:13,Not:true},{From:35,To:40,Not:true}],Callback:function(){var e=this.Input.getAttribute("data-autocomplete-old-value"),t=this._Pre();if(t!==""&&t.length>=this._MinChars()){if(!e||t!=e){this.DOMResults.setAttribute("class","autocomplete open")}i.prototype.cache(this,function(e){this._Render(this._Post(e));this._Open()}.bind(this))}},Operator:l.AND,Event:a.KEYUP}},DOMResults:null,Request:null,Input:null,_EmptyMessage:function(){var e="";if(this.Input.hasAttribute("data-autocomplete-empty-message")){e=this.Input.getAttribute("data-autocomplete-empty-message")}else if(this.EmptyMessage!==false){e=this.EmptyMessage}else{e=""}return e},_Limit:function(){var e=this.Input.getAttribute("data-autocomplete-limit");if(isNaN(e)||e===null){return this.Limit}return parseInt(e,10)},_MinChars:function(){var e=this.Input.getAttribute("data-autocomplete-minchars");if(isNaN(e)||e===null){return this.MinChars}return parseInt(e,10)},_Highlight:function(e){return e.replace(this.Highlight.getRegex(this._Pre()),this.Highlight.transform)},_HttpMethod:function(){if(this.Input.hasAttribute("data-autocomplete-method")){return this.Input.getAttribute("data-autocomplete-method")}return this.HttpMethod},_QueryArg:function(){if(this.Input.hasAttribute("data-autocomplete-param-name")){return this.Input.getAttribute("data-autocomplete-param-name")}return this.QueryArg},_Url:function(){if(this.Input.hasAttribute("data-autocomplete")){return this.Input.getAttribute("data-autocomplete")}return this.Url},_Blur:function(e){if(e===true){this.DOMResults.setAttribute("class","autocomplete");this.Input.setAttribute("data-autocomplete-old-value",this.Input.value)}else{var t=this;setTimeout(function(){t._Blur(true)},150)}},_Cache:function(e){return this.$Cache[e]},_Focus:function(){var e=this.Input.getAttribute("data-autocomplete-old-value");if((!e||this.Input.value!=e)&&this._MinChars()<=this.Input.value.length){this.DOMResults.setAttribute("class","autocomplete open")}},_Open:function(){var n=this;Array.prototype.forEach.call(this.DOMResults.getElementsByTagName("li"),function(t){if(t.getAttribute("class")!="locked"){t.onclick=function(e){n._Select(t)};t.onmouseenter=function(){var e=n.DOMResults.querySelector("li.active");if(e!==t){if(e!==null){e.classList.remove("active")}t.classList.add("active")}}}})},_Position:function(){this.DOMResults.setAttribute("class","autocomplete");this.DOMResults.setAttribute("style","top:"+(this.Input.offsetTop+this.Input.offsetHeight)+"px;left:"+this.Input.offsetLeft+"px;width:"+this.Input.clientWidth+"px;")},_Render:function(e){var t;if(typeof e=="string"){t=this._RenderRaw(e)}else{t=this._RenderResponseItems(e)}if(this.DOMResults.hasChildNodes()){this.DOMResults.removeChild(this.DOMResults.childNodes[0])}this.DOMResults.appendChild(t)},_RenderResponseItems:function(e){var t=document.createElement("ul"),n=document.createElement("li"),i=this._Limit();if(i<0){e=e.reverse()}else if(i===0){i=e.length}for(var r=0;r<Math.min(Math.abs(i),e.length);r++){n.innerHTML=e[r].Label;n.setAttribute("data-autocomplete-value",e[r].Value);t.appendChild(n);n=document.createElement("li")}return t},_RenderRaw:function(e){var t=document.createElement("ul"),n=document.createElement("li");if(e.length>0){this.DOMResults.innerHTML=e}else{var i=this._EmptyMessage();if(i!==""){n.innerHTML=i;n.setAttribute("class","locked");t.appendChild(n)}}return t},_Post:function(t){try{var e=[];var n=JSON.parse(t);if(Object.keys(n).length===0){return""}if(Array.isArray(n)){for(var i=0;i<Object.keys(n).length;i++){e[e.length]={Value:n[i],Label:this._Highlight(n[i])}}}else{for(var r in n){e.push({Value:r,Label:this._Highlight(n[r])})}}return e}catch(e){return t}},_Pre:function(){return this.Input.value},_Select:function(e){console.log("test test test");if(e.hasAttribute("data-autocomplete-value")){this.Input.value=e.getAttribute("data-autocomplete-value")}else{this.Input.value=e.innerHTML}this.Input.setAttribute("data-autocomplete-old-value",this.Input.value)},$AjaxTimer:null,$Cache:{},$Listeners:{}};t.exports=i},{}]},{},[1])(1)});
14+/**
13*
15*
14* Google Image Layout v0.0.1
16* Google Image Layout v0.0.1
15* Description, by Anh Trinh.
17* Description, by Anh Trinh.
@@ -19,5 +21,5 @@
19* @license Free to use under the MIT License.
21* @license Free to use under the MIT License.
20*
22*
21*/
23*/
22−(function(e,t){"use strict";function n(e,t,n,i){this.container_selector=e;this.results_selector=t;this.img_selector=n;this.margin=10;this.maxHeight=i;this._alignAllDone=true}n.prototype._getHeigth=function(e,t){var n=0,i;t-=e.length*this.margin;for(var r=0;r<e.length;r++){i=e[r];if(i.naturalWidth>0&&i.naturalHeight>0){n+=i.naturalWidth/i.naturalHeight}else{n+=1}}return t/n};n.prototype._setSize=function(e,t){var n,i,r=e.length;for(var a=0;a<r;a++){n=e[a];if(n.naturalWidth>0&&n.naturalHeight>0){i=t*n.naturalWidth/n.naturalHeight}else{i=t}n.style.width=i+"px";n.style.height=t+"px";n.style.marginLeft="3px";n.style.marginTop="3px";n.style.marginRight=this.margin-7+"px";n.style.marginBottom=this.margin-7+"px"}};n.prototype._alignImgs=function(e){var n,i,r=t.querySelector(this.container_selector).clientWidth;e:while(e.length>0){for(var a=1;a<=e.length;a++){n=e.slice(0,a);i=this._getHeigth(n,r);if(i<this.maxHeight){this._setSize(n,i);e=e.slice(a);continue e}}this._setSize(n,Math.min(this.maxHeight,i));break}};n.prototype.align=function(e){var n=t.querySelectorAll(this.results_selector),i=n.length,r=null,a=null,o=[];for(var s=0;s<i;s++){a=n[s];if(a.previousElementSibling!==r&&o.length>0){this._alignImgs(o);o=[]}o.push(a.querySelector(this.img_selector));r=a}if(o.length>0){this._alignImgs(o)}};n.prototype.watch=function(){var n,i,r,a,o=this,s=t.querySelectorAll(this.results_selector),l=s.length;function u(e){o.align()}function c(e){if(o._alignAllDone){o._alignAllDone=false;setTimeout(function(){o.align();o._alignAllDone=true},100)}}e.addEventListener("resize",c);e.addEventListener("pageshow",u);for(n=0;n<l;n++){i=s[n].querySelector(this.img_selector);if(typeof i!=="undefined"){i.addEventListener("load",c);i.addEventListener("error",c)}}};e.searx.ImageLayout=n})(window,document);searx.ready(function(){searx.on(".result","click",function(){t(this)(true)});searx.on(".result a","focus",function(e){var n=e.target;while(n!==undefined){if(n.classList.contains("result")){if(n.getAttribute("data-vim-selected")===null){t(n)(true)}break}n=n.parentNode}},true);var e={27:{key:"Escape",fun:i,des:"remove focus from the focused input",cat:"Control"},73:{key:"i",fun:l,des:"focus on the search input",cat:"Control"},66:{key:"b",fun:o(-window.innerHeight),des:"scroll one page up",cat:"Navigation"},70:{key:"f",fun:o(window.innerHeight),des:"scroll one page down",cat:"Navigation"},85:{key:"u",fun:o(-window.innerHeight/2),des:"scroll half a page up",cat:"Navigation"},68:{key:"d",fun:o(window.innerHeight/2),des:"scroll half a page down",cat:"Navigation"},71:{key:"g",fun:s(-document.body.scrollHeight,"top"),des:"scroll to the top of the page",cat:"Navigation"},86:{key:"v",fun:s(document.body.scrollHeight,"bottom"),des:"scroll to the bottom of the page",cat:"Navigation"},75:{key:"k",fun:t("up"),des:"select previous search result",cat:"Results"},74:{key:"j",fun:t("down"),des:"select next search result",cat:"Results"},80:{key:"p",fun:r(0),des:"go to previous page",cat:"Results"},78:{key:"n",fun:r(1),des:"go to next page",cat:"Results"},79:{key:"o",fun:u(false),des:"open search result",cat:"Results"},84:{key:"t",fun:u(true),des:"open the result in a new tab",cat:"Results"},82:{key:"r",fun:n,des:"reload page from the server",cat:"Control"},72:{key:"h",fun:d,des:"toggle help window",cat:"Other"}};searx.on(document,"keydown",function(t){if(e.hasOwnProperty(t.keyCode)&&!t.ctrlKey&&!t.altKey&&!t.shiftKey&&!t.metaKey){var n=t.target.tagName.toLowerCase();if(t.keyCode===27){if(n==="input"||n==="select"||n==="textarea"){e[t.keyCode].fun()}}else{if(t.target===document.body||n==="a"||n==="button"){t.preventDefault();e[t.keyCode].fun()}}}});function t(e){return function(t){var n=document.querySelector(".result[data-vim-selected]"),i=e;if(n===null){n=document.querySelector(".result");if(n===null){return}if(e==="down"||e==="up"){i=n}}var r,o=document.querySelectorAll(".result");if(typeof i!=="string"){r=i}else{switch(i){case"visible":var s=document.documentElement.scrollTop||document.body.scrollTop;var l=s+document.documentElement.clientHeight;for(var u=0;u<o.length;u++){r=o[u];var c=r.offsetTop;var d=c+r.clientHeight;if(d<=l&&c>s){break}}break;case"down":r=n.nextElementSibling;if(r===null){r=o[0]}break;case"up":r=n.previousElementSibling;if(r===null){r=o[o.length-1]}break;case"bottom":r=o[o.length-1];break;case"top":default:r=o[0]}}if(r){n.removeAttribute("data-vim-selected");r.setAttribute("data-vim-selected","true");var f=r.querySelector("h3 a")||r.querySelector("a");if(f!==null){f.focus()}if(!t){a()}}}}function n(){document.location.reload(true)}function i(){if(document.activeElement){document.activeElement.blur()}}function r(e){return function(){var t=$('div#pagination button[type="submit"]');if(t.length!==2){console.log("page navigation with this theme is not supported");return}if(e>=0&&e<t.length){t[e].click()}else{console.log("pageButtonClick(): invalid argument")}}}function a(){var e=document.querySelector(".result[data-vim-selected]");if(e===null){return}var t=document.documentElement.scrollTop||document.body.scrollTop,n=document.documentElement.clientHeight,i=e.offsetTop,r=i+e.clientHeight,a=120;if(e.previousElementSibling===null&&r<n){window.scroll(window.scrollX,0);return}if(t>i-a){window.scroll(window.scrollX,i-a)}else{var o=t+n;if(o<r+a){window.scroll(window.scrollX,r-n+a)}}}function o(e){return function(){window.scrollBy(0,e);t("visible")()}}function s(e,n){return function(){window.scrollTo(0,e);t(n)()}}function l(){window.scrollTo(0,0);document.querySelector("#q").focus()}function u(e){return function(){var t=document.querySelector(".result[data-vim-selected] h3 a");if(t!==null){var n=t.getAttribute("href");if(e){window.open(n)}else{window.location.href=n}}}}function c(t){var n={};for(var i in e){var r=e[i];n[r.cat]=n[r.cat]||[];n[r.cat].push(r)}var a=Object.keys(n).sort(function(e,t){return n[t].length-n[e].length});if(a.length===0){return}var o='<a href="#" class="close" aria-label="close" title="close">×</a>';o+="<h3>How to navigate searx with Vim-like hotkeys</h3>";o+="<table>";for(var s=0;s<a.length;s++){var l=n[a[s]];var u=s===a.length-1;var c=s%2===0;if(c){o+="<tr>"}o+="<td>";o+="<h4>"+l[0].cat+"</h4>";o+='<ul class="list-unstyled">';for(var d in l){o+="<li><kbd>"+l[d].key+"</kbd> "+l[d].des+"</li>"}o+="</ul>";o+="</td>";if(!c||u){o+="</tr>"}}o+="</table>";t.innerHTML=o}function d(){var e=document.querySelector("#vim-hotkeys-help");console.log(e);if(e===undefined||e===null){e=document.createElement("div");e.id="vim-hotkeys-help";e.className="dialog-modal";e.style="width: 40%";c(e);var t=document.getElementsByTagName("body")[0];t.appendChild(e)}else{e.classList.toggle("invisible");return}}});(function(e,t,n){"use strict";n.ready(function(){n.on(".searx_overpass_request","click",function(e){this.classList.remove("searx_overpass_request");var i="https://overpass-api.de/api/interpreter?data=";var r=i+"[out:json][timeout:25];(";var a=");out meta;";var o=this.dataset.osmId;var s=this.dataset.osmType;var l=t.querySelector("#"+this.dataset.resultTable);var u=t.querySelector("#"+this.dataset.resultTableLoadicon);var c=["addr:city","addr:country","addr:housenumber","addr:postcode","addr:street"];if(o&&s&&l){var d=null;switch(s){case"node":d=r+"node("+o+");"+a;break;case"way":d=r+"way("+o+");"+a;break;case"relation":d=r+"relation("+o+");"+a;break;default:break}if(d){n.http("GET",d).then(function(e,t){e=JSON.parse(e);if(e&&e.elements&&e.elements[0]){var n=e.elements[0];var i="";for(var r in n.tags){if(n.tags.name===null||c.indexOf(r)==-1){i+="<tr><td>"+r+"</td><td>";switch(r){case"phone":case"fax":i+='<a href="tel:'+n.tags[r].replace(/ /g,"")+'">'+n.tags[r]+"</a>";break;case"email":i+='<a href="mailto:'+n.tags[r]+'">'+n.tags[r]+"</a>";break;case"website":case"url":i+='<a href="'+n.tags[r]+'">'+n.tags[r]+"</a>";break;case"wikidata":i+='<a href="https://www.wikidata.org/wiki/'+n.tags[r]+'">'+n.tags[r]+"</a>";break;case"wikipedia":if(n.tags[r].indexOf(":")!=-1){i+='<a href="https://'+n.tags[r].substring(0,n.tags[r].indexOf(":"))+".wikipedia.org/wiki/"+n.tags[r].substring(n.tags[r].indexOf(":")+1)+'">'+n.tags[r]+"</a>";break}default:i+=n.tags[r];break}i+="</td></tr>"}}u.parentNode.removeChild(u);l.classList.remove("invisible");l.querySelector("tbody").innerHTML=i}}).catch(function(){u.classList.remove("invisible");u.innerHTML="could not load data!"})}}e.preventDefault()});n.on(".searx_init_map","click",function(e){this.classList.remove("searx_init_map");var t=this.dataset.leafletTarget;var i=parseFloat(this.dataset.mapLon);var r=parseFloat(this.dataset.mapLat);var a=parseFloat(this.dataset.mapZoom);var o=JSON.parse(this.dataset.mapBoundingbox);var s=JSON.parse(this.dataset.mapGeojson);n.loadStyle("leaflet/leaflet.css");n.loadScript("leaflet/leaflet.js",function(){var e=null;if(o){var n=L.latLng(o[0],o[2]);var l=L.latLng(o[1],o[3]);e=L.latLngBounds(n,l)}var u=L.map(t);var c="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";var d='Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';var f=new L.TileLayer(c,{minZoom:1,maxZoom:19,attribution:d});var p="https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png";var h='Wikimedia maps beta | Maps data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';var m=new L.TileLayer(p,{minZoom:1,maxZoom:19,attribution:h});if(e){setTimeout(function(){u.fitBounds(e,{maxZoom:17})},0)}else if(i&&r){if(a){u.setView(new L.latLng(r,i),a)}else{u.setView(new L.latLng(r,i),8)}}u.addLayer(f);var g={"OSM Mapnik":f};L.control.layers(g).addTo(u);if(s){L.geoJson(s).addTo(u)}});e.preventDefault()})})})(window,document,window.searx);(function(e,t,n){"use strict";n.ready(function(){n.image_thumbnail_layout=new n.ImageLayout("#urls","#urls .result-images","img.image_thumbnail",200);n.image_thumbnail_layout.watch();n.on(".btn-collapse","click",function(e){var n=this.getAttribute("data-btn-text-collapsed");var i=this.getAttribute("data-btn-text-not-collapsed");var r=this.getAttribute("data-target");var a=t.querySelector(r);var o=this.innerHTML;if(this.classList.contains("collapsed")){o=o.replace(n,i)}else{o=o.replace(i,n)}this.innerHTML=o;this.classList.toggle("collapsed");a.classList.toggle("invisible")});n.on(".media-loader","click",function(e){var n=this.getAttribute("data-target");var i=t.querySelector(n+" > iframe");var r=i.getAttribute("src");if(r===null||r===undefined||r===false){i.setAttribute("src",i.getAttribute("data-src"))}});e.addEventListener("scroll",function(){var e=t.getElementById("backToTop"),n=document.documentElement.scrollTop||document.body.scrollTop;if(e!==null){if(n>=200){e.style.opacity=1}else{e.style.opacity=0}}})})})(window,document,window.searx);(function(e,t,n){"use strict";var i=true,r="q",a;function o(e){if(e.setSelectionRange){var t=e.value.length;e.setSelectionRange(t,t)}}function s(){if(a.value.length>0){var e=document.getElementById("search");setTimeout(e.submit.bind(e),0)}}function l(e){var t=document.getElementById("clear_search");var n=function(){if(e.value.length===0){t.classList.add("empty")}else{t.classList.remove("empty")}};n();t.addEventListener("click",function(){e.value="";e.focus();n()});e.addEventListener("keyup",n,false)}n.ready(function(){a=t.getElementById(r);function u(e){if(i){o(a);i=false}else{}}if(a!==null){l(a);if(n.autocompleter){n.autocomplete=AutoComplete.call(e,{Url:"./autocompleter",EmptyMessage:n.noItemFound,HttpMethod:n.method,MinChars:4,Delay:300},"#"+r);e.addEventListener("resize",function(){var e=new CustomEvent("position");a.dispatchEvent(e)})}a.addEventListener("focus",u,false);a.focus()}if(a!==null&&n.search_on_category_select){t.querySelector(".help").className="invisible";n.on("#categories input","change",function(e){var n,i=t.querySelectorAll('#categories input[type="checkbox"]');for(n=0;n<i.length;n++){if(i[n]!==this&&i[n].checked){i[n].click()}}if(!this.checked){this.click()}s();return false});n.on(t.getElementById("time_range"),"change",s);n.on(t.getElementById("language"),"change",s)}})})(window,document,window.searx);
24+(function(u,c){"use strict";function e(e,t,n,i){this.container_selector=e;this.results_selector=t;this.img_selector=n;this.margin=10;this.maxHeight=i;this._alignAllDone=true}e.prototype._getHeigth=function(e,t){var n=0,i;t-=e.length*this.margin;for(var r=0;r<e.length;r++){i=e[r];if(i.naturalWidth>0&&i.naturalHeight>0){n+=i.naturalWidth/i.naturalHeight}else{n+=1}}return t/n};e.prototype._setSize=function(e,t){var n,i,r=e.length;for(var a=0;a<r;a++){n=e[a];if(n.naturalWidth>0&&n.naturalHeight>0){i=t*n.naturalWidth/n.naturalHeight}else{i=t}n.style.width=i+"px";n.style.height=t+"px";n.style.marginLeft="3px";n.style.marginTop="3px";n.style.marginRight=this.margin-7+"px";n.style.marginBottom=this.margin-7+"px"}};e.prototype._alignImgs=function(e){var t,n,i=c.querySelector(this.container_selector).clientWidth;e:while(e.length>0){for(var r=1;r<=e.length;r++){t=e.slice(0,r);n=this._getHeigth(t,i);if(n<this.maxHeight){this._setSize(t,n);e=e.slice(r);continue e}}this._setSize(t,Math.min(this.maxHeight,n));break}};e.prototype.align=function(e){var t=c.querySelectorAll(this.results_selector),n=t.length,i=null,r=null,a=[];for(var o=0;o<n;o++){r=t[o];if(r.previousElementSibling!==i&&a.length>0){this._alignImgs(a);a=[]}a.push(r.querySelector(this.img_selector));i=r}if(a.length>0){this._alignImgs(a)}};e.prototype.watch=function(){var e,t,n,i,r=this,a=c.querySelectorAll(this.results_selector),o=a.length;function s(e){r.align()}function l(e){if(r._alignAllDone){r._alignAllDone=false;setTimeout(function(){r.align();r._alignAllDone=true},100)}}u.addEventListener("resize",l);u.addEventListener("pageshow",s);for(e=0;e<o;e++){t=a[e].querySelector(this.img_selector);if(typeof t!=="undefined"){t.addEventListener("load",l);t.addEventListener("error",l)}}};u.searx.ImageLayout=e})(window,document);searx.ready(function(){searx.on(".result","click",function(){n(this)(true)});searx.on(".result a","focus",function(e){var t=e.target;while(t!==undefined){if(t.classList.contains("result")){if(t.getAttribute("data-vim-selected")===null){n(t)(true)}break}t=t.parentNode}},true);var d={27:{key:"Escape",fun:t,des:"remove focus from the focused input",cat:"Control"},73:{key:"i",fun:o,des:"focus on the search input",cat:"Control"},66:{key:"b",fun:r(-window.innerHeight),des:"scroll one page up",cat:"Navigation"},70:{key:"f",fun:r(window.innerHeight),des:"scroll one page down",cat:"Navigation"},85:{key:"u",fun:r(-window.innerHeight/2),des:"scroll half a page up",cat:"Navigation"},68:{key:"d",fun:r(window.innerHeight/2),des:"scroll half a page down",cat:"Navigation"},71:{key:"g",fun:a(-document.body.scrollHeight,"top"),des:"scroll to the top of the page",cat:"Navigation"},86:{key:"v",fun:a(document.body.scrollHeight,"bottom"),des:"scroll to the bottom of the page",cat:"Navigation"},75:{key:"k",fun:n("up"),des:"select previous search result",cat:"Results"},74:{key:"j",fun:n("down"),des:"select next search result",cat:"Results"},80:{key:"p",fun:i(0),des:"go to previous page",cat:"Results"},78:{key:"n",fun:i(1),des:"go to next page",cat:"Results"},79:{key:"o",fun:s(false),des:"open search result",cat:"Results"},84:{key:"t",fun:s(true),des:"open the result in a new tab",cat:"Results"},82:{key:"r",fun:e,des:"reload page from the server",cat:"Control"},72:{key:"h",fun:u,des:"toggle help window",cat:"Other"}};searx.on(document,"keydown",function(e){if(d.hasOwnProperty(e.keyCode)&&!e.ctrlKey&&!e.altKey&&!e.shiftKey&&!e.metaKey){var t=e.target.tagName.toLowerCase();if(e.keyCode===27){if(t==="input"||t==="select"||t==="textarea"){d[e.keyCode].fun()}}else{if(e.target===document.body||t==="a"||t==="button"){e.preventDefault();d[e.keyCode].fun()}}}});function n(d){return function(e){var t=document.querySelector(".result[data-vim-selected]"),n=d;if(t===null){t=document.querySelector(".result");if(t===null){return}if(d==="down"||d==="up"){n=t}}var i,r=document.querySelectorAll(".result");if(typeof n!=="string"){i=n}else{switch(n){case"visible":var a=document.documentElement.scrollTop||document.body.scrollTop;var o=a+document.documentElement.clientHeight;for(var s=0;s<r.length;s++){i=r[s];var l=i.offsetTop;var u=l+i.clientHeight;if(u<=o&&l>a){break}}break;case"down":i=t.nextElementSibling;if(i===null){i=r[0]}break;case"up":i=t.previousElementSibling;if(i===null){i=r[r.length-1]}break;case"bottom":i=r[r.length-1];break;case"top":default:i=r[0]}}if(i){t.removeAttribute("data-vim-selected");i.setAttribute("data-vim-selected","true");var c=i.querySelector("h3 a")||i.querySelector("a");if(c!==null){c.focus()}if(!e){f()}}}}function e(){document.location.reload(true)}function t(){if(document.activeElement){document.activeElement.blur()}}function i(t){return function(){var e=$('div#pagination button[type="submit"]');if(e.length!==2){console.log("page navigation with this theme is not supported");return}if(t>=0&&t<e.length){e[t].click()}else{console.log("pageButtonClick(): invalid argument")}}}function f(){var e=document.querySelector(".result[data-vim-selected]");if(e===null){return}var t=document.documentElement.scrollTop||document.body.scrollTop,n=document.documentElement.clientHeight,i=e.offsetTop,r=i+e.clientHeight,a=120;if(e.previousElementSibling===null&&r<n){window.scroll(window.scrollX,0);return}if(t>i-a){window.scroll(window.scrollX,i-a)}else{var o=t+n;if(o<r+a){window.scroll(window.scrollX,r-n+a)}}}function r(e){return function(){window.scrollBy(0,e);n("visible")()}}function a(e,t){return function(){window.scrollTo(0,e);n(t)()}}function o(){window.scrollTo(0,0);document.querySelector("#q").focus()}function s(n){return function(){var e=document.querySelector(".result[data-vim-selected] h3 a");if(e!==null){var t=e.getAttribute("href");if(n){window.open(t)}else{window.location.href=t}}}}function l(e){var n={};for(var t in d){var i=d[t];n[i.cat]=n[i.cat]||[];n[i.cat].push(i)}var r=Object.keys(n).sort(function(e,t){return n[t].length-n[e].length});if(r.length===0){return}var a='<a href="#" class="close" aria-label="close" title="close">×</a>';a+="<h3>How to navigate searx with Vim-like hotkeys</h3>";a+="<table>";for(var o=0;o<r.length;o++){var s=n[r[o]];var l=o===r.length-1;var u=o%2===0;if(u){a+="<tr>"}a+="<td>";a+="<h4>"+s[0].cat+"</h4>";a+='<ul class="list-unstyled">';for(var c in s){a+="<li><kbd>"+s[c].key+"</kbd> "+s[c].des+"</li>"}a+="</ul>";a+="</td>";if(!u||l){a+="</tr>"}}a+="</table>";e.innerHTML=a}function u(){var e=document.querySelector("#vim-hotkeys-help");console.log(e);if(e===undefined||e===null){e=document.createElement("div");e.id="vim-hotkeys-help";e.className="dialog-modal";e.style="width: 40%";l(e);var t=document.getElementsByTagName("body")[0];t.appendChild(e)}else{e.classList.toggle("invisible");return}}});(function(e,c,v){"use strict";v.ready(function(){v.on(".searx_overpass_request","click",function(e){this.classList.remove("searx_overpass_request");var t="https://overpass-api.de/api/interpreter?data=";var n=t+"[out:json][timeout:25];(";var i=");out meta;";var r=this.dataset.osmId;var a=this.dataset.osmType;var o=c.querySelector("#"+this.dataset.resultTable);var s=c.querySelector("#"+this.dataset.resultTableLoadicon);var l=["addr:city","addr:country","addr:housenumber","addr:postcode","addr:street"];if(r&&a&&o){var u=null;switch(a){case"node":u=n+"node("+r+");"+i;break;case"way":u=n+"way("+r+");"+i;break;case"relation":u=n+"relation("+r+");"+i;break;default:break}if(u){v.http("GET",u).then(function(e,t){e=JSON.parse(e);if(e&&e.elements&&e.elements[0]){var n=e.elements[0];var i="";for(var r in n.tags){if(n.tags.name===null||l.indexOf(r)==-1){i+="<tr><td>"+r+"</td><td>";switch(r){case"phone":case"fax":i+='<a href="tel:'+n.tags[r].replace(/ /g,"")+'">'+n.tags[r]+"</a>";break;case"email":i+='<a href="mailto:'+n.tags[r]+'">'+n.tags[r]+"</a>";break;case"website":case"url":i+='<a href="'+n.tags[r]+'">'+n.tags[r]+"</a>";break;case"wikidata":i+='<a href="https://www.wikidata.org/wiki/'+n.tags[r]+'">'+n.tags[r]+"</a>";break;case"wikipedia":if(n.tags[r].indexOf(":")!=-1){i+='<a href="https://'+n.tags[r].substring(0,n.tags[r].indexOf(":"))+".wikipedia.org/wiki/"+n.tags[r].substring(n.tags[r].indexOf(":")+1)+'">'+n.tags[r]+"</a>";break}default:i+=n.tags[r];break}i+="</td></tr>"}}s.parentNode.removeChild(s);o.classList.remove("invisible");o.querySelector("tbody").innerHTML=i}}).catch(function(){s.classList.remove("invisible");s.innerHTML="could not load data!"})}}e.preventDefault()});v.on(".searx_init_map","click",function(e){this.classList.remove("searx_init_map");var d=this.dataset.leafletTarget;var f=parseFloat(this.dataset.mapLon);var p=parseFloat(this.dataset.mapLat);var h=parseFloat(this.dataset.mapZoom);var m=JSON.parse(this.dataset.mapBoundingbox);var g=JSON.parse(this.dataset.mapGeojson);v.loadStyle("leaflet/leaflet.css");v.loadScript("leaflet/leaflet.js",function(){var e=null;if(m){var t=L.latLng(m[0],m[2]);var n=L.latLng(m[1],m[3]);e=L.latLngBounds(t,n)}var i=L.map(d);var r="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";var a='Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';var o=new L.TileLayer(r,{minZoom:1,maxZoom:19,attribution:a});var s="https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png";var l='Wikimedia maps beta | Maps data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';var u=new L.TileLayer(s,{minZoom:1,maxZoom:19,attribution:l});if(e){setTimeout(function(){i.fitBounds(e,{maxZoom:17})},0)}else if(f&&p){if(h){i.setView(new L.latLng(p,f),h)}else{i.setView(new L.latLng(p,f),8)}}i.addLayer(o);var c={"OSM Mapnik":o};L.control.layers(c).addTo(i);if(g){L.geoJson(g).addTo(i)}});e.preventDefault()})})})(window,document,window.searx);(function(e,o,t){"use strict";t.ready(function(){t.image_thumbnail_layout=new t.ImageLayout("#urls","#urls .result-images","img.image_thumbnail",200);t.image_thumbnail_layout.watch();t.on(".btn-collapse","click",function(e){var t=this.getAttribute("data-btn-text-collapsed");var n=this.getAttribute("data-btn-text-not-collapsed");var i=this.getAttribute("data-target");var r=o.querySelector(i);var a=this.innerHTML;if(this.classList.contains("collapsed")){a=a.replace(t,n)}else{a=a.replace(n,t)}this.innerHTML=a;this.classList.toggle("collapsed");r.classList.toggle("invisible")});t.on(".media-loader","click",function(e){var t=this.getAttribute("data-target");var n=o.querySelector(t+" > iframe");var i=n.getAttribute("src");if(i===null||i===undefined||i===false){n.setAttribute("src",n.getAttribute("data-src"))}});e.addEventListener("scroll",function(){var e=o.getElementById("backToTop"),t=document.documentElement.scrollTop||document.body.scrollTop;if(e!==null){if(t>=200){e.style.opacity=1}else{e.style.opacity=0}}})})})(window,document,window.searx);(function(t,i,n){"use strict";var r=true,a="q",o;function s(e){if(e.setSelectionRange){var t=e.value.length;e.setSelectionRange(t,t)}}function l(){if(o.value.length>0){var e=document.getElementById("search");setTimeout(e.submit.bind(e),0)}}function u(e){var t=document.getElementById("clear_search");var n=function(){if(e.value.length===0){t.classList.add("empty")}else{t.classList.remove("empty")}};n();t.addEventListener("click",function(){e.value="";e.focus();n()});e.addEventListener("keyup",n,false)}n.ready(function(){o=i.getElementById(a);function e(e){if(r){s(o);r=false}else{}}if(o!==null){u(o);if(n.autocompleter){n.autocomplete=AutoComplete.call(t,{Url:"./autocompleter",EmptyMessage:n.no_item_found,HttpMethod:n.method,MinChars:4,Delay:300},"#"+a);t.addEventListener("resize",function(){var e=new CustomEvent("position");o.dispatchEvent(e)})}o.addEventListener("focus",e,false);o.focus()}if(o!==null&&n.search_on_category_select){i.querySelector(".help").className="invisible";n.on("#categories input","change",function(e){var t,n=i.querySelectorAll('#categories input[type="checkbox"]');for(t=0;t<n.length;t++){if(n[t]!==this&&n[t].checked){n[t].click()}}if(!this.checked){this.click()}l();return false});n.on(i.getElementById("time_range"),"change",l);n.on(i.getElementById("language"),"change",l)}})})(window,document,window.searx);
23//# sourceMappingURL=searx.min.js.map
25//# sourceMappingURL=searx.min.js.map
searx/static/themes/simple/js/searx.min.js.map+1−1
@@ -1 +1 @@
1−{"version":3,"sources":["searx.js"],"names":["w","d","searx","Element","ElementPrototype","matches","matchesSelector","webkitMatchesSelector","msMatchesSelector","selector","node","this","nodes","parentNode","document","querySelectorAll","i","prototype","callbackSafe","callback","el","e","call","exception","console","log","on","obj","eventType","useCapture","addEventListener","target","srcElement","found","parentElement","ready","readyState","bind","http","method","url","req","XMLHttpRequest","resolve","reject","promise","then","catch","open","onload","status","response","responseType","Error","statusText","onerror","onabort","send","ex","loadStyle","src","path","staticPath","id","replace","s","getElementById","createElement","setAttribute","body","appendChild","loadScript","hasAttribute","apply","insertBefore","newNode","referenceNode","element","insertAfter","nextSibling","classList","add","window","f","exports","module","define","amd","g","global","self","AutoComplete","t","n","r","o","u","a","require","code","l","length","1","ConditionOperator","EventType","params","Array","isArray","forEach","elements","input","specificParams","merge","defaults","DOMResults","create","Input","nodeName","match","getAttribute","_Position","$Listeners","blur","_Blur","destroy","focus","_Focus","keyup","event","KEYUP","keydown","KEYDOWN","position","getEventsByType","type","mappings","key","KeyboardMappings","Event","undefined","eventIdentifier","condition","mapping","Operator","AND","OR","Not","hasOwnProperty","Is","keyCode","From","To","name","Conditions","Callback","makeRequest","propertyHttpHeaders","Object","getOwnPropertyNames","HttpHeaders","request","_HttpMethod","_Url","queryParams","_Pre","queryParamsStringify","encodeURIComponent","_QueryArg","indexOf","setRequestHeader","onreadystatechange","$Cache","ajax","timeout","$AjaxTimer","clearTimeout","setTimeout","Delay","Request","abort","cache","_Cache","removeEventListener","removeChild","tmp","arguments","EmptyMessage","Highlight","getRegex","value","RegExp","transform","Content-type","Limit","MinChars","HttpMethod","QueryArg","Url","Enter","liActive","querySelector","preventDefault","_Select","KeyUpAndDown_down","KeyUpAndDown_up","first","last","active","currentIndex","children","lisCount","getElementsByTagName","remove","item","AlphaNum","oldValue","currentValue","_MinChars","_Render","_Post","_Open","_EmptyMessage","emptyMessage","_Limit","limit","isNaN","parseInt","minchars","_Highlight","label","now","li","onclick","onmouseenter","offsetTop","offsetHeight","offsetLeft","clientWidth","ul","_RenderRaw","_RenderResponseItems","hasChildNodes","childNodes","reverse","Math","min","abs","innerHTML","Label","Value","returnResponse","json","JSON","parse","keys","push","ImageLayout","container_selector","results_selector","img_selector","maxHeight","margin","_alignAllDone","_getHeigth","images","width","img","naturalWidth","naturalHeight","_setSize","height","imgWidth","imagesLength","style","marginLeft","marginTop","marginRight","marginBottom","_alignImgs","imgGroup","slice","h","containerWidth","align","results_selectorNode","results_length","previous","current","previousElementSibling","watch","imgNodeLength","results_nodes","throttleAlign","highlightResult","contains","vimKeys","27","fun","removeFocus","des","cat","73","searchInputFocus","66","scrollPage","innerHeight","70","85","68","71","scrollPageTo","scrollHeight","86","75","74","80","pageButtonClick","78","79","openResult","84","82","reloadPage","72","toggleHelp","ctrlKey","altKey","shiftKey","metaKey","tagName","toLowerCase","which","noScroll","effectiveWhich","next","results","top","documentElement","scrollTop","bot","clientHeight","etop","ebot","nextElementSibling","removeAttribute","link","scrollPageToSelected","location","reload","activeElement","num","buttons","$","click","sel","wtop","wheight","offset","scroll","scrollX","wbot","amount","scrollBy","nav","scrollTo","newTab","href","initHelpContent","divElement","categories","k","sorted","sort","b","html","lastCategory","cj","helpPanel","className","toggle","overpass_url","query_start","query_end","osm_id","dataset","osmId","osm_type","osmType","result_table","resultTable","result_table_loadicon","resultTableLoadicon","osm_ignore_tags","query","contentType","newHtml","row","tags","substring","leaflet_target","leafletTarget","map_lon","parseFloat","mapLon","map_lat","mapLat","map_zoom","mapZoom","map_boundingbox","mapBoundingbox","map_geojson","mapGeojson","map_bounds","southWest","L","latLng","northEast","latLngBounds","map","osmMapnikUrl","osmMapnikAttrib","osmMapnik","TileLayer","minZoom","maxZoom","attribution","osmWikimediaUrl","osmWikimediaAttrib","osmWikimedia","fitBounds","setView","addLayer","baseLayers","OSM Mapnik","control","layers","addTo","geoJson","image_thumbnail_layout","btnLabelCollapsed","btnLabelNotCollapsed","targetElement","iframe_load","srctest","opacity","firstFocus","qinput_id","qinput","placeCursorAtEnd","setSelectionRange","len","submitIfQuery","search","submit","createClearButton","cs","updateClearButton","placeCursorAtEndOnce","autocompleter","autocomplete","noItemFound","CustomEvent","dispatchEvent","search_on_category_select","checked"],"mappings":";;CAiBA,SAAUA,EAAGC,EAAGC,GAEd,aAMA,GAAIF,EAAEG,QAAS,EACb,SAAUC,GACRA,EAAiBC,QAAUD,EAAiBC,SAC5CD,EAAiBE,iBACjBF,EAAiBG,uBACjBH,EAAiBI,mBACjB,SAASC,GACP,IAAIC,EAAOC,KAAMC,GAASF,EAAKG,YAAcH,EAAKI,UAAUC,iBAAiBN,GAAWO,GAAK,EAC7F,MAAOJ,IAAQI,IAAMJ,EAAMI,IAAMN,GACjC,QAASE,EAAMI,KARnB,CAUGb,QAAQc,WAGb,SAASC,EAAaC,EAAUC,EAAIC,GAClC,IACEF,EAASG,KAAKF,EAAIC,GAClB,MAAOE,GACPC,QAAQC,IAAIF,IAIhBrB,EAAQA,MAERA,EAAMwB,GAAK,SAASC,EAAKC,EAAWT,EAAUU,GAC5CA,EAAaA,GAAc,MAC3B,UAAWF,IAAQ,SAAU,CAE3BA,EAAIG,iBAAiBF,EAAWT,EAAUU,OACrC,CAEL5B,EAAE6B,iBAAiBF,EAAW,SAASP,GACrC,IAAID,EAAKC,EAAEU,QAAUV,EAAEW,WAAYC,EAAQ,MAC3C,MAAOb,GAAMA,EAAGf,SAAWe,IAAOnB,KAAOgC,EAAQb,EAAGf,QAAQsB,IAAOP,EAAKA,EAAGc,cAC3E,GAAID,EAAOf,EAAaC,EAAUC,EAAIC,IACrCQ,KAIP3B,EAAMiC,MAAQ,SAAShB,GACrB,GAAIL,SAASsB,YAAc,UAAW,CACpCjB,EAASG,KAAKtB,OACT,CACLA,EAAE8B,iBAAiB,mBAAoBX,EAASkB,KAAKrC,MAIzDE,EAAMoC,KAAO,SAASC,EAAQC,EAAKrB,GACjC,IAAIsB,EAAM,IAAIC,eACdC,EAAU,aACVC,EAAS,aACTC,GACEC,KAAM,SAAS3B,GAAYwB,EAAUxB,EAAU,OAAO0B,GACtDE,MAAO,SAAS5B,GAAYyB,EAASzB,EAAU,OAAO0B,IAGxD,IACEJ,EAAIO,KAAKT,EAAQC,EAAK,MAGtBC,EAAIQ,OAAS,WACX,GAAIR,EAAIS,QAAU,IAAK,CACrBP,EAAQF,EAAIU,SAAUV,EAAIW,kBACrB,CACLR,EAAOS,MAAMZ,EAAIa,eAKrBb,EAAIc,QAAU,WACZX,EAAOS,MAAM,mBAGfZ,EAAIe,QAAU,WACZZ,EAAOS,MAAM,4BAIfZ,EAAIgB,OACJ,MAAOC,GACPd,EAAOc,GAGT,OAAOb,GAGT3C,EAAMyD,UAAY,SAASC,GACzB,IAAIC,EAAO3D,EAAM4D,WAAaF,EAC9BG,EAAK,SAAWH,EAAII,QAAQ,IAAK,KACjCC,EAAIhE,EAAEiE,eAAeH,GACrB,GAAIE,IAAM,KAAM,CACdA,EAAIhE,EAAEkE,cAAc,QACpBF,EAAEG,aAAa,KAAML,GACrBE,EAAEG,aAAa,MAAO,cACtBH,EAAEG,aAAa,OAAQ,YACvBH,EAAEG,aAAa,OAAQP,GACvB5D,EAAEoE,KAAKC,YAAYL,KAIvB/D,EAAMqE,WAAa,SAASX,EAAKzC,GAC/B,IAAI0C,EAAO3D,EAAM4D,WAAaF,EAC9BG,EAAK,UAAYH,EAAII,QAAQ,IAAK,KAClCC,EAAIhE,EAAEiE,eAAeH,GACrB,GAAIE,IAAM,KAAM,CACdA,EAAIhE,EAAEkE,cAAc,UACpBF,EAAEG,aAAa,KAAML,GACrBE,EAAEG,aAAa,MAAOP,GACtBI,EAAEhB,OAAS9B,EACX8C,EAAEV,QAAU,WACVU,EAAEG,aAAa,QAAS,MAE1BnE,EAAEoE,KAAKC,YAAYL,QACd,IAAKA,EAAEO,aAAa,SAAU,CACnC,IACErD,EAASsD,MAAMR,MACf,MAAO1C,GACPC,QAAQC,IAAIF,QAET,CACLC,QAAQC,IAAI,mCAAqCoC,EAAO,mBAI5D3D,EAAMwE,aAAe,SAAUC,EAASC,GACtCC,QAAQhE,WAAW6D,aAAaC,EAASC,IAG3C1E,EAAM4E,YAAc,SAASH,EAASC,GACpCA,EAAc/D,WAAW6D,aAAaC,EAASC,EAAcG,cAG/D7E,EAAMwB,GAAG,SAAU,QAAS,SAASL,GACnC,IAAID,EAAKC,EAAEU,QAAUV,EAAEW,WACvBrB,KAAKE,WAAWmE,UAAUC,IAAI,eAGhC,OAAO/E,GAjJT,CAkJGgF,OAAQpE,SAAUoE,OAAOhF,QAC3B,SAAUiF,GAAG,UAAUC,UAAU,iBAAiBC,SAAS,YAAY,CAACA,OAAOD,QAAQD,SAAS,UAAUG,SAAS,YAAYA,OAAOC,IAAI,CAACD,UAAUH,OAAO,CAAC,IAAIK,EAAE,UAAUN,SAAS,YAAY,CAACM,EAAEN,YAAY,UAAUO,SAAS,YAAY,CAACD,EAAEC,YAAY,UAAUC,OAAO,YAAY,CAACF,EAAEE,SAAS,CAACF,EAAE7E,KAAK6E,EAAEG,aAAeR,MAAjU,CAAwU,WAAW,IAAIG,EAAOD,EAAOD,EAAQ,OAAO,SAAU/D,EAAEuE,EAAEC,EAAEC,GAAG,SAAS7B,EAAE8B,EAAEC,GAAG,IAAIH,EAAEE,GAAG,CAAC,IAAIH,EAAEG,GAAG,CAAC,IAAIE,SAASC,SAAS,YAAYA,QAAQ,IAAIF,GAAGC,EAAE,OAAOA,EAAEF,GAAG,GAAG,GAAG/E,EAAE,OAAOA,EAAE+E,GAAG,GAAG,IAAIZ,EAAE,IAAI9B,MAAM,uBAAuB0C,EAAE,KAAK,MAAMZ,EAAEgB,KAAK,mBAAmBhB,EAAE,IAAIiB,EAAEP,EAAEE,IAAIX,YAAYQ,EAAEG,GAAG,GAAGzE,KAAK8E,EAAEhB,QAAQ,SAAS/D,GAAG,IAAIwE,EAAED,EAAEG,GAAG,GAAG1E,GAAG,OAAO4C,EAAE4B,EAAEA,EAAExE,IAAI+E,EAAEA,EAAEhB,QAAQ/D,EAAEuE,EAAEC,EAAEC,GAAG,OAAOD,EAAEE,GAAGX,QAAQ,IAAIpE,SAASkF,SAAS,YAAYA,QAAQ,IAAI,IAAIH,EAAE,EAAEA,EAAED,EAAEO,OAAON,IAAI9B,EAAE6B,EAAEC,IAAI,OAAO9B,EAAvb,EAA4bqC,GAAG,SAASJ,EAAQb,EAAOD;;;;;;;;;AAU50B,aACA,IAAImB,GACJ,SAAWA,GACPA,EAAkBA,EAAkB,OAAS,GAAK,MAClDA,EAAkBA,EAAkB,MAAQ,GAAK,MAFrD,CAGGA,IAAsBA,OACzB,IAAIC,GACJ,SAAWA,GACPA,EAAUA,EAAU,WAAa,GAAK,UACtCA,EAAUA,EAAU,SAAW,GAAK,SAFxC,CAGGA,IAAcA,OAOjB,IAAIb,EAAgB,WAEhB,SAASA,EAAac,EAAQhG,GAC1B,GAAIgG,SAAgB,EAAG,CAAEA,KACzB,GAAIhG,SAAkB,EAAG,CAAEA,EAAW,sBACtC,GAAIiG,MAAMC,QAAQlG,GAAW,CACzBA,EAASmG,QAAQ,SAAU3C,GACvB,IAAI0B,EAAac,EAAQxC,UAG5B,UAAWxD,GAAY,SAAU,CAClC,IAAIoG,EAAW/F,SAASC,iBAAiBN,GACzCiG,MAAMzF,UAAU2F,QAAQtF,KAAKuF,EAAU,SAAUC,GAC7C,IAAInB,EAAac,EAAQK,SAG5B,CACD,IAAIC,EAAiBpB,EAAaqB,MAAMrB,EAAasB,SAAUR,GAC3DS,WAAYpG,SAASqD,cAAc,SAEvCwB,EAAa1E,UAAUkG,OAAOJ,EAAgBtG,GAC9C,OAAOsG,GAGfpB,EAAa1E,UAAUkG,OAAS,SAAUV,EAAQ5B,GAC9C4B,EAAOW,MAAQvC,EACf,GAAI4B,EAAOW,MAAMC,SAASC,MAAM,cAAgBb,EAAOW,MAAM5C,aAAa,UAAY,OAASiC,EAAOW,MAAMG,aAAa,QAAQD,MAAM,mBAAoB,CACvJb,EAAOW,MAAMhD,aAAa,eAAgB,OAC1CqC,EAAOe,UAAUf,GACjBA,EAAOW,MAAMvG,WAAWyD,YAAYmC,EAAOS,YAC3CT,EAAOgB,YACHC,KAAMjB,EAAOkB,MAAMtF,KAAKoE,GACxBmB,QAASjC,EAAa1E,UAAU2G,QAAQvF,KAAK,KAAMoE,GACnDoB,MAAOpB,EAAOqB,OAAOzF,KAAKoE,GAC1BsB,MAAOpC,EAAa1E,UAAU+G,MAAM3F,KAAK,KAAMoE,EAAQD,EAAUyB,OACjEC,QAASvC,EAAa1E,UAAU+G,MAAM3F,KAAK,KAAMoE,EAAQD,EAAU2B,SACnEC,SAAU3B,EAAOe,UAAUnF,KAAKoE,IAEpC,IAAK,IAAIuB,KAASvB,EAAOgB,WAAY,CACjChB,EAAOW,MAAMtF,iBAAiBkG,EAAOvB,EAAOgB,WAAWO,OAInErC,EAAa1E,UAAUoH,gBAAkB,SAAU5B,EAAQ6B,GACvD,IAAIC,KACJ,IAAK,IAAIC,KAAO/B,EAAOgC,iBAAkB,CACrC,IAAIT,EAAQxB,EAAUyB,MACtB,GAAIxB,EAAOgC,iBAAiBD,GAAKE,QAAUC,UAAW,CAClDX,EAAQvB,EAAOgC,iBAAiBD,GAAKE,MAEzC,GAAIV,GAASM,EAAM,CACfC,EAASC,GAAO/B,EAAOgC,iBAAiBD,IAGhD,OAAOD,GAEX5C,EAAa1E,UAAU+G,MAAQ,SAAUvB,EAAQ6B,EAAMN,GACnD,IAAIY,EAAkB,SAAUC,GAC5B,GAAKvB,IAAU,MAAQwB,EAAQC,UAAYxC,EAAkByC,KAAS1B,IAAU,OAASwB,EAAQC,UAAYxC,EAAkB0C,GAAK,CAChIJ,EAAYlD,EAAaqB,OACrBkC,IAAK,OACNL,GACH,GAAIA,EAAUM,eAAe,MAAO,CAChC,GAAIN,EAAUO,IAAMpB,EAAMqB,QAAS,CAC/B/B,GAASuB,EAAUK,QAElB,CACD5B,EAAQuB,EAAUK,UAGrB,GAAIL,EAAUM,eAAe,SAAWN,EAAUM,eAAe,MAAO,CACzE,GAAInB,EAAMqB,SAAWR,EAAUS,MAAQtB,EAAMqB,SAAWR,EAAUU,GAAI,CAClEjC,GAASuB,EAAUK,QAElB,CACD5B,EAAQuB,EAAUK,QAKlC,IAAK,IAAIM,KAAQ7D,EAAa1E,UAAUoH,gBAAgB5B,EAAQ6B,GAAO,CACnE,IAAIQ,EAAUnD,EAAaqB,OACvB+B,SAAUxC,EAAkByC,KAC7BvC,EAAOgC,iBAAiBe,IAAQlC,EAAQf,EAAkByC,KAAOF,EAAQC,SAC5ED,EAAQW,WAAW7C,QAAQgC,GAC3B,GAAItB,IAAU,KAAM,CAChBwB,EAAQY,SAASpI,KAAKmF,EAAQuB,MAI1CrC,EAAa1E,UAAU0I,YAAc,SAAUlD,EAAQtF,GACnD,IAAIyI,EAAsBC,OAAOC,oBAAoBrD,EAAOsD,aAAcC,EAAU,IAAItH,eAAkBH,EAASkE,EAAOwD,cAAezH,EAAMiE,EAAOyD,OAAQC,EAAc1D,EAAO2D,OAAQC,EAAuBC,mBAAmB7D,EAAO8D,aAAe,IAAMD,mBAAmBH,GACpR,GAAI5H,EAAO+E,MAAM,UAAW,CACxB,GAAI9E,EAAIgI,QAAQ,QAAU,EAAG,CACzBhI,GAAO,IAAM6H,MAEZ,CACD7H,GAAO,IAAM6H,GAGrBL,EAAQhH,KAAKT,EAAQC,EAAK,MAC1B,IAAK,IAAIxB,EAAI4I,EAAoBvD,OAAS,EAAGrF,GAAK,EAAGA,IAAK,CACtDgJ,EAAQS,iBAAiBb,EAAoB5I,GAAIyF,EAAOsD,YAAYH,EAAoB5I,KAE5FgJ,EAAQU,mBAAqB,WACzB,GAAIV,EAAQ5H,YAAc,GAAK4H,EAAQ9G,QAAU,IAAK,CAClDuD,EAAOkE,OAAOR,GAAeH,EAAQ7G,SACrChC,EAAS6I,EAAQ7G,YAGzB,OAAO6G,GAEXrE,EAAa1E,UAAU2J,KAAO,SAAUnE,EAAQuD,EAASa,GACrD,GAAIA,SAAiB,EAAG,CAAEA,EAAU,KACpC,GAAIpE,EAAOqE,WAAY,CACnB5F,OAAO6F,aAAatE,EAAOqE,YAE/B,GAAID,IAAY,KAAM,CAClBpE,EAAOqE,WAAa5F,OAAO8F,WAAWrF,EAAa1E,UAAU2J,KAAKvI,KAAK,KAAMoE,EAAQuD,EAAS,OAAQvD,EAAOwE,WAE5G,CACD,GAAIxE,EAAOyE,QAAS,CAChBzE,EAAOyE,QAAQC,QAEnB1E,EAAOyE,QAAUlB,EACjBvD,EAAOyE,QAAQzH,KAAKgD,EAAO8D,YAAc,IAAM9D,EAAO2D,UAG9DzE,EAAa1E,UAAUmK,MAAQ,SAAU3E,EAAQtF,GAC7C,IAAIgC,EAAWsD,EAAO4E,OAAO5E,EAAO2D,QACpC,GAAIjH,IAAawF,UAAW,CACxB,IAAIqB,EAAUrE,EAAa1E,UAAU0I,YAAYlD,EAAQtF,GACzDwE,EAAa1E,UAAU2J,KAAKnE,EAAQuD,OAEnC,CACD7I,EAASgC,KAGjBwC,EAAa1E,UAAU2G,QAAU,SAAUnB,GACvC,IAAK,IAAIuB,KAASvB,EAAOgB,WAAY,CACjChB,EAAOW,MAAMkE,oBAAoBtD,EAAOvB,EAAOgB,WAAWO,IAE9DvB,EAAOS,WAAWrG,WAAW0K,YAAY9E,EAAOS,aAEpD,OAAOvB,EAhJQ,GAkJnBA,EAAaqB,MAAQ,WACjB,IAAIA,KAAYwE,EAChB,IAAK,IAAIxK,EAAI,EAAGA,EAAIyK,UAAUpF,OAAQrF,IAAK,CACvC,IAAKwK,KAAOC,UAAUzK,GAAI,CACtBgG,EAAMwE,GAAOC,UAAUzK,GAAGwK,IAGlC,OAAOxE,GAEXrB,EAAasB,UACTgE,MAAO,IACPS,aAAc,iBACdC,WACIC,SAAU,SAAUC,GAChB,OAAO,IAAIC,OAAOD,EAAO,OAE7BE,UAAW,SAAUF,GACjB,MAAO,WAAaA,EAAQ,cAGpC9B,aACIiC,eAAgB,qCAEpBC,MAAO,EACPC,SAAU,EACVC,WAAY,MACZC,SAAU,IACVC,IAAK,KACL5D,kBACI6D,OACI7C,aACQL,GAAI,GACJF,IAAK,QAEbQ,SAAU,SAAU1B,GAChB,GAAIrH,KAAKuG,WAAWK,aAAa,SAASiD,QAAQ,UAAY,EAAG,CAC7D,IAAI+B,EAAW5L,KAAKuG,WAAWsF,cAAc,aAC7C,GAAID,IAAa,KAAM,CACnBvE,EAAMyE,iBACN9L,KAAK+L,QAAQH,GACb5L,KAAKuG,WAAW9C,aAAa,QAAS,mBAIlD2E,SAAUxC,EAAkByC,IAC5BN,MAAOlC,EAAU2B,SAErBwE,mBACIlD,aACQL,GAAI,GACJF,IAAK,QAGLE,GAAI,GACJF,IAAK,QAEbQ,SAAU,SAAU1B,GAChBA,EAAMyE,kBAEV1D,SAAUxC,EAAkB0C,GAC5BP,MAAOlC,EAAU2B,SAErByE,iBACInD,aACQL,GAAI,GACJF,IAAK,QAGLE,GAAI,GACJF,IAAK,QAEbQ,SAAU,SAAU1B,GAChBA,EAAMyE,iBACN,IAAII,EAAQlM,KAAKuG,WAAWsF,cAAc,+BAAgCM,EAAOnM,KAAKuG,WAAWsF,cAAc,8BAA+BO,EAASpM,KAAKuG,WAAWsF,cAAc,aACrL,GAAIO,EAAQ,CACR,IAAIC,EAAetG,MAAMzF,UAAUuJ,QAAQlJ,KAAKyL,EAAOlM,WAAWoM,SAAUF,GAAS3E,EAAW4E,GAAgBhF,EAAMqB,QAAU,IAAK6D,EAAWvM,KAAKuG,WAAWiG,qBAAqB,MAAM9G,OAC3L,GAAI+B,EAAW,EAAG,CACdA,EAAW8E,EAAW,OAErB,GAAI9E,GAAY8E,EAAU,CAC3B9E,EAAW,EAEf2E,EAAO/H,UAAUoI,OAAO,UACxBL,EAAO7K,cAAc+K,SAASI,KAAKjF,GAAUpD,UAAUC,IAAI,eAE1D,GAAI6H,GAAQ9E,EAAMqB,SAAW,GAAI,CAClCyD,EAAK9H,UAAUC,IAAI,eAElB,GAAI4H,EAAO,CACZA,EAAM7H,UAAUC,IAAI,YAG5B8D,SAAUxC,EAAkB0C,GAC5BP,MAAOlC,EAAUyB,OAErBqF,UACI7D,aACQL,GAAI,GACJF,IAAK,OAELI,KAAM,GACNC,GAAI,GACJL,IAAK,OAEbQ,SAAU,WACN,IAAI6D,EAAW5M,KAAKyG,MAAMG,aAAa,+BAAgCiG,EAAe7M,KAAKyJ,OAC3F,GAAIoD,IAAiB,IAAMA,EAAanH,QAAU1F,KAAK8M,YAAa,CAChE,IAAKF,GAAYC,GAAgBD,EAAU,CACvC5M,KAAKuG,WAAW9C,aAAa,QAAS,qBAE1CuB,EAAa1E,UAAUmK,MAAMzK,KAAM,SAAUwC,GACzCxC,KAAK+M,QAAQ/M,KAAKgN,MAAMxK,IACxBxC,KAAKiN,SACPvL,KAAK1B,SAGfoI,SAAUxC,EAAkByC,IAC5BN,MAAOlC,EAAUyB,QAGzBf,WAAY,KACZgE,QAAS,KACT9D,MAAO,KAIPyG,cAAe,WACX,IAAIC,EAAe,GACnB,GAAInN,KAAKyG,MAAM5C,aAAa,mCAAoC,CAC5DsJ,EAAenN,KAAKyG,MAAMG,aAAa,wCAEtC,GAAI5G,KAAK+K,eAAiB,MAAO,CAClCoC,EAAenN,KAAK+K,iBAEnB,CACDoC,EAAe,GAEnB,OAAOA,GAKXC,OAAQ,WACJ,IAAIC,EAAQrN,KAAKyG,MAAMG,aAAa,2BACpC,GAAI0G,MAAMD,IAAUA,IAAU,KAAM,CAChC,OAAOrN,KAAKsL,MAEhB,OAAOiC,SAASF,EAAO,KAK3BP,UAAW,WACP,IAAIU,EAAWxN,KAAKyG,MAAMG,aAAa,8BACvC,GAAI0G,MAAME,IAAaA,IAAa,KAAM,CACtC,OAAOxN,KAAKuL,SAEhB,OAAOgC,SAASC,EAAU,KAK9BC,WAAY,SAAUC,GAClB,OAAOA,EAAMrK,QAAQrD,KAAKgL,UAAUC,SAASjL,KAAKyJ,QAASzJ,KAAKgL,UAAUI,YAK9E9B,YAAa,WACT,GAAItJ,KAAKyG,MAAM5C,aAAa,4BAA6B,CACrD,OAAO7D,KAAKyG,MAAMG,aAAa,4BAEnC,OAAO5G,KAAKwL,YAKhB5B,UAAW,WACP,GAAI5J,KAAKyG,MAAM5C,aAAa,gCAAiC,CACzD,OAAO7D,KAAKyG,MAAMG,aAAa,gCAEnC,OAAO5G,KAAKyL,UAKhBlC,KAAM,WACF,GAAIvJ,KAAKyG,MAAM5C,aAAa,qBAAsB,CAC9C,OAAO7D,KAAKyG,MAAMG,aAAa,qBAEnC,OAAO5G,KAAK0L,KAKhB1E,MAAO,SAAU2G,GACb,GAAIA,IAAQ,KAAM,CACd3N,KAAKuG,WAAW9C,aAAa,QAAS,gBACtCzD,KAAKyG,MAAMhD,aAAa,8BAA+BzD,KAAKyG,MAAMyE,WAEjE,CACD,IAAIpF,EAAS9F,KACbqK,WAAW,WACPvE,EAAOkB,MAAM,OACd,OAMX0D,OAAQ,SAAUQ,GACd,OAAOlL,KAAKgK,OAAOkB,IAKvB/D,OAAQ,WACJ,IAAIyF,EAAW5M,KAAKyG,MAAMG,aAAa,+BACvC,KAAMgG,GAAY5M,KAAKyG,MAAMyE,OAAS0B,IAAa5M,KAAK8M,aAAe9M,KAAKyG,MAAMyE,MAAMxF,OAAQ,CAC5F1F,KAAKuG,WAAW9C,aAAa,QAAS,uBAM9CwJ,MAAO,WACH,IAAInH,EAAS9F,KACb+F,MAAMzF,UAAU2F,QAAQtF,KAAKX,KAAKuG,WAAWiG,qBAAqB,MAAO,SAAUoB,GAC/E,GAAIA,EAAGhH,aAAa,UAAY,SAAU,CACxCgH,EAAGC,QAAU,SAAUxG,GACjBvB,EAAOiG,QAAQ6B,IAEnBA,EAAGE,aAAe,WACd,IAAI1B,EAAStG,EAAOS,WAAWsF,cAAc,aAC7C,GAAIO,IAAWwB,EAAI,CACf,GAAIxB,IAAW,KAAM,CACjBA,EAAO/H,UAAUoI,OAAO,UAE5BmB,EAAGvJ,UAAUC,IAAI,gBASrCuC,UAAW,WACP7G,KAAKuG,WAAW9C,aAAa,QAAS,gBACtCzD,KAAKuG,WAAW9C,aAAa,QAAS,QAAUzD,KAAKyG,MAAMsH,UAAY/N,KAAKyG,MAAMuH,cAAgB,WAAahO,KAAKyG,MAAMwH,WAAa,YAAcjO,KAAKyG,MAAMyH,YAAc,QAKlLnB,QAAS,SAAUvK,GACf,IAAI2L,EACJ,UAAW3L,GAAY,SAAU,CAC7B2L,EAAKnO,KAAKoO,WAAW5L,OAEpB,CACD2L,EAAKnO,KAAKqO,qBAAqB7L,GAEnC,GAAIxC,KAAKuG,WAAW+H,gBAAiB,CACjCtO,KAAKuG,WAAWqE,YAAY5K,KAAKuG,WAAWgI,WAAW,IAE3DvO,KAAKuG,WAAW5C,YAAYwK,IAKhCE,qBAAsB,SAAU7L,GAC5B,IAAI2L,EAAKhO,SAASqD,cAAc,MAAOoK,EAAKzN,SAASqD,cAAc,MAAO6J,EAAQrN,KAAKoN,SAEvF,GAAIC,EAAQ,EAAG,CACX7K,EAAWA,EAASgM,eAEnB,GAAInB,IAAU,EAAG,CAClBA,EAAQ7K,EAASkD,OAErB,IAAK,IAAIgH,EAAO,EAAGA,EAAO+B,KAAKC,IAAID,KAAKE,IAAItB,GAAQ7K,EAASkD,QAASgH,IAAQ,CAC1EkB,EAAGgB,UAAYpM,EAASkK,GAAMmC,MAC9BjB,EAAGnK,aAAa,0BAA2BjB,EAASkK,GAAMoC,OAC1DX,EAAGxK,YAAYiK,GACfA,EAAKzN,SAASqD,cAAc,MAEhC,OAAO2K,GAKXC,WAAY,SAAU5L,GAClB,IAAI2L,EAAKhO,SAASqD,cAAc,MAAOoK,EAAKzN,SAASqD,cAAc,MACnE,GAAIhB,EAASkD,OAAS,EAAG,CACrB1F,KAAKuG,WAAWqI,UAAYpM,MAE3B,CACD,IAAI2K,EAAenN,KAAKkN,gBACxB,GAAIC,IAAiB,GAAI,CACrBS,EAAGgB,UAAYzB,EACfS,EAAGnK,aAAa,QAAS,UACzB0K,EAAGxK,YAAYiK,IAGvB,OAAOO,GAKXnB,MAAO,SAAUxK,GACb,IACI,IAAIuM,KAEJ,IAAIC,EAAOC,KAAKC,MAAM1M,GACtB,GAAI0G,OAAOiG,KAAKH,GAAMtJ,SAAW,EAAG,CAChC,MAAO,GAEX,GAAIK,MAAMC,QAAQgJ,GAAO,CACrB,IAAK,IAAI3O,EAAI,EAAGA,EAAI6I,OAAOiG,KAAKH,GAAMtJ,OAAQrF,IAAK,CAC/C0O,EAAeA,EAAerJ,SAAYoJ,MAASE,EAAK3O,GAAIwO,MAAS7O,KAAKyN,WAAWuB,EAAK3O,UAG7F,CACD,IAAK,IAAI6K,KAAS8D,EAAM,CACpBD,EAAeK,MACXN,MAAS5D,EACT2D,MAAS7O,KAAKyN,WAAWuB,EAAK9D,OAI1C,OAAO6D,EAEX,MAAO1H,GAEH,OAAO7E,IAMfiH,KAAM,WACF,OAAOzJ,KAAKyG,MAAMyE,OAKtBa,QAAS,SAAUW,GACtB7L,QAAQC,IAAI,kBACL,GAAI4L,EAAK7I,aAAa,2BAA4B,CAC9C7D,KAAKyG,MAAMyE,MAAQwB,EAAK9F,aAAa,+BAEpC,CACD5G,KAAKyG,MAAMyE,MAAQwB,EAAKkC,UAE5B5O,KAAKyG,MAAMhD,aAAa,8BAA+BzD,KAAKyG,MAAMyE,QAEtEf,WAAY,KACZH,UACAlD,eAEJpC,EAAOD,QAAUO,YAEN,IAAI;;;;;;;;;;CAYf,SAAU3F,EAAGC,GACX,aAEA,SAAS+P,EAAYC,EAAoBC,EAAkBC,EAAcC,GACvEzP,KAAKsP,mBAAqBA,EAC1BtP,KAAKuP,iBAAmBA,EACxBvP,KAAKwP,aAAeA,EACpBxP,KAAK0P,OAAS,GACd1P,KAAKyP,UAAYA,EACjBzP,KAAK2P,cAAgB,KAcvBN,EAAY/O,UAAUsP,WAAa,SAASC,EAAQC,GAClD,IAAI3K,EAAI,EACR4K,EAEAD,GAASD,EAAOnK,OAAS1F,KAAK0P,OAC9B,IAAK,IAAIrP,EAAI,EAAGA,EAAIwP,EAAOnK,OAAQrF,IAAK,CACtC0P,EAAMF,EAAOxP,GACb,GAAK0P,EAAIC,aAAe,GAAOD,EAAIE,cAAgB,EAAI,CACrD9K,GAAK4K,EAAIC,aAAeD,EAAIE,kBACvB,CAEL9K,GAAK,GAIT,OAAO2K,EAAQ3K,GAGjBkK,EAAY/O,UAAU4P,SAAW,SAASL,EAAQM,GAChD,IAAIJ,EAAKK,EAAUC,EAAeR,EAAOnK,OACzC,IAAK,IAAIrF,EAAI,EAAGA,EAAIgQ,EAAchQ,IAAK,CACrC0P,EAAMF,EAAOxP,GACb,GAAK0P,EAAIC,aAAe,GAAOD,EAAIE,cAAgB,EAAI,CACrDG,EAAWD,EAASJ,EAAIC,aAAeD,EAAIE,kBACtC,CAELG,EAAWD,EAEbJ,EAAIO,MAAMR,MAAQM,EAAW,KAC7BL,EAAIO,MAAMH,OAASA,EAAS,KAC5BJ,EAAIO,MAAMC,WAAa,MACvBR,EAAIO,MAAME,UAAY,MACtBT,EAAIO,MAAMG,YAAczQ,KAAK0P,OAAS,EAAI,KAC1CK,EAAIO,MAAMI,aAAe1Q,KAAK0P,OAAS,EAAI,OAI/CL,EAAY/O,UAAUqQ,WAAa,SAASC,GAC1C,IAAIC,EAAOC,EACXC,EAAiBzR,EAAEuM,cAAc7L,KAAKsP,oBAAoBpB,YAE1D7O,EAAG,MAAOuR,EAASlL,OAAS,EAAG,CAC7B,IAAK,IAAIrF,EAAI,EAAGA,GAAKuQ,EAASlL,OAAQrF,IAAK,CACzCwQ,EAAQD,EAASC,MAAM,EAAGxQ,GAC1ByQ,EAAI9Q,KAAK4P,WAAWiB,EAAOE,GAC3B,GAAID,EAAI9Q,KAAKyP,UAAW,CACtBzP,KAAKkQ,SAASW,EAAOC,GACrBF,EAAWA,EAASC,MAAMxQ,GAC1B,SAAShB,GAGbW,KAAKkQ,SAASW,EAAOpC,KAAKC,IAAI1O,KAAKyP,UAAWqB,IAC9C,QAIJzB,EAAY/O,UAAU0Q,MAAQ,SAASzB,GACrC,IAAI0B,EAAuB3R,EAAEc,iBAAiBJ,KAAKuP,kBACnD2B,EAAiBD,EAAqBvL,OACtCyL,EAAW,KACXC,EAAU,KACVR,KACA,IAAK,IAAIvQ,EAAI,EAAGA,EAAI6Q,EAAgB7Q,IAAK,CACvC+Q,EAAUH,EAAqB5Q,GAC/B,GAAI+Q,EAAQC,yBAA2BF,GAAYP,EAASlL,OAAS,EAAG,CAItE1F,KAAK2Q,WAAWC,GAEhBA,KAGFA,EAASxB,KAAKgC,EAAQvF,cAAc7L,KAAKwP,eAEzC2B,EAAWC,EAGb,GAAIR,EAASlL,OAAS,EAAG,CACvB1F,KAAK2Q,WAAWC,KAIpBvB,EAAY/O,UAAUgR,MAAQ,WAC5B,IAAIjR,EAAG0P,EAAKa,EAAUW,EACtBvQ,EAAMhB,KACNwR,EAAgBlS,EAAEc,iBAAiBJ,KAAKuP,kBACxC2B,EAAiBM,EAAc9L,OAE/B,SAASsL,EAAMtQ,GACbM,EAAIgQ,QAGN,SAASS,EAAc/Q,GACrB,GAAIM,EAAI2O,cAAe,CACrB3O,EAAI2O,cAAgB,MACpBtF,WAAW,WACTrJ,EAAIgQ,QACJhQ,EAAI2O,cAAgB,MACnB,MAIPtQ,EAAE8B,iBAAiB,SAAUsQ,GAC7BpS,EAAE8B,iBAAiB,WAAY6P,GAE/B,IAAK3Q,EAAI,EAAGA,EAAI6Q,EAAgB7Q,IAAK,CACnC0P,EAAMyB,EAAcnR,GAAGwL,cAAc7L,KAAKwP,cAC1C,UAAWO,IAAQ,YAAa,CAC9BA,EAAI5O,iBAAiB,OAAQsQ,GAC7B1B,EAAI5O,iBAAiB,QAASsQ,MAKpCpS,EAAEE,MAAM8P,YAAcA,GA1IxB,CA4IG9K,OAAQpE,UACVZ,MAAMiC,MAAM,WAEXjC,MAAMwB,GAAG,UAAW,QAAS,WAC3B2Q,EAAgB1R,MAAM,QAGxBT,MAAMwB,GAAG,YAAa,QAAS,SAASL,GACtC,IAAID,EAAKC,EAAEU,OACX,MAAOX,IAAOuH,UAAW,CACvB,GAAIvH,EAAG4D,UAAUsN,SAAS,UAAW,CACnC,GAAIlR,EAAGmG,aAAa,uBAAyB,KAAM,CACjD8K,EAAgBjR,GAAI,MAEtB,MAEFA,EAAKA,EAAGP,aAET,MAEH,IAAI0R,GACFC,IACEhK,IAAK,SACLiK,IAAKC,EACLC,IAAK,sCACLC,IAAK,WAEPC,IACErK,IAAK,IACLiK,IAAKK,EACLH,IAAK,4BACLC,IAAK,WAEPG,IACEvK,IAAK,IACLiK,IAAKO,GAAY9N,OAAO+N,aACxBN,IAAK,qBACLC,IAAK,cAEPM,IACE1K,IAAK,IACLiK,IAAKO,EAAW9N,OAAO+N,aACvBN,IAAK,uBACLC,IAAK,cAEPO,IACE3K,IAAK,IACLiK,IAAKO,GAAY9N,OAAO+N,YAAc,GACtCN,IAAK,wBACLC,IAAK,cAEPQ,IACE5K,IAAK,IACLiK,IAAKO,EAAW9N,OAAO+N,YAAc,GACrCN,IAAK,0BACLC,IAAK,cAEPS,IACE7K,IAAK,IACLiK,IAAKa,GAAcxS,SAASuD,KAAKkP,aAAc,OAC/CZ,IAAK,gCACLC,IAAK,cAEPY,IACEhL,IAAK,IACLiK,IAAKa,EAAaxS,SAASuD,KAAKkP,aAAc,UAC9CZ,IAAK,mCACLC,IAAK,cAEPa,IACEjL,IAAK,IACLiK,IAAKJ,EAAgB,MACrBM,IAAK,gCACLC,IAAK,WAEPc,IACElL,IAAK,IACLiK,IAAKJ,EAAgB,QACrBM,IAAK,4BACLC,IAAK,WAEPe,IACEnL,IAAK,IACLiK,IAAKmB,EAAgB,GACrBjB,IAAK,sBACLC,IAAK,WAEPiB,IACErL,IAAK,IACLiK,IAAKmB,EAAgB,GACrBjB,IAAK,kBACLC,IAAK,WAEPkB,IACEtL,IAAK,IACLiK,IAAKsB,EAAW,OAChBpB,IAAK,qBACLC,IAAK,WAEPoB,IACExL,IAAK,IACLiK,IAAKsB,EAAW,MAChBpB,IAAK,+BACLC,IAAK,WAEPqB,IACEzL,IAAK,IACLiK,IAAKyB,EACLvB,IAAK,8BACLC,IAAK,WAEPuB,IACE3L,IAAK,IACLiK,IAAK2B,EACLzB,IAAK,qBACLC,IAAK,UAIT1S,MAAMwB,GAAGZ,SAAU,UAAW,SAASO,GAErC,GAAIkR,EAAQpJ,eAAe9H,EAAEgI,WAAahI,EAAEgT,UAAYhT,EAAEiT,SAAWjT,EAAEkT,WAAalT,EAAEmT,QAAS,CAC7F,IAAIC,EAAUpT,EAAEU,OAAO0S,QAAQC,cAC/B,GAAIrT,EAAEgI,UAAY,GAAI,CACpB,GAAIoL,IAAY,SAAWA,IAAY,UAAYA,IAAY,WAAY,CACzElC,EAAQlR,EAAEgI,SAASoJ,WAEhB,CACL,GAAIpR,EAAEU,SAAWjB,SAASuD,MAAQoQ,IAAY,KAAOA,IAAY,SAAU,CACzEpT,EAAEoL,iBACF8F,EAAQlR,EAAEgI,SAASoJ,WAM3B,SAASJ,EAAgBsC,GACvB,OAAO,SAASC,GACd,IAAI7C,EAAUjR,SAAS0L,cAAc,8BACrCqI,EAAiBF,EACjB,GAAI5C,IAAY,KAAM,CAEpBA,EAAUjR,SAAS0L,cAAc,WACjC,GAAIuF,IAAY,KAAM,CAEpB,OAGF,GAAI4C,IAAU,QAAUA,IAAU,KAAM,CACtCE,EAAiB9C,GAIrB,IAAI+C,EAAMC,EAAUjU,SAASC,iBAAiB,WAE9C,UAAW8T,IAAmB,SAAU,CACtCC,EAAOD,MACF,CACL,OAAQA,GACN,IAAK,UACL,IAAIG,EAAMlU,SAASmU,gBAAgBC,WAAapU,SAASuD,KAAK6Q,UAC9D,IAAIC,EAAMH,EAAMlU,SAASmU,gBAAgBG,aAEzC,IAAK,IAAIpU,EAAI,EAAGA,EAAI+T,EAAQ1O,OAAQrF,IAAK,CACvC8T,EAAOC,EAAQ/T,GACf,IAAIqU,EAAOP,EAAKpG,UAChB,IAAI4G,EAAOD,EAAOP,EAAKM,aAEvB,GAAKE,GAAQH,GAASE,EAAOL,EAAM,CACjC,OAGJ,MACA,IAAK,OACLF,EAAO/C,EAAQwD,mBACf,GAAIT,IAAS,KAAM,CACjBA,EAAOC,EAAQ,GAEjB,MACA,IAAK,KACLD,EAAO/C,EAAQC,uBACf,GAAI8C,IAAS,KAAM,CACjBA,EAAOC,EAAQA,EAAQ1O,OAAS,GAElC,MACA,IAAK,SACLyO,EAAOC,EAAQA,EAAQ1O,OAAS,GAChC,MACA,IAAK,MAEL,QACAyO,EAAOC,EAAQ,IAInB,GAAID,EAAM,CACR/C,EAAQyD,gBAAgB,qBACxBV,EAAK1Q,aAAa,oBAAqB,QACvC,IAAIqR,EAAOX,EAAKtI,cAAc,SAAWsI,EAAKtI,cAAc,KAC5D,GAAIiJ,IAAS,KAAM,CACjBA,EAAK5N,QAEP,IAAK+M,EAAU,CACbc,OAMR,SAASxB,IACPpT,SAAS6U,SAASC,OAAO,MAG3B,SAASlD,IACP,GAAI5R,SAAS+U,cAAe,CAC1B/U,SAAS+U,cAAcnO,QAI3B,SAASkM,EAAgBkC,GACvB,OAAO,WACL,IAAIC,EAAUC,EAAE,wCAChB,GAAID,EAAQ1P,SAAW,EAAG,CACxB7E,QAAQC,IAAI,oDACZ,OAEF,GAAIqU,GAAO,GAAKA,EAAMC,EAAQ1P,OAAQ,CACpC0P,EAAQD,GAAKG,YACR,CACLzU,QAAQC,IAAI,yCAKlB,SAASiU,IACP,IAAIQ,EAAMpV,SAAS0L,cAAc,8BACjC,GAAI0J,IAAQ,KAAM,CAChB,OAEF,IAAIC,EAAOrV,SAASmU,gBAAgBC,WAAapU,SAASuD,KAAK6Q,UAC/DkB,EAAUtV,SAASmU,gBAAgBG,aACnCC,EAAOa,EAAIxH,UACX4G,EAAOD,EAAOa,EAAId,aAClBiB,EAAS,IAET,GAAKH,EAAIlE,yBAA2B,MAAUsD,EAAOc,EAAU,CAG7DlR,OAAOoR,OAAOpR,OAAOqR,QAAS,GAC9B,OAEF,GAAIJ,EAAQd,EAAOgB,EAAS,CAC1BnR,OAAOoR,OAAOpR,OAAOqR,QAASlB,EAAOgB,OAChC,CACL,IAAIG,EAAOL,EAAOC,EAClB,GAAII,EAAQlB,EAAOe,EAAS,CAC1BnR,OAAOoR,OAAOpR,OAAOqR,QAASjB,EAAOc,EAAUC,KAKrD,SAASrD,EAAWyD,GAClB,OAAO,WACLvR,OAAOwR,SAAS,EAAGD,GACnBpE,EAAgB,cAIpB,SAASiB,EAAalL,EAAUuO,GAC9B,OAAO,WACLzR,OAAO0R,SAAS,EAAGxO,GACnBiK,EAAgBsE,MAIpB,SAAS7D,IACP5N,OAAO0R,SAAS,EAAG,GACnB9V,SAAS0L,cAAc,MAAM3E,QAG/B,SAASkM,EAAW8C,GAClB,OAAO,WACL,IAAIpB,EAAO3U,SAAS0L,cAAc,mCAClC,GAAIiJ,IAAS,KAAM,CACjB,IAAIjT,EAAMiT,EAAKlO,aAAa,QAC5B,GAAIsP,EAAQ,CACV3R,OAAOlC,KAAKR,OACP,CACL0C,OAAOyQ,SAASmB,KAAOtU,KAM/B,SAASuU,EAAgBC,GACvB,IAAIC,KAEJ,IAAK,IAAIC,KAAK3E,EAAS,CACrB,IAAI/J,EAAM+J,EAAQ2E,GAClBD,EAAWzO,EAAIoK,KAAOqE,EAAWzO,EAAIoK,SACrCqE,EAAWzO,EAAIoK,KAAK7C,KAAKvH,GAG3B,IAAI2O,EAAStN,OAAOiG,KAAKmH,GAAYG,KAAK,SAASnR,EAAGoR,GACpD,OAAOJ,EAAWI,GAAGhR,OAAS4Q,EAAWhR,GAAGI,SAG9C,GAAI8Q,EAAO9Q,SAAW,EAAG,CACvB,OAGH,IAAIiR,EAAO,mEACVA,GAAQ,uDACVA,GAAQ,UAEN,IAAK,IAAItW,EAAI,EAAGA,EAAImW,EAAO9Q,OAAQrF,IAAK,CACtC,IAAI4R,EAAMqE,EAAWE,EAAOnW,IAE5B,IAAIuW,EAAevW,IAAOmW,EAAO9Q,OAAS,EAC1C,IAAIwG,EAAQ7L,EAAI,IAAM,EAEtB,GAAI6L,EAAO,CACTyK,GAAQ,OAEVA,GAAQ,OAERA,GAAQ,OAAS1E,EAAI,GAAGA,IAAM,QAC9B0E,GAAQ,6BAER,IAAK,IAAIE,KAAM5E,EAAK,CAClB0E,GAAQ,YAAc1E,EAAI4E,GAAIhP,IAAM,UAAYoK,EAAI4E,GAAI7E,IAAM,QAGhE2E,GAAQ,QACRA,GAAQ,QAER,IAAKzK,GAAS0K,EAAc,CAC1BD,GAAQ,SAIdA,GAAQ,WAENN,EAAWzH,UAAY+H,EAGzB,SAASlD,IACR,IAAIqD,EAAY3W,SAAS0L,cAAc,qBACvChL,QAAQC,IAAIgW,GACb,GAAIA,IAAc9O,WAAa8O,IAAc,KAAM,CAElDA,EAAY3W,SAASqD,cAAc,OAChCsT,EAAU1T,GAAK,mBACjB0T,EAAUC,UAAU,eACpBD,EAAUxG,MAAM,aACjB8F,EAAgBU,GAChB,IAAIpT,EAAOvD,SAASqM,qBAAqB,QAAQ,GACjD9I,EAAKC,YAAYmT,OACX,CAENA,EAAUzS,UAAU2S,OAAO,aAC3B,YAuBH,SAAW3X,EAAGC,EAAGC,GACf,aAEAA,EAAMiC,MAAM,WACVjC,EAAMwB,GAAG,0BAA2B,QAAS,SAASsG,GAEpDrH,KAAKqE,UAAUoI,OAAO,0BAGtB,IAAIwK,EAAe,gDACnB,IAAIC,EAAcD,EAAe,2BACjC,IAAIE,EAAY,cAEhB,IAAIC,EAASpX,KAAKqX,QAAQC,MAC1B,IAAIC,EAAWvX,KAAKqX,QAAQG,QAC5B,IAAIC,EAAenY,EAAEuM,cAAc,IAAM7L,KAAKqX,QAAQK,aACtD,IAAIC,EAAwBrY,EAAEuM,cAAc,IAAM7L,KAAKqX,QAAQO,qBAG/D,IAAIC,GAAoB,YAAa,eAAgB,mBAAoB,gBAAiB,eAE1F,GAAGT,GAAUG,GAAYE,EAAc,CACrC,IAAIK,EAAQ,KACZ,OAAOP,GACL,IAAK,OACLO,EAAQZ,EAAc,QAAUE,EAAS,KAAOD,EAChD,MACA,IAAK,MACLW,EAAQZ,EAAc,OAASE,EAAS,KAAOD,EAC/C,MACA,IAAK,WACLW,EAAQZ,EAAc,YAAcE,EAAS,KAAOD,EACpD,MACA,QACA,MAEF,GAAGW,EAAO,CAERvY,EAAMoC,KAAM,MAAOmW,GAAQ3V,KAAK,SAASwU,EAAMoB,GAC7CpB,EAAO1H,KAAKC,MAAMyH,GAClB,GAAGA,GAAQA,EAAKzQ,UAAYyQ,EAAKzQ,SAAS,GAAI,CAC5C,IAAIhC,EAAUyS,EAAKzQ,SAAS,GAC5B,IAAI8R,EAAU,GACd,IAAK,IAAIC,KAAO/T,EAAQgU,KAAM,CAC5B,GAAGhU,EAAQgU,KAAKrP,OAAS,MAAQgP,EAAgBhO,QAAQoO,KAAS,EAAG,CACnED,GAAW,WAAaC,EAAM,YAC9B,OAAOA,GACL,IAAK,QACL,IAAK,MACLD,GAAW,gBAAmB9T,EAAQgU,KAAKD,GAAK5U,QAAQ,KAAK,IAAM,KAAQa,EAAQgU,KAAKD,GAAO,OAC/F,MACA,IAAK,QACLD,GAAW,mBAAsB9T,EAAQgU,KAAKD,GAAO,KAAQ/T,EAAQgU,KAAKD,GAAO,OACjF,MACA,IAAK,UACL,IAAK,MACLD,GAAW,YAAe9T,EAAQgU,KAAKD,GAAO,KAAQ/T,EAAQgU,KAAKD,GAAO,OAC1E,MACA,IAAK,WACLD,GAAW,0CAA6C9T,EAAQgU,KAAKD,GAAO,KAAQ/T,EAAQgU,KAAKD,GAAO,OACxG,MACA,IAAK,YACL,GAAG/T,EAAQgU,KAAKD,GAAKpO,QAAQ,OAAS,EAAG,CACvCmO,GAAW,oBAAuB9T,EAAQgU,KAAKD,GAAKE,UAAU,EAAEjU,EAAQgU,KAAKD,GAAKpO,QAAQ,MAAQ,uBAAyB3F,EAAQgU,KAAKD,GAAKE,UAAUjU,EAAQgU,KAAKD,GAAKpO,QAAQ,KAAK,GAAK,KAAQ3F,EAAQgU,KAAKD,GAAO,OACvN,MAGF,QAEAD,GAAW9T,EAAQgU,KAAKD,GACxB,MAEFD,GAAW,cAGtBL,EAAsBzX,WAAW0K,YAAY+M,GACtCF,EAAapT,UAAUoI,OAAO,aAC9BgL,EAAa5L,cAAc,SAAS+C,UAAYoJ,KAGnD5V,MAAM,WACLuV,EAAsBtT,UAAUoI,OAAO,aACvCkL,EAAsB/I,UAAY,0BAMxCvH,EAAMyE,mBAGRvM,EAAMwB,GAAG,kBAAmB,QAAS,SAASsG,GAE5CrH,KAAKqE,UAAUoI,OAAO,kBAGtB,IAAI2L,EAAiBpY,KAAKqX,QAAQgB,cAClC,IAAIC,EAAUC,WAAWvY,KAAKqX,QAAQmB,QACtC,IAAIC,EAAUF,WAAWvY,KAAKqX,QAAQqB,QACtC,IAAIC,EAAWJ,WAAWvY,KAAKqX,QAAQuB,SACvC,IAAIC,EAAkB5J,KAAKC,MAAMlP,KAAKqX,QAAQyB,gBAC9C,IAAIC,EAAc9J,KAAKC,MAAMlP,KAAKqX,QAAQ2B,YAE1CzZ,EAAMyD,UAAU,uBAChBzD,EAAMqE,WAAW,qBAAsB,WACrC,IAAIqV,EAAa,KACjB,GAAGJ,EAAiB,CAClB,IAAIK,EAAYC,EAAEC,OAAOP,EAAgB,GAAIA,EAAgB,IAC7D,IAAIQ,EAAYF,EAAEC,OAAOP,EAAgB,GAAIA,EAAgB,IAC7DI,EAAaE,EAAEG,aAAaJ,EAAWG,GAIzC,IAAIE,EAAMJ,EAAEI,IAAInB,GAEhB,IAAIoB,EAAa,qDACjB,IAAIC,EAAgB,gFACpB,IAAIC,EAAY,IAAIP,EAAEQ,UAAUH,GAAeI,QAAS,EAAGC,QAAS,GAAIC,YAAaL,IACrF,IAAIM,EAAgB,sDACpB,IAAIC,EAAqB,uGACzB,IAAIC,EAAe,IAAId,EAAEQ,UAAUI,GAAkBH,QAAS,EAAGC,QAAS,GAAIC,YAAaE,IAE3F,GAAGf,EAAY,CAGb5O,WAAW,WACTkP,EAAIW,UAAUjB,GACZY,QAAQ,MAET,QACE,GAAIvB,GAAWG,EAAS,CAC7B,GAAGE,EAAU,CACXY,EAAIY,QAAQ,IAAIhB,EAAEC,OAAOX,EAASH,GAASK,OACtC,CACLY,EAAIY,QAAQ,IAAIhB,EAAEC,OAAOX,EAASH,GAAS,IAI/CiB,EAAIa,SAASV,GAEb,IAAIW,GACFC,aAAcZ,GAIhBP,EAAEoB,QAAQC,OAAOH,GAAYI,MAAMlB,GAEnC,GAAGR,EAAa,CACdI,EAAEuB,QAAQ3B,GAAa0B,MAAMlB,MAOjClS,EAAMyE,sBA3JZ,CA8JGvH,OAAQpE,SAAUoE,OAAOhF,QAiB5B,SAAUF,EAAGC,EAAGC,GACd,aAEAA,EAAMiC,MAAM,WACVjC,EAAMob,uBAAyB,IAAIpb,EAAM8P,YAAY,QAAS,uBAAwB,sBAAuB,KAC7G9P,EAAMob,uBAAuBrJ,QAE7B/R,EAAMwB,GAAG,gBAAiB,QAAS,SAASsG,GAC1C,IAAIuT,EAAoB5a,KAAK4G,aAAa,2BAC1C,IAAIiU,EAAuB7a,KAAK4G,aAAa,+BAC7C,IAAIxF,EAASpB,KAAK4G,aAAa,eAC/B,IAAIkU,EAAgBxb,EAAEuM,cAAczK,GACpC,IAAIuV,EAAO3W,KAAK4O,UAChB,GAAI5O,KAAKqE,UAAUsN,SAAS,aAAc,CACxCgF,EAAOA,EAAKtT,QAAQuX,EAAmBC,OAClC,CACLlE,EAAOA,EAAKtT,QAAQwX,EAAsBD,GAE5C5a,KAAK4O,UAAY+H,EACjB3W,KAAKqE,UAAU2S,OAAO,aACtB8D,EAAczW,UAAU2S,OAAO,eAGjCzX,EAAMwB,GAAG,gBAAiB,QAAS,SAASsG,GAC1C,IAAIjG,EAASpB,KAAK4G,aAAa,eAC/B,IAAImU,EAAczb,EAAEuM,cAAczK,EAAS,aAC3C,IAAI4Z,EAAUD,EAAYnU,aAAa,OACvC,GAAIoU,IAAY,MAAQA,IAAYhT,WAAagT,IAAY,MAAO,CAClED,EAAYtX,aAAa,MAAOsX,EAAYnU,aAAa,gBAI7DvH,EAAE8B,iBAAiB,SAAU,WAC3B,IAAIT,EAAIpB,EAAEiE,eAAe,aACzBgR,EAAYpU,SAASmU,gBAAgBC,WAAapU,SAASuD,KAAK6Q,UAChE,GAAI7T,IAAM,KAAM,CACd,GAAI6T,GAAa,IAAK,CACpB7T,EAAE4P,MAAM2K,QAAU,MACb,CACLva,EAAE4P,MAAM2K,QAAU,SAvC5B,CA8CG1W,OAAQpE,SAAUoE,OAAOhF,QAiB5B,SAAUF,EAAGC,EAAGC,GACd,aAEA,IAAI2b,EAAa,KAAMC,EAAY,IAAKC,EAExC,SAASC,EAAiBnX,GACxB,GAAIA,EAAQoX,kBAAmB,CAC7B,IAAIC,EAAMrX,EAAQgH,MAAMxF,OACxBxB,EAAQoX,kBAAkBC,EAAKA,IAInC,SAASC,IACP,GAAIJ,EAAOlQ,MAAMxF,OAAU,EAAG,CAC5B,IAAI+V,EAAStb,SAASoD,eAAe,UACrC8G,WAAWoR,EAAOC,OAAOha,KAAK+Z,GAAS,IAI3C,SAASE,EAAkBP,GACzB,IAAIQ,EAAKzb,SAASoD,eAAe,gBACjC,IAAIsY,EAAoB,WACtB,GAAIT,EAAOlQ,MAAMxF,SAAW,EAAG,CACpCkW,EAAGvX,UAAUC,IAAI,aACL,CACZsX,EAAGvX,UAAUoI,OAAO,WAKjBoP,IACAD,EAAGza,iBAAiB,QAAS,WAC3Bia,EAAOlQ,MAAM,GACbkQ,EAAOlU,QACP2U,MAEFT,EAAOja,iBAAiB,QAAS0a,EAAmB,OAGtDtc,EAAMiC,MAAM,WACV4Z,EAAS9b,EAAEiE,eAAe4X,GAE1B,SAASW,EAAqBpb,GAC5B,GAAIwa,EAAY,CACdG,EAAiBD,GACjBF,EAAa,UACR,GAKT,GAAIE,IAAW,KAAM,CAEnBO,EAAkBP,GAGlB,GAAI7b,EAAMwc,cAAe,CACvBxc,EAAMyc,aAAehX,aAAarE,KAAKtB,GACrCqM,IAAK,kBACLX,aAAcxL,EAAM0c,YACpBzQ,WAAYjM,EAAMqC,OAClB2J,SAAU,EACVjB,MAAO,KACN,IAAM6Q,GAGT9b,EAAE8B,iBAAiB,SAAU,WAC3B,IAAIkG,EAAQ,IAAI6U,YAAY,YAC5Bd,EAAOe,cAAc9U,KAIzB+T,EAAOja,iBAAiB,QAAS2a,EAAsB,OACvDV,EAAOlU,QAIT,GAAIkU,IAAW,MAAQ7b,EAAM6c,0BAA2B,CACtD9c,EAAEuM,cAAc,SAASkL,UAAU,YAEnCxX,EAAMwB,GAAG,oBAAqB,SAAU,SAASL,GAC/C,IAAIL,EAAGiW,EAAahX,EAAEc,iBAAiB,sCACvC,IAAIC,EAAE,EAAGA,EAAEiW,EAAW5Q,OAAQrF,IAAK,CACjC,GAAIiW,EAAWjW,KAAOL,MAAQsW,EAAWjW,GAAGgc,QAAS,CACnD/F,EAAWjW,GAAGiV,SAGlB,IAAMtV,KAAKqc,QAAS,CAClBrc,KAAKsV,QAEPkG,IACA,OAAO,QAGTjc,EAAMwB,GAAGzB,EAAEiE,eAAe,cAAe,SAAUiY,GACnDjc,EAAMwB,GAAGzB,EAAEiE,eAAe,YAAa,SAAUiY,OA/FvD,CAoGGjX,OAAQpE,SAAUoE,OAAOhF","file":"searx.min.js"}
1+{"version":3,"sources":["searx.js"],"names":["window","searx","w","d","Element","ElementPrototype","matches","matchesSelector","webkitMatchesSelector","msMatchesSelector","selector","node","this","nodes","parentNode","document","querySelectorAll","i","prototype","callbackSafe","callback","el","e","call","exception","console","log","on","obj","eventType","useCapture","addEventListener","target","srcElement","found","parentElement","ready","readyState","bind","http","method","url","req","XMLHttpRequest","resolve","reject","promise","then","catch","open","onload","status","response","responseType","Error","statusText","onerror","onabort","send","ex","loadStyle","src","path","static_path","id","replace","s","getElementById","createElement","setAttribute","body","appendChild","loadScript","hasAttribute","apply","insertBefore","newNode","referenceNode","element","insertAfter","nextSibling","classList","add","f","exports","module","define","amd","g","global","self","AutoComplete","t","n","r","o","u","a","require","code","l","length","1","ConditionOperator","EventType","params","Array","isArray","forEach","elements","input","specificParams","merge","defaults","DOMResults","create","Input","nodeName","match","getAttribute","_Position","$Listeners","blur","_Blur","destroy","focus","_Focus","keyup","event","KEYUP","keydown","KEYDOWN","position","getEventsByType","type","mappings","key","KeyboardMappings","Event","undefined","eventIdentifier","condition","mapping","Operator","AND","OR","Not","hasOwnProperty","Is","keyCode","From","To","name","Conditions","Callback","makeRequest","propertyHttpHeaders","Object","getOwnPropertyNames","HttpHeaders","request","_HttpMethod","_Url","queryParams","_Pre","queryParamsStringify","encodeURIComponent","_QueryArg","indexOf","setRequestHeader","onreadystatechange","$Cache","ajax","timeout","$AjaxTimer","clearTimeout","setTimeout","Delay","Request","abort","cache","_Cache","removeEventListener","removeChild","tmp","arguments","EmptyMessage","Highlight","getRegex","value","RegExp","transform","Content-type","Limit","MinChars","HttpMethod","QueryArg","Url","Enter","liActive","querySelector","preventDefault","_Select","KeyUpAndDown_down","KeyUpAndDown_up","first","last","active","currentIndex","children","lisCount","getElementsByTagName","remove","item","AlphaNum","oldValue","currentValue","_MinChars","_Render","_Post","_Open","_EmptyMessage","emptyMessage","_Limit","limit","isNaN","parseInt","minchars","_Highlight","label","now","li","onclick","onmouseenter","offsetTop","offsetHeight","offsetLeft","clientWidth","ul","_RenderRaw","_RenderResponseItems","hasChildNodes","childNodes","reverse","Math","min","abs","innerHTML","Label","Value","returnResponse","json","JSON","parse","keys","push","ImageLayout","container_selector","results_selector","img_selector","maxHeight","margin","_alignAllDone","_getHeigth","images","width","img","naturalWidth","naturalHeight","_setSize","height","imgWidth","imagesLength","style","marginLeft","marginTop","marginRight","marginBottom","_alignImgs","imgGroup","slice","h","containerWidth","align","results_selectorNode","results_length","previous","current","previousElementSibling","watch","imgNodeLength","results_nodes","throttleAlign","highlightResult","contains","vimKeys","27","fun","removeFocus","des","cat","73","searchInputFocus","66","scrollPage","innerHeight","70","85","68","71","scrollPageTo","scrollHeight","86","75","74","80","pageButtonClick","78","79","openResult","84","82","reloadPage","72","toggleHelp","ctrlKey","altKey","shiftKey","metaKey","tagName","toLowerCase","which","noScroll","effectiveWhich","next","results","top","documentElement","scrollTop","bot","clientHeight","etop","ebot","nextElementSibling","removeAttribute","link","scrollPageToSelected","location","reload","activeElement","num","buttons","$","click","sel","wtop","wheight","offset","scroll","scrollX","wbot","amount","scrollBy","nav","scrollTo","newTab","href","initHelpContent","divElement","categories","k","sorted","sort","b","html","lastCategory","cj","helpPanel","className","toggle","overpass_url","query_start","query_end","osm_id","dataset","osmId","osm_type","osmType","result_table","resultTable","result_table_loadicon","resultTableLoadicon","osm_ignore_tags","query","contentType","newHtml","row","tags","substring","leaflet_target","leafletTarget","map_lon","parseFloat","mapLon","map_lat","mapLat","map_zoom","mapZoom","map_boundingbox","mapBoundingbox","map_geojson","mapGeojson","map_bounds","southWest","L","latLng","northEast","latLngBounds","map","osmMapnikUrl","osmMapnikAttrib","osmMapnik","TileLayer","minZoom","maxZoom","attribution","osmWikimediaUrl","osmWikimediaAttrib","osmWikimedia","fitBounds","setView","addLayer","baseLayers","OSM Mapnik","control","layers","addTo","geoJson","image_thumbnail_layout","btnLabelCollapsed","btnLabelNotCollapsed","targetElement","iframe_load","srctest","opacity","firstFocus","qinput_id","qinput","placeCursorAtEnd","setSelectionRange","len","submitIfQuery","search","submit","createClearButton","cs","updateClearButton","placeCursorAtEndOnce","autocompleter","autocomplete","no_item_found","CustomEvent","dispatchEvent","search_on_category_select","checked"],"mappings":";;AAiBAA,OAAOC,MAAQ,SAAUC,EAAGC,GAE1B,aAMA,GAAID,EAAEE,QAAS,EACb,SAAUC,GACRA,EAAiBC,QAAUD,EAAiBC,SAC5CD,EAAiBE,iBACjBF,EAAiBG,uBACjBH,EAAiBI,mBACjB,SAASC,GACP,IAAIC,EAAOC,KAAMC,GAASF,EAAKG,YAAcH,EAAKI,UAAUC,iBAAiBN,GAAWO,GAAK,EAC7F,MAAOJ,IAAQI,IAAMJ,EAAMI,IAAMN,GACjC,QAASE,EAAMI,KARnB,CAUGb,QAAQc,WAGb,SAASC,EAAaC,EAAUC,EAAIC,GAClC,IACEF,EAASG,KAAKF,EAAIC,GAClB,MAAOE,GACPC,QAAQC,IAAIF,IAIhB,IAAIvB,EAAQD,OAAOC,OAAS,GAE5BA,EAAM0B,GAAK,SAASC,EAAKC,EAAWT,EAAUU,GAC5CA,EAAaA,GAAc,MAC3B,UAAWF,IAAQ,SAAU,CAE3BA,EAAIG,iBAAiBF,EAAWT,EAAUU,OACrC,CAEL3B,EAAE4B,iBAAiBF,EAAW,SAASP,GACrC,IAAID,EAAKC,EAAEU,QAAUV,EAAEW,WAAYC,EAAQ,MAC3C,MAAOb,GAAMA,EAAGf,SAAWe,IAAOlB,KAAO+B,EAAQb,EAAGf,QAAQsB,IAAOP,EAAKA,EAAGc,cAC3E,GAAID,EAAOf,EAAaC,EAAUC,EAAIC,IACrCQ,KAIP7B,EAAMmC,MAAQ,SAAShB,GACrB,GAAIL,SAASsB,YAAc,UAAW,CACpCjB,EAASG,KAAKrB,OACT,CACLA,EAAE6B,iBAAiB,mBAAoBX,EAASkB,KAAKpC,MAIzDD,EAAMsC,KAAO,SAASC,EAAQC,EAAKrB,GACjC,IAAIsB,EAAM,IAAIC,eACdC,EAAU,aACVC,EAAS,aACTC,EAAU,CACRC,KAAM,SAAS3B,GAAYwB,EAAUxB,EAAU,OAAO0B,GACtDE,MAAO,SAAS5B,GAAYyB,EAASzB,EAAU,OAAO0B,IAGxD,IACEJ,EAAIO,KAAKT,EAAQC,EAAK,MAGtBC,EAAIQ,OAAS,WACX,GAAIR,EAAIS,QAAU,IAAK,CACrBP,EAAQF,EAAIU,SAAUV,EAAIW,kBACrB,CACLR,EAAOS,MAAMZ,EAAIa,eAKrBb,EAAIc,QAAU,WACZX,EAAOS,MAAM,mBAGfZ,EAAIe,QAAU,WACZZ,EAAOS,MAAM,4BAIfZ,EAAIgB,OACJ,MAAOC,GACPd,EAAOc,GAGT,OAAOb,GAGT7C,EAAM2D,UAAY,SAASC,GACzB,IAAIC,EAAO7D,EAAM8D,YAAcF,EAC/BG,EAAK,SAAWH,EAAII,QAAQ,IAAK,KACjCC,EAAI/D,EAAEgE,eAAeH,GACrB,GAAIE,IAAM,KAAM,CACdA,EAAI/D,EAAEiE,cAAc,QACpBF,EAAEG,aAAa,KAAML,GACrBE,EAAEG,aAAa,MAAO,cACtBH,EAAEG,aAAa,OAAQ,YACvBH,EAAEG,aAAa,OAAQP,GACvB3D,EAAEmE,KAAKC,YAAYL,KAIvBjE,EAAMuE,WAAa,SAASX,EAAKzC,GAC/B,IAAI0C,EAAO7D,EAAM8D,YAAcF,EAC/BG,EAAK,UAAYH,EAAII,QAAQ,IAAK,KAClCC,EAAI/D,EAAEgE,eAAeH,GACrB,GAAIE,IAAM,KAAM,CACdA,EAAI/D,EAAEiE,cAAc,UACpBF,EAAEG,aAAa,KAAML,GACrBE,EAAEG,aAAa,MAAOP,GACtBI,EAAEhB,OAAS9B,EACX8C,EAAEV,QAAU,WACVU,EAAEG,aAAa,QAAS,MAE1BlE,EAAEmE,KAAKC,YAAYL,QACd,IAAKA,EAAEO,aAAa,SAAU,CACnC,IACErD,EAASsD,MAAMR,EAAG,IAClB,MAAO1C,GACPC,QAAQC,IAAIF,QAET,CACLC,QAAQC,IAAI,mCAAqCoC,EAAO,mBAI5D7D,EAAM0E,aAAe,SAAUC,EAASC,GACtCC,QAAQhE,WAAW6D,aAAaC,EAASC,IAG3C5E,EAAM8E,YAAc,SAASH,EAASC,GACpCA,EAAc/D,WAAW6D,aAAaC,EAASC,EAAcG,cAG/D/E,EAAM0B,GAAG,SAAU,QAAS,SAASL,GACnC,IAAID,EAAKC,EAAEU,QAAUV,EAAEW,WACvBrB,KAAKE,WAAWmE,UAAUC,IAAI,eAGhC,OAAOjF,EAjJM,CAkJZD,OAAQe,WACV,SAAUoE,GAAG,UAAUC,UAAU,iBAAiBC,SAAS,YAAY,CAACA,OAAOD,QAAQD,SAAS,UAAUG,SAAS,YAAYA,OAAOC,IAAI,CAACD,OAAO,GAAGH,OAAO,CAAC,IAAIK,EAAE,UAAUxF,SAAS,YAAY,CAACwF,EAAExF,YAAY,UAAUyF,SAAS,YAAY,CAACD,EAAEC,YAAY,UAAUC,OAAO,YAAY,CAACF,EAAEE,SAAS,CAACF,EAAE5E,KAAK4E,EAAEG,aAAeR,MAAjU,CAAwU,WAAW,IAAIG,EAAOD,EAAOD,EAAQ,OAAO,SAAU9D,EAAEsE,EAAEC,EAAEC,GAAG,SAAS5B,EAAE6B,EAAEC,GAAG,IAAIH,EAAEE,GAAG,CAAC,IAAIH,EAAEG,GAAG,CAAC,IAAIE,SAASC,SAAS,YAAYA,QAAQ,IAAIF,GAAGC,EAAE,OAAOA,EAAEF,GAAG,GAAG,GAAG9E,EAAE,OAAOA,EAAE8E,GAAG,GAAG,IAAIZ,EAAE,IAAI7B,MAAM,uBAAuByC,EAAE,KAAK,MAAMZ,EAAEgB,KAAK,mBAAmBhB,EAAE,IAAIiB,EAAEP,EAAEE,GAAG,CAACX,QAAQ,IAAIQ,EAAEG,GAAG,GAAGxE,KAAK6E,EAAEhB,QAAQ,SAAS9D,GAAG,IAAIuE,EAAED,EAAEG,GAAG,GAAGzE,GAAG,OAAO4C,EAAE2B,EAAEA,EAAEvE,IAAI8E,EAAEA,EAAEhB,QAAQ9D,EAAEsE,EAAEC,EAAEC,GAAG,OAAOD,EAAEE,GAAGX,QAAQ,IAAInE,SAASiF,SAAS,YAAYA,QAAQ,IAAI,IAAIH,EAAE,EAAEA,EAAED,EAAEO,OAAON,IAAI7B,EAAE4B,EAAEC,IAAI,OAAO7B,EAAvb,CAA2b,CAACoC,EAAE,CAAC,SAASJ,EAAQb,EAAOD;;;;;;;;;;AAU50B,aACA,IAAImB,GACJ,SAAWA,GACPA,EAAkBA,EAAkB,OAAS,GAAK,MAClDA,EAAkBA,EAAkB,MAAQ,GAAK,MAFrD,CAGGA,IAAsBA,EAAoB,KAC7C,IAAIC,GACJ,SAAWA,GACPA,EAAUA,EAAU,WAAa,GAAK,UACtCA,EAAUA,EAAU,SAAW,GAAK,SAFxC,CAGGA,IAAcA,EAAY,KAO7B,IAAIb,EAAgB,WAEhB,SAASA,EAAac,EAAQ/F,GAC1B,GAAI+F,SAAgB,EAAG,CAAEA,EAAS,GAClC,GAAI/F,SAAkB,EAAG,CAAEA,EAAW,sBACtC,GAAIgG,MAAMC,QAAQjG,GAAW,CACzBA,EAASkG,QAAQ,SAAU1C,GACvB,IAAIyB,EAAac,EAAQvC,UAG5B,UAAWxD,GAAY,SAAU,CAClC,IAAImG,EAAW9F,SAASC,iBAAiBN,GACzCgG,MAAMxF,UAAU0F,QAAQrF,KAAKsF,EAAU,SAAUC,GAC7C,IAAInB,EAAac,EAAQK,SAG5B,CACD,IAAIC,EAAiBpB,EAAaqB,MAAMrB,EAAasB,SAAUR,EAAQ,CACnES,WAAYnG,SAASqD,cAAc,SAEvCuB,EAAazE,UAAUiG,OAAOJ,EAAgBrG,GAC9C,OAAOqG,GAGfpB,EAAazE,UAAUiG,OAAS,SAAUV,EAAQ3B,GAC9C2B,EAAOW,MAAQtC,EACf,GAAI2B,EAAOW,MAAMC,SAASC,MAAM,cAAgBb,EAAOW,MAAM3C,aAAa,UAAY,OAASgC,EAAOW,MAAMG,aAAa,QAAQD,MAAM,mBAAoB,CACvJb,EAAOW,MAAM/C,aAAa,eAAgB,OAC1CoC,EAAOe,UAAUf,GACjBA,EAAOW,MAAMtG,WAAWyD,YAAYkC,EAAOS,YAC3CT,EAAOgB,WAAa,CAChBC,KAAMjB,EAAOkB,MAAMrF,KAAKmE,GACxBmB,QAASjC,EAAazE,UAAU0G,QAAQtF,KAAK,KAAMmE,GACnDoB,MAAOpB,EAAOqB,OAAOxF,KAAKmE,GAC1BsB,MAAOpC,EAAazE,UAAU8G,MAAM1F,KAAK,KAAMmE,EAAQD,EAAUyB,OACjEC,QAASvC,EAAazE,UAAU8G,MAAM1F,KAAK,KAAMmE,EAAQD,EAAU2B,SACnEC,SAAU3B,EAAOe,UAAUlF,KAAKmE,IAEpC,IAAK,IAAIuB,KAASvB,EAAOgB,WAAY,CACjChB,EAAOW,MAAMrF,iBAAiBiG,EAAOvB,EAAOgB,WAAWO,OAInErC,EAAazE,UAAUmH,gBAAkB,SAAU5B,EAAQ6B,GACvD,IAAIC,EAAW,GACf,IAAK,IAAIC,KAAO/B,EAAOgC,iBAAkB,CACrC,IAAIT,EAAQxB,EAAUyB,MACtB,GAAIxB,EAAOgC,iBAAiBD,GAAKE,QAAUC,UAAW,CAClDX,EAAQvB,EAAOgC,iBAAiBD,GAAKE,MAEzC,GAAIV,GAASM,EAAM,CACfC,EAASC,GAAO/B,EAAOgC,iBAAiBD,IAGhD,OAAOD,GAEX5C,EAAazE,UAAU8G,MAAQ,SAAUvB,EAAQ6B,EAAMN,GACnD,IAAIY,EAAkB,SAAUC,GAC5B,GAAKvB,IAAU,MAAQwB,EAAQC,UAAYxC,EAAkByC,KAAS1B,IAAU,OAASwB,EAAQC,UAAYxC,EAAkB0C,GAAK,CAChIJ,EAAYlD,EAAaqB,MAAM,CAC3BkC,IAAK,OACNL,GACH,GAAIA,EAAUM,eAAe,MAAO,CAChC,GAAIN,EAAUO,IAAMpB,EAAMqB,QAAS,CAC/B/B,GAASuB,EAAUK,QAElB,CACD5B,EAAQuB,EAAUK,UAGrB,GAAIL,EAAUM,eAAe,SAAWN,EAAUM,eAAe,MAAO,CACzE,GAAInB,EAAMqB,SAAWR,EAAUS,MAAQtB,EAAMqB,SAAWR,EAAUU,GAAI,CAClEjC,GAASuB,EAAUK,QAElB,CACD5B,EAAQuB,EAAUK,QAKlC,IAAK,IAAIM,KAAQ7D,EAAazE,UAAUmH,gBAAgB5B,EAAQ6B,GAAO,CACnE,IAAIQ,EAAUnD,EAAaqB,MAAM,CAC7B+B,SAAUxC,EAAkByC,KAC7BvC,EAAOgC,iBAAiBe,IAAQlC,EAAQf,EAAkByC,KAAOF,EAAQC,SAC5ED,EAAQW,WAAW7C,QAAQgC,GAC3B,GAAItB,IAAU,KAAM,CAChBwB,EAAQY,SAASnI,KAAKkF,EAAQuB,MAI1CrC,EAAazE,UAAUyI,YAAc,SAAUlD,EAAQrF,GACnD,IAAIwI,EAAsBC,OAAOC,oBAAoBrD,EAAOsD,aAAcC,EAAU,IAAIrH,eAAkBH,EAASiE,EAAOwD,cAAexH,EAAMgE,EAAOyD,OAAQC,EAAc1D,EAAO2D,OAAQC,EAAuBC,mBAAmB7D,EAAO8D,aAAe,IAAMD,mBAAmBH,GACpR,GAAI3H,EAAO8E,MAAM,UAAW,CACxB,GAAI7E,EAAI+H,QAAQ,QAAU,EAAG,CACzB/H,GAAO,IAAM4H,MAEZ,CACD5H,GAAO,IAAM4H,GAGrBL,EAAQ/G,KAAKT,EAAQC,EAAK,MAC1B,IAAK,IAAIxB,EAAI2I,EAAoBvD,OAAS,EAAGpF,GAAK,EAAGA,IAAK,CACtD+I,EAAQS,iBAAiBb,EAAoB3I,GAAIwF,EAAOsD,YAAYH,EAAoB3I,KAE5F+I,EAAQU,mBAAqB,WACzB,GAAIV,EAAQ3H,YAAc,GAAK2H,EAAQ7G,QAAU,IAAK,CAClDsD,EAAOkE,OAAOR,GAAeH,EAAQ5G,SACrChC,EAAS4I,EAAQ5G,YAGzB,OAAO4G,GAEXrE,EAAazE,UAAU0J,KAAO,SAAUnE,EAAQuD,EAASa,GACrD,GAAIA,SAAiB,EAAG,CAAEA,EAAU,KACpC,GAAIpE,EAAOqE,WAAY,CACnB9K,OAAO+K,aAAatE,EAAOqE,YAE/B,GAAID,IAAY,KAAM,CAClBpE,EAAOqE,WAAa9K,OAAOgL,WAAWrF,EAAazE,UAAU0J,KAAKtI,KAAK,KAAMmE,EAAQuD,EAAS,OAAQvD,EAAOwE,WAE5G,CACD,GAAIxE,EAAOyE,QAAS,CAChBzE,EAAOyE,QAAQC,QAEnB1E,EAAOyE,QAAUlB,EACjBvD,EAAOyE,QAAQxH,KAAK+C,EAAO8D,YAAc,IAAM9D,EAAO2D,UAG9DzE,EAAazE,UAAUkK,MAAQ,SAAU3E,EAAQrF,GAC7C,IAAIgC,EAAWqD,EAAO4E,OAAO5E,EAAO2D,QACpC,GAAIhH,IAAauF,UAAW,CACxB,IAAIqB,EAAUrE,EAAazE,UAAUyI,YAAYlD,EAAQrF,GACzDuE,EAAazE,UAAU0J,KAAKnE,EAAQuD,OAEnC,CACD5I,EAASgC,KAGjBuC,EAAazE,UAAU0G,QAAU,SAAUnB,GACvC,IAAK,IAAIuB,KAASvB,EAAOgB,WAAY,CACjChB,EAAOW,MAAMkE,oBAAoBtD,EAAOvB,EAAOgB,WAAWO,IAE9DvB,EAAOS,WAAWpG,WAAWyK,YAAY9E,EAAOS,aAEpD,OAAOvB,EAhJQ,GAkJnBA,EAAaqB,MAAQ,WACjB,IAAIA,EAAQ,GAAIwE,EAChB,IAAK,IAAIvK,EAAI,EAAGA,EAAIwK,UAAUpF,OAAQpF,IAAK,CACvC,IAAKuK,KAAOC,UAAUxK,GAAI,CACtB+F,EAAMwE,GAAOC,UAAUxK,GAAGuK,IAGlC,OAAOxE,GAEXrB,EAAasB,SAAW,CACpBgE,MAAO,IACPS,aAAc,iBACdC,UAAW,CACPC,SAAU,SAAUC,GAChB,OAAO,IAAIC,OAAOD,EAAO,OAE7BE,UAAW,SAAUF,GACjB,MAAO,WAAaA,EAAQ,cAGpC9B,YAAa,CACTiC,eAAgB,qCAEpBC,MAAO,EACPC,SAAU,EACVC,WAAY,MACZC,SAAU,IACVC,IAAK,KACL5D,iBAAkB,CACd6D,MAAS,CACL7C,WAAY,CAAC,CACLL,GAAI,GACJF,IAAK,QAEbQ,SAAU,SAAU1B,GAChB,GAAIpH,KAAKsG,WAAWK,aAAa,SAASiD,QAAQ,UAAY,EAAG,CAC7D,IAAI+B,EAAW3L,KAAKsG,WAAWsF,cAAc,aAC7C,GAAID,IAAa,KAAM,CACnBvE,EAAMyE,iBACN7L,KAAK8L,QAAQH,GACb3L,KAAKsG,WAAW7C,aAAa,QAAS,mBAIlD0E,SAAUxC,EAAkByC,IAC5BN,MAAOlC,EAAU2B,SAErBwE,kBAAqB,CACjBlD,WAAY,CAAC,CACLL,GAAI,GACJF,IAAK,OAET,CACIE,GAAI,GACJF,IAAK,QAEbQ,SAAU,SAAU1B,GAChBA,EAAMyE,kBAEV1D,SAAUxC,EAAkB0C,GAC5BP,MAAOlC,EAAU2B,SAErByE,gBAAmB,CACfnD,WAAY,CAAC,CACLL,GAAI,GACJF,IAAK,OAET,CACIE,GAAI,GACJF,IAAK,QAEbQ,SAAU,SAAU1B,GAChBA,EAAMyE,iBACN,IAAII,EAAQjM,KAAKsG,WAAWsF,cAAc,+BAAgCM,EAAOlM,KAAKsG,WAAWsF,cAAc,8BAA+BO,EAASnM,KAAKsG,WAAWsF,cAAc,aACrL,GAAIO,EAAQ,CACR,IAAIC,EAAetG,MAAMxF,UAAUsJ,QAAQjJ,KAAKwL,EAAOjM,WAAWmM,SAAUF,GAAS3E,EAAW4E,GAAgBhF,EAAMqB,QAAU,IAAK6D,EAAWtM,KAAKsG,WAAWiG,qBAAqB,MAAM9G,OAC3L,GAAI+B,EAAW,EAAG,CACdA,EAAW8E,EAAW,OAErB,GAAI9E,GAAY8E,EAAU,CAC3B9E,EAAW,EAEf2E,EAAO9H,UAAUmI,OAAO,UACxBL,EAAO5K,cAAc8K,SAASI,KAAKjF,GAAUnD,UAAUC,IAAI,eAE1D,GAAI4H,GAAQ9E,EAAMqB,SAAW,GAAI,CAClCyD,EAAK7H,UAAUC,IAAI,eAElB,GAAI2H,EAAO,CACZA,EAAM5H,UAAUC,IAAI,YAG5B6D,SAAUxC,EAAkB0C,GAC5BP,MAAOlC,EAAUyB,OAErBqF,SAAY,CACR7D,WAAY,CAAC,CACLL,GAAI,GACJF,IAAK,MACN,CACCI,KAAM,GACNC,GAAI,GACJL,IAAK,OAEbQ,SAAU,WACN,IAAI6D,EAAW3M,KAAKwG,MAAMG,aAAa,+BAAgCiG,EAAe5M,KAAKwJ,OAC3F,GAAIoD,IAAiB,IAAMA,EAAanH,QAAUzF,KAAK6M,YAAa,CAChE,IAAKF,GAAYC,GAAgBD,EAAU,CACvC3M,KAAKsG,WAAW7C,aAAa,QAAS,qBAE1CsB,EAAazE,UAAUkK,MAAMxK,KAAM,SAAUwC,GACzCxC,KAAK8M,QAAQ9M,KAAK+M,MAAMvK,IACxBxC,KAAKgN,SACPtL,KAAK1B,SAGfmI,SAAUxC,EAAkByC,IAC5BN,MAAOlC,EAAUyB,QAGzBf,WAAY,KACZgE,QAAS,KACT9D,MAAO,KAIPyG,cAAe,WACX,IAAIC,EAAe,GACnB,GAAIlN,KAAKwG,MAAM3C,aAAa,mCAAoC,CAC5DqJ,EAAelN,KAAKwG,MAAMG,aAAa,wCAEtC,GAAI3G,KAAK8K,eAAiB,MAAO,CAClCoC,EAAelN,KAAK8K,iBAEnB,CACDoC,EAAe,GAEnB,OAAOA,GAKXC,OAAQ,WACJ,IAAIC,EAAQpN,KAAKwG,MAAMG,aAAa,2BACpC,GAAI0G,MAAMD,IAAUA,IAAU,KAAM,CAChC,OAAOpN,KAAKqL,MAEhB,OAAOiC,SAASF,EAAO,KAK3BP,UAAW,WACP,IAAIU,EAAWvN,KAAKwG,MAAMG,aAAa,8BACvC,GAAI0G,MAAME,IAAaA,IAAa,KAAM,CACtC,OAAOvN,KAAKsL,SAEhB,OAAOgC,SAASC,EAAU,KAK9BC,WAAY,SAAUC,GAClB,OAAOA,EAAMpK,QAAQrD,KAAK+K,UAAUC,SAAShL,KAAKwJ,QAASxJ,KAAK+K,UAAUI,YAK9E9B,YAAa,WACT,GAAIrJ,KAAKwG,MAAM3C,aAAa,4BAA6B,CACrD,OAAO7D,KAAKwG,MAAMG,aAAa,4BAEnC,OAAO3G,KAAKuL,YAKhB5B,UAAW,WACP,GAAI3J,KAAKwG,MAAM3C,aAAa,gCAAiC,CACzD,OAAO7D,KAAKwG,MAAMG,aAAa,gCAEnC,OAAO3G,KAAKwL,UAKhBlC,KAAM,WACF,GAAItJ,KAAKwG,MAAM3C,aAAa,qBAAsB,CAC9C,OAAO7D,KAAKwG,MAAMG,aAAa,qBAEnC,OAAO3G,KAAKyL,KAKhB1E,MAAO,SAAU2G,GACb,GAAIA,IAAQ,KAAM,CACd1N,KAAKsG,WAAW7C,aAAa,QAAS,gBACtCzD,KAAKwG,MAAM/C,aAAa,8BAA+BzD,KAAKwG,MAAMyE,WAEjE,CACD,IAAIpF,EAAS7F,KACboK,WAAW,WACPvE,EAAOkB,MAAM,OACd,OAMX0D,OAAQ,SAAUQ,GACd,OAAOjL,KAAK+J,OAAOkB,IAKvB/D,OAAQ,WACJ,IAAIyF,EAAW3M,KAAKwG,MAAMG,aAAa,+BACvC,KAAMgG,GAAY3M,KAAKwG,MAAMyE,OAAS0B,IAAa3M,KAAK6M,aAAe7M,KAAKwG,MAAMyE,MAAMxF,OAAQ,CAC5FzF,KAAKsG,WAAW7C,aAAa,QAAS,uBAM9CuJ,MAAO,WACH,IAAInH,EAAS7F,KACb8F,MAAMxF,UAAU0F,QAAQrF,KAAKX,KAAKsG,WAAWiG,qBAAqB,MAAO,SAAUoB,GAC/E,GAAIA,EAAGhH,aAAa,UAAY,SAAU,CACxCgH,EAAGC,QAAU,SAAUxG,GACjBvB,EAAOiG,QAAQ6B,IAEnBA,EAAGE,aAAe,WACd,IAAI1B,EAAStG,EAAOS,WAAWsF,cAAc,aAC7C,GAAIO,IAAWwB,EAAI,CACf,GAAIxB,IAAW,KAAM,CACjBA,EAAO9H,UAAUmI,OAAO,UAE5BmB,EAAGtJ,UAAUC,IAAI,gBASrCsC,UAAW,WACP5G,KAAKsG,WAAW7C,aAAa,QAAS,gBACtCzD,KAAKsG,WAAW7C,aAAa,QAAS,QAAUzD,KAAKwG,MAAMsH,UAAY9N,KAAKwG,MAAMuH,cAAgB,WAAa/N,KAAKwG,MAAMwH,WAAa,YAAchO,KAAKwG,MAAMyH,YAAc,QAKlLnB,QAAS,SAAUtK,GACf,IAAI0L,EACJ,UAAW1L,GAAY,SAAU,CAC7B0L,EAAKlO,KAAKmO,WAAW3L,OAEpB,CACD0L,EAAKlO,KAAKoO,qBAAqB5L,GAEnC,GAAIxC,KAAKsG,WAAW+H,gBAAiB,CACjCrO,KAAKsG,WAAWqE,YAAY3K,KAAKsG,WAAWgI,WAAW,IAE3DtO,KAAKsG,WAAW3C,YAAYuK,IAKhCE,qBAAsB,SAAU5L,GAC5B,IAAI0L,EAAK/N,SAASqD,cAAc,MAAOmK,EAAKxN,SAASqD,cAAc,MAAO4J,EAAQpN,KAAKmN,SAEvF,GAAIC,EAAQ,EAAG,CACX5K,EAAWA,EAAS+L,eAEnB,GAAInB,IAAU,EAAG,CAClBA,EAAQ5K,EAASiD,OAErB,IAAK,IAAIgH,EAAO,EAAGA,EAAO+B,KAAKC,IAAID,KAAKE,IAAItB,GAAQ5K,EAASiD,QAASgH,IAAQ,CAC1EkB,EAAGgB,UAAYnM,EAASiK,GAAMmC,MAC9BjB,EAAGlK,aAAa,0BAA2BjB,EAASiK,GAAMoC,OAC1DX,EAAGvK,YAAYgK,GACfA,EAAKxN,SAASqD,cAAc,MAEhC,OAAO0K,GAKXC,WAAY,SAAU3L,GAClB,IAAI0L,EAAK/N,SAASqD,cAAc,MAAOmK,EAAKxN,SAASqD,cAAc,MACnE,GAAIhB,EAASiD,OAAS,EAAG,CACrBzF,KAAKsG,WAAWqI,UAAYnM,MAE3B,CACD,IAAI0K,EAAelN,KAAKiN,gBACxB,GAAIC,IAAiB,GAAI,CACrBS,EAAGgB,UAAYzB,EACfS,EAAGlK,aAAa,QAAS,UACzByK,EAAGvK,YAAYgK,IAGvB,OAAOO,GAKXnB,MAAO,SAAUvK,GACb,IACI,IAAIsM,EAAiB,GAErB,IAAIC,EAAOC,KAAKC,MAAMzM,GACtB,GAAIyG,OAAOiG,KAAKH,GAAMtJ,SAAW,EAAG,CAChC,MAAO,GAEX,GAAIK,MAAMC,QAAQgJ,GAAO,CACrB,IAAK,IAAI1O,EAAI,EAAGA,EAAI4I,OAAOiG,KAAKH,GAAMtJ,OAAQpF,IAAK,CAC/CyO,EAAeA,EAAerJ,QAAU,CAAEoJ,MAASE,EAAK1O,GAAIuO,MAAS5O,KAAKwN,WAAWuB,EAAK1O,UAG7F,CACD,IAAK,IAAI4K,KAAS8D,EAAM,CACpBD,EAAeK,KAAK,CAChBN,MAAS5D,EACT2D,MAAS5O,KAAKwN,WAAWuB,EAAK9D,OAI1C,OAAO6D,EAEX,MAAO1H,GAEH,OAAO5E,IAMfgH,KAAM,WACF,OAAOxJ,KAAKwG,MAAMyE,OAKtBa,QAAS,SAAUW,GACtB5L,QAAQC,IAAI,kBACL,GAAI2L,EAAK5I,aAAa,2BAA4B,CAC9C7D,KAAKwG,MAAMyE,MAAQwB,EAAK9F,aAAa,+BAEpC,CACD3G,KAAKwG,MAAMyE,MAAQwB,EAAKkC,UAE5B3O,KAAKwG,MAAM/C,aAAa,8BAA+BzD,KAAKwG,MAAMyE,QAEtEf,WAAY,KACZH,OAAQ,GACRlD,WAAY,IAEhBpC,EAAOD,QAAUO,GAEf,KAAK,GAAG,CAAC,GAthB0W,CAshBtW;;;;;;;;;;;CAYf,SAAUzF,EAAGC,GACX,aAEA,SAAS6P,EAAYC,EAAoBC,EAAkBC,EAAcC,GACvExP,KAAKqP,mBAAqBA,EAC1BrP,KAAKsP,iBAAmBA,EACxBtP,KAAKuP,aAAeA,EACpBvP,KAAKyP,OAAS,GACdzP,KAAKwP,UAAYA,EACjBxP,KAAK0P,cAAgB,KAcvBN,EAAY9O,UAAUqP,WAAa,SAASC,EAAQC,GAClD,IAAI3K,EAAI,EACR4K,EAEAD,GAASD,EAAOnK,OAASzF,KAAKyP,OAC9B,IAAK,IAAIpP,EAAI,EAAGA,EAAIuP,EAAOnK,OAAQpF,IAAK,CACtCyP,EAAMF,EAAOvP,GACb,GAAKyP,EAAIC,aAAe,GAAOD,EAAIE,cAAgB,EAAI,CACrD9K,GAAK4K,EAAIC,aAAeD,EAAIE,kBACvB,CAEL9K,GAAK,GAIT,OAAO2K,EAAQ3K,GAGjBkK,EAAY9O,UAAU2P,SAAW,SAASL,EAAQM,GAChD,IAAIJ,EAAKK,EAAUC,EAAeR,EAAOnK,OACzC,IAAK,IAAIpF,EAAI,EAAGA,EAAI+P,EAAc/P,IAAK,CACrCyP,EAAMF,EAAOvP,GACb,GAAKyP,EAAIC,aAAe,GAAOD,EAAIE,cAAgB,EAAI,CACrDG,EAAWD,EAASJ,EAAIC,aAAeD,EAAIE,kBACtC,CAELG,EAAWD,EAEbJ,EAAIO,MAAMR,MAAQM,EAAW,KAC7BL,EAAIO,MAAMH,OAASA,EAAS,KAC5BJ,EAAIO,MAAMC,WAAa,MACvBR,EAAIO,MAAME,UAAY,MACtBT,EAAIO,MAAMG,YAAcxQ,KAAKyP,OAAS,EAAI,KAC1CK,EAAIO,MAAMI,aAAezQ,KAAKyP,OAAS,EAAI,OAI/CL,EAAY9O,UAAUoQ,WAAa,SAASC,GAC1C,IAAIC,EAAOC,EACXC,EAAiBvR,EAAEqM,cAAc5L,KAAKqP,oBAAoBpB,YAE1D3O,EAAG,MAAOqR,EAASlL,OAAS,EAAG,CAC7B,IAAK,IAAIpF,EAAI,EAAGA,GAAKsQ,EAASlL,OAAQpF,IAAK,CACzCuQ,EAAQD,EAASC,MAAM,EAAGvQ,GAC1BwQ,EAAI7Q,KAAK2P,WAAWiB,EAAOE,GAC3B,GAAID,EAAI7Q,KAAKwP,UAAW,CACtBxP,KAAKiQ,SAASW,EAAOC,GACrBF,EAAWA,EAASC,MAAMvQ,GAC1B,SAASf,GAGbU,KAAKiQ,SAASW,EAAOpC,KAAKC,IAAIzO,KAAKwP,UAAWqB,IAC9C,QAIJzB,EAAY9O,UAAUyQ,MAAQ,SAASzB,GACrC,IAAI0B,EAAuBzR,EAAEa,iBAAiBJ,KAAKsP,kBACnD2B,EAAiBD,EAAqBvL,OACtCyL,EAAW,KACXC,EAAU,KACVR,EAAW,GACX,IAAK,IAAItQ,EAAI,EAAGA,EAAI4Q,EAAgB5Q,IAAK,CACvC8Q,EAAUH,EAAqB3Q,GAC/B,GAAI8Q,EAAQC,yBAA2BF,GAAYP,EAASlL,OAAS,EAAG,CAItEzF,KAAK0Q,WAAWC,GAEhBA,EAAW,GAGbA,EAASxB,KAAKgC,EAAQvF,cAAc5L,KAAKuP,eAEzC2B,EAAWC,EAGb,GAAIR,EAASlL,OAAS,EAAG,CACvBzF,KAAK0Q,WAAWC,KAIpBvB,EAAY9O,UAAU+Q,MAAQ,WAC5B,IAAIhR,EAAGyP,EAAKa,EAAUW,EACtBtQ,EAAMhB,KACNuR,EAAgBhS,EAAEa,iBAAiBJ,KAAKsP,kBACxC2B,EAAiBM,EAAc9L,OAE/B,SAASsL,EAAMrQ,GACbM,EAAI+P,QAGN,SAASS,EAAc9Q,GACrB,GAAIM,EAAI0O,cAAe,CACrB1O,EAAI0O,cAAgB,MACpBtF,WAAW,WACTpJ,EAAI+P,QACJ/P,EAAI0O,cAAgB,MACnB,MAIPpQ,EAAE6B,iBAAiB,SAAUqQ,GAC7BlS,EAAE6B,iBAAiB,WAAY4P,GAE/B,IAAK1Q,EAAI,EAAGA,EAAI4Q,EAAgB5Q,IAAK,CACnCyP,EAAMyB,EAAclR,GAAGuL,cAAc5L,KAAKuP,cAC1C,UAAWO,IAAQ,YAAa,CAC9BA,EAAI3O,iBAAiB,OAAQqQ,GAC7B1B,EAAI3O,iBAAiB,QAASqQ,MAKpClS,EAAED,MAAM+P,YAAcA,GA1IxB,CA4IGhQ,OAAQe,UACVd,MAAMmC,MAAM,WAEXnC,MAAM0B,GAAG,UAAW,QAAS,WAC3B0Q,EAAgBzR,KAAhByR,CAAsB,QAGxBpS,MAAM0B,GAAG,YAAa,QAAS,SAASL,GACtC,IAAID,EAAKC,EAAEU,OACX,MAAOX,IAAOsH,UAAW,CACvB,GAAItH,EAAG4D,UAAUqN,SAAS,UAAW,CACnC,GAAIjR,EAAGkG,aAAa,uBAAyB,KAAM,CACjD8K,EAAgBhR,EAAhBgR,CAAoB,MAEtB,MAEFhR,EAAKA,EAAGP,aAET,MAEH,IAAIyR,EAAU,CACZC,GAAI,CACFhK,IAAK,SACLiK,IAAKC,EACLC,IAAK,sCACLC,IAAK,WAEPC,GAAI,CACFrK,IAAK,IACLiK,IAAKK,EACLH,IAAK,4BACLC,IAAK,WAEPG,GAAI,CACFvK,IAAK,IACLiK,IAAKO,GAAYhT,OAAOiT,aACxBN,IAAK,qBACLC,IAAK,cAEPM,GAAI,CACF1K,IAAK,IACLiK,IAAKO,EAAWhT,OAAOiT,aACvBN,IAAK,uBACLC,IAAK,cAEPO,GAAI,CACF3K,IAAK,IACLiK,IAAKO,GAAYhT,OAAOiT,YAAc,GACtCN,IAAK,wBACLC,IAAK,cAEPQ,GAAI,CACF5K,IAAK,IACLiK,IAAKO,EAAWhT,OAAOiT,YAAc,GACrCN,IAAK,0BACLC,IAAK,cAEPS,GAAI,CACF7K,IAAK,IACLiK,IAAKa,GAAcvS,SAASuD,KAAKiP,aAAc,OAC/CZ,IAAK,gCACLC,IAAK,cAEPY,GAAI,CACFhL,IAAK,IACLiK,IAAKa,EAAavS,SAASuD,KAAKiP,aAAc,UAC9CZ,IAAK,mCACLC,IAAK,cAEPa,GAAI,CACFjL,IAAK,IACLiK,IAAKJ,EAAgB,MACrBM,IAAK,gCACLC,IAAK,WAEPc,GAAI,CACFlL,IAAK,IACLiK,IAAKJ,EAAgB,QACrBM,IAAK,4BACLC,IAAK,WAEPe,GAAI,CACFnL,IAAK,IACLiK,IAAKmB,EAAgB,GACrBjB,IAAK,sBACLC,IAAK,WAEPiB,GAAI,CACFrL,IAAK,IACLiK,IAAKmB,EAAgB,GACrBjB,IAAK,kBACLC,IAAK,WAEPkB,GAAI,CACFtL,IAAK,IACLiK,IAAKsB,EAAW,OAChBpB,IAAK,qBACLC,IAAK,WAEPoB,GAAI,CACFxL,IAAK,IACLiK,IAAKsB,EAAW,MAChBpB,IAAK,+BACLC,IAAK,WAEPqB,GAAI,CACFzL,IAAK,IACLiK,IAAKyB,EACLvB,IAAK,8BACLC,IAAK,WAEPuB,GAAI,CACF3L,IAAK,IACLiK,IAAK2B,EACLzB,IAAK,qBACLC,IAAK,UAIT3S,MAAM0B,GAAGZ,SAAU,UAAW,SAASO,GAErC,GAAIiR,EAAQpJ,eAAe7H,EAAE+H,WAAa/H,EAAE+S,UAAY/S,EAAEgT,SAAWhT,EAAEiT,WAAajT,EAAEkT,QAAS,CAC7F,IAAIC,EAAUnT,EAAEU,OAAOyS,QAAQC,cAC/B,GAAIpT,EAAE+H,UAAY,GAAI,CACpB,GAAIoL,IAAY,SAAWA,IAAY,UAAYA,IAAY,WAAY,CACzElC,EAAQjR,EAAE+H,SAASoJ,WAEhB,CACL,GAAInR,EAAEU,SAAWjB,SAASuD,MAAQmQ,IAAY,KAAOA,IAAY,SAAU,CACzEnT,EAAEmL,iBACF8F,EAAQjR,EAAE+H,SAASoJ,WAM3B,SAASJ,EAAgBsC,GACvB,OAAO,SAASC,GACd,IAAI7C,EAAUhR,SAASyL,cAAc,8BACrCqI,EAAiBF,EACjB,GAAI5C,IAAY,KAAM,CAEpBA,EAAUhR,SAASyL,cAAc,WACjC,GAAIuF,IAAY,KAAM,CAEpB,OAGF,GAAI4C,IAAU,QAAUA,IAAU,KAAM,CACtCE,EAAiB9C,GAIrB,IAAI+C,EAAMC,EAAUhU,SAASC,iBAAiB,WAE9C,UAAW6T,IAAmB,SAAU,CACtCC,EAAOD,MACF,CACL,OAAQA,GACN,IAAK,UACL,IAAIG,EAAMjU,SAASkU,gBAAgBC,WAAanU,SAASuD,KAAK4Q,UAC9D,IAAIC,EAAMH,EAAMjU,SAASkU,gBAAgBG,aAEzC,IAAK,IAAInU,EAAI,EAAGA,EAAI8T,EAAQ1O,OAAQpF,IAAK,CACvC6T,EAAOC,EAAQ9T,GACf,IAAIoU,EAAOP,EAAKpG,UAChB,IAAI4G,EAAOD,EAAOP,EAAKM,aAEvB,GAAKE,GAAQH,GAASE,EAAOL,EAAM,CACjC,OAGJ,MACA,IAAK,OACLF,EAAO/C,EAAQwD,mBACf,GAAIT,IAAS,KAAM,CACjBA,EAAOC,EAAQ,GAEjB,MACA,IAAK,KACLD,EAAO/C,EAAQC,uBACf,GAAI8C,IAAS,KAAM,CACjBA,EAAOC,EAAQA,EAAQ1O,OAAS,GAElC,MACA,IAAK,SACLyO,EAAOC,EAAQA,EAAQ1O,OAAS,GAChC,MACA,IAAK,MAEL,QACAyO,EAAOC,EAAQ,IAInB,GAAID,EAAM,CACR/C,EAAQyD,gBAAgB,qBACxBV,EAAKzQ,aAAa,oBAAqB,QACvC,IAAIoR,EAAOX,EAAKtI,cAAc,SAAWsI,EAAKtI,cAAc,KAC5D,GAAIiJ,IAAS,KAAM,CACjBA,EAAK5N,QAEP,IAAK+M,EAAU,CACbc,OAMR,SAASxB,IACPnT,SAAS4U,SAASC,OAAO,MAG3B,SAASlD,IACP,GAAI3R,SAAS8U,cAAe,CAC1B9U,SAAS8U,cAAcnO,QAI3B,SAASkM,EAAgBkC,GACvB,OAAO,WACL,IAAIC,EAAUC,EAAE,wCAChB,GAAID,EAAQ1P,SAAW,EAAG,CACxB5E,QAAQC,IAAI,oDACZ,OAEF,GAAIoU,GAAO,GAAKA,EAAMC,EAAQ1P,OAAQ,CACpC0P,EAAQD,GAAKG,YACR,CACLxU,QAAQC,IAAI,yCAKlB,SAASgU,IACP,IAAIQ,EAAMnV,SAASyL,cAAc,8BACjC,GAAI0J,IAAQ,KAAM,CAChB,OAEF,IAAIC,EAAOpV,SAASkU,gBAAgBC,WAAanU,SAASuD,KAAK4Q,UAC/DkB,EAAUrV,SAASkU,gBAAgBG,aACnCC,EAAOa,EAAIxH,UACX4G,EAAOD,EAAOa,EAAId,aAClBiB,EAAS,IAET,GAAKH,EAAIlE,yBAA2B,MAAUsD,EAAOc,EAAU,CAG7DpW,OAAOsW,OAAOtW,OAAOuW,QAAS,GAC9B,OAEF,GAAIJ,EAAQd,EAAOgB,EAAS,CAC1BrW,OAAOsW,OAAOtW,OAAOuW,QAASlB,EAAOgB,OAChC,CACL,IAAIG,EAAOL,EAAOC,EAClB,GAAII,EAAQlB,EAAOe,EAAS,CAC1BrW,OAAOsW,OAAOtW,OAAOuW,QAASjB,EAAOc,EAAUC,KAKrD,SAASrD,EAAWyD,GAClB,OAAO,WACLzW,OAAO0W,SAAS,EAAGD,GACnBpE,EAAgB,UAAhBA,IAIJ,SAASiB,EAAalL,EAAUuO,GAC9B,OAAO,WACL3W,OAAO4W,SAAS,EAAGxO,GACnBiK,EAAgBsE,EAAhBtE,IAIJ,SAASS,IACP9S,OAAO4W,SAAS,EAAG,GACnB7V,SAASyL,cAAc,MAAM3E,QAG/B,SAASkM,EAAW8C,GAClB,OAAO,WACL,IAAIpB,EAAO1U,SAASyL,cAAc,mCAClC,GAAIiJ,IAAS,KAAM,CACjB,IAAIhT,EAAMgT,EAAKlO,aAAa,QAC5B,GAAIsP,EAAQ,CACV7W,OAAOiD,KAAKR,OACP,CACLzC,OAAO2V,SAASmB,KAAOrU,KAM/B,SAASsU,EAAgBC,GACvB,IAAIC,EAAa,GAEjB,IAAK,IAAIC,KAAK3E,EAAS,CACrB,IAAI/J,EAAM+J,EAAQ2E,GAClBD,EAAWzO,EAAIoK,KAAOqE,EAAWzO,EAAIoK,MAAQ,GAC7CqE,EAAWzO,EAAIoK,KAAK7C,KAAKvH,GAG3B,IAAI2O,EAAStN,OAAOiG,KAAKmH,GAAYG,KAAK,SAASnR,EAAGoR,GACpD,OAAOJ,EAAWI,GAAGhR,OAAS4Q,EAAWhR,GAAGI,SAG9C,GAAI8Q,EAAO9Q,SAAW,EAAG,CACvB,OAGH,IAAIiR,EAAO,mEACVA,GAAQ,uDACVA,GAAQ,UAEN,IAAK,IAAIrW,EAAI,EAAGA,EAAIkW,EAAO9Q,OAAQpF,IAAK,CACtC,IAAI2R,EAAMqE,EAAWE,EAAOlW,IAE5B,IAAIsW,EAAetW,IAAOkW,EAAO9Q,OAAS,EAC1C,IAAIwG,EAAQ5L,EAAI,IAAM,EAEtB,GAAI4L,EAAO,CACTyK,GAAQ,OAEVA,GAAQ,OAERA,GAAQ,OAAS1E,EAAI,GAAGA,IAAM,QAC9B0E,GAAQ,6BAER,IAAK,IAAIE,KAAM5E,EAAK,CAClB0E,GAAQ,YAAc1E,EAAI4E,GAAIhP,IAAM,UAAYoK,EAAI4E,GAAI7E,IAAM,QAGhE2E,GAAQ,QACRA,GAAQ,QAER,IAAKzK,GAAS0K,EAAc,CAC1BD,GAAQ,SAIdA,GAAQ,WAENN,EAAWzH,UAAY+H,EAGzB,SAASlD,IACR,IAAIqD,EAAY1W,SAASyL,cAAc,qBACvC/K,QAAQC,IAAI+V,GACb,GAAIA,IAAc9O,WAAa8O,IAAc,KAAM,CAElDA,EAAY1W,SAASqD,cAAc,OAChCqT,EAAUzT,GAAK,mBACjByT,EAAUC,UAAU,eACpBD,EAAUxG,MAAM,aACjB8F,EAAgBU,GAChB,IAAInT,EAAOvD,SAASoM,qBAAqB,QAAQ,GACjD7I,EAAKC,YAAYkT,OACX,CAENA,EAAUxS,UAAU0S,OAAO,aAC3B,YAuBH,SAAWzX,EAAGC,EAAGF,GACf,aAEAA,EAAMmC,MAAM,WACVnC,EAAM0B,GAAG,0BAA2B,QAAS,SAASqG,GAEpDpH,KAAKqE,UAAUmI,OAAO,0BAGtB,IAAIwK,EAAe,gDACnB,IAAIC,EAAcD,EAAe,2BACjC,IAAIE,EAAY,cAEhB,IAAIC,EAASnX,KAAKoX,QAAQC,MAC1B,IAAIC,EAAWtX,KAAKoX,QAAQG,QAC5B,IAAIC,EAAejY,EAAEqM,cAAc,IAAM5L,KAAKoX,QAAQK,aACtD,IAAIC,EAAwBnY,EAAEqM,cAAc,IAAM5L,KAAKoX,QAAQO,qBAG/D,IAAIC,EAAkB,CAAE,YAAa,eAAgB,mBAAoB,gBAAiB,eAE1F,GAAGT,GAAUG,GAAYE,EAAc,CACrC,IAAIK,EAAQ,KACZ,OAAOP,GACL,IAAK,OACLO,EAAQZ,EAAc,QAAUE,EAAS,KAAOD,EAChD,MACA,IAAK,MACLW,EAAQZ,EAAc,OAASE,EAAS,KAAOD,EAC/C,MACA,IAAK,WACLW,EAAQZ,EAAc,YAAcE,EAAS,KAAOD,EACpD,MACA,QACA,MAEF,GAAGW,EAAO,CAERxY,EAAMsC,KAAM,MAAOkW,GAAQ1V,KAAK,SAASuU,EAAMoB,GAC7CpB,EAAO1H,KAAKC,MAAMyH,GAClB,GAAGA,GAAQA,EAAKzQ,UAAYyQ,EAAKzQ,SAAS,GAAI,CAC5C,IAAI/B,EAAUwS,EAAKzQ,SAAS,GAC5B,IAAI8R,EAAU,GACd,IAAK,IAAIC,KAAO9T,EAAQ+T,KAAM,CAC5B,GAAG/T,EAAQ+T,KAAKrP,OAAS,MAAQgP,EAAgBhO,QAAQoO,KAAS,EAAG,CACnED,GAAW,WAAaC,EAAM,YAC9B,OAAOA,GACL,IAAK,QACL,IAAK,MACLD,GAAW,gBAAmB7T,EAAQ+T,KAAKD,GAAK3U,QAAQ,KAAK,IAAM,KAAQa,EAAQ+T,KAAKD,GAAO,OAC/F,MACA,IAAK,QACLD,GAAW,mBAAsB7T,EAAQ+T,KAAKD,GAAO,KAAQ9T,EAAQ+T,KAAKD,GAAO,OACjF,MACA,IAAK,UACL,IAAK,MACLD,GAAW,YAAe7T,EAAQ+T,KAAKD,GAAO,KAAQ9T,EAAQ+T,KAAKD,GAAO,OAC1E,MACA,IAAK,WACLD,GAAW,0CAA6C7T,EAAQ+T,KAAKD,GAAO,KAAQ9T,EAAQ+T,KAAKD,GAAO,OACxG,MACA,IAAK,YACL,GAAG9T,EAAQ+T,KAAKD,GAAKpO,QAAQ,OAAS,EAAG,CACvCmO,GAAW,oBAAuB7T,EAAQ+T,KAAKD,GAAKE,UAAU,EAAEhU,EAAQ+T,KAAKD,GAAKpO,QAAQ,MAAQ,uBAAyB1F,EAAQ+T,KAAKD,GAAKE,UAAUhU,EAAQ+T,KAAKD,GAAKpO,QAAQ,KAAK,GAAK,KAAQ1F,EAAQ+T,KAAKD,GAAO,OACvN,MAGF,QAEAD,GAAW7T,EAAQ+T,KAAKD,GACxB,MAEFD,GAAW,cAGtBL,EAAsBxX,WAAWyK,YAAY+M,GACtCF,EAAanT,UAAUmI,OAAO,aAC9BgL,EAAa5L,cAAc,SAAS+C,UAAYoJ,KAGnD3V,MAAM,WACLsV,EAAsBrT,UAAUmI,OAAO,aACvCkL,EAAsB/I,UAAY,0BAMxCvH,EAAMyE,mBAGRxM,EAAM0B,GAAG,kBAAmB,QAAS,SAASqG,GAE5CpH,KAAKqE,UAAUmI,OAAO,kBAGtB,IAAI2L,EAAiBnY,KAAKoX,QAAQgB,cAClC,IAAIC,EAAUC,WAAWtY,KAAKoX,QAAQmB,QACtC,IAAIC,EAAUF,WAAWtY,KAAKoX,QAAQqB,QACtC,IAAIC,EAAWJ,WAAWtY,KAAKoX,QAAQuB,SACvC,IAAIC,EAAkB5J,KAAKC,MAAMjP,KAAKoX,QAAQyB,gBAC9C,IAAIC,EAAc9J,KAAKC,MAAMjP,KAAKoX,QAAQ2B,YAE1C1Z,EAAM2D,UAAU,uBAChB3D,EAAMuE,WAAW,qBAAsB,WACrC,IAAIoV,EAAa,KACjB,GAAGJ,EAAiB,CAClB,IAAIK,EAAYC,EAAEC,OAAOP,EAAgB,GAAIA,EAAgB,IAC7D,IAAIQ,EAAYF,EAAEC,OAAOP,EAAgB,GAAIA,EAAgB,IAC7DI,EAAaE,EAAEG,aAAaJ,EAAWG,GAIzC,IAAIE,EAAMJ,EAAEI,IAAInB,GAEhB,IAAIoB,EAAa,qDACjB,IAAIC,EAAgB,gFACpB,IAAIC,EAAY,IAAIP,EAAEQ,UAAUH,EAAc,CAACI,QAAS,EAAGC,QAAS,GAAIC,YAAaL,IACrF,IAAIM,EAAgB,sDACpB,IAAIC,EAAqB,uGACzB,IAAIC,EAAe,IAAId,EAAEQ,UAAUI,EAAiB,CAACH,QAAS,EAAGC,QAAS,GAAIC,YAAaE,IAE3F,GAAGf,EAAY,CAGb5O,WAAW,WACTkP,EAAIW,UAAUjB,EAAY,CACxBY,QAAQ,MAET,QACE,GAAIvB,GAAWG,EAAS,CAC7B,GAAGE,EAAU,CACXY,EAAIY,QAAQ,IAAIhB,EAAEC,OAAOX,EAASH,GAASK,OACtC,CACLY,EAAIY,QAAQ,IAAIhB,EAAEC,OAAOX,EAASH,GAAS,IAI/CiB,EAAIa,SAASV,GAEb,IAAIW,EAAa,CACfC,aAAcZ,GAIhBP,EAAEoB,QAAQC,OAAOH,GAAYI,MAAMlB,GAEnC,GAAGR,EAAa,CACdI,EAAEuB,QAAQ3B,GAAa0B,MAAMlB,MAOjClS,EAAMyE,sBA3JZ,CA8JGzM,OAAQe,SAAUf,OAAOC,QAiB5B,SAAUC,EAAGC,EAAGF,GACd,aAEAA,EAAMmC,MAAM,WACVnC,EAAMqb,uBAAyB,IAAIrb,EAAM+P,YAAY,QAAS,uBAAwB,sBAAuB,KAC7G/P,EAAMqb,uBAAuBrJ,QAE7BhS,EAAM0B,GAAG,gBAAiB,QAAS,SAASqG,GAC1C,IAAIuT,EAAoB3a,KAAK2G,aAAa,2BAC1C,IAAIiU,EAAuB5a,KAAK2G,aAAa,+BAC7C,IAAIvF,EAASpB,KAAK2G,aAAa,eAC/B,IAAIkU,EAAgBtb,EAAEqM,cAAcxK,GACpC,IAAIsV,EAAO1W,KAAK2O,UAChB,GAAI3O,KAAKqE,UAAUqN,SAAS,aAAc,CACxCgF,EAAOA,EAAKrT,QAAQsX,EAAmBC,OAClC,CACLlE,EAAOA,EAAKrT,QAAQuX,EAAsBD,GAE5C3a,KAAK2O,UAAY+H,EACjB1W,KAAKqE,UAAU0S,OAAO,aACtB8D,EAAcxW,UAAU0S,OAAO,eAGjC1X,EAAM0B,GAAG,gBAAiB,QAAS,SAASqG,GAC1C,IAAIhG,EAASpB,KAAK2G,aAAa,eAC/B,IAAImU,EAAcvb,EAAEqM,cAAcxK,EAAS,aAC3C,IAAI2Z,EAAUD,EAAYnU,aAAa,OACvC,GAAIoU,IAAY,MAAQA,IAAYhT,WAAagT,IAAY,MAAO,CAClED,EAAYrX,aAAa,MAAOqX,EAAYnU,aAAa,gBAI7DrH,EAAE6B,iBAAiB,SAAU,WAC3B,IAAIT,EAAInB,EAAEgE,eAAe,aACzB+Q,EAAYnU,SAASkU,gBAAgBC,WAAanU,SAASuD,KAAK4Q,UAChE,GAAI5T,IAAM,KAAM,CACd,GAAI4T,GAAa,IAAK,CACpB5T,EAAE2P,MAAM2K,QAAU,MACb,CACLta,EAAE2P,MAAM2K,QAAU,SAvC5B,CA8CG5b,OAAQe,SAAUf,OAAOC,QAiB5B,SAAUC,EAAGC,EAAGF,GACd,aAEA,IAAI4b,EAAa,KAAMC,EAAY,IAAKC,EAExC,SAASC,EAAiBlX,GACxB,GAAIA,EAAQmX,kBAAmB,CAC7B,IAAIC,EAAMpX,EAAQ+G,MAAMxF,OACxBvB,EAAQmX,kBAAkBC,EAAKA,IAInC,SAASC,IACP,GAAIJ,EAAOlQ,MAAMxF,OAAU,EAAG,CAC5B,IAAI+V,EAASrb,SAASoD,eAAe,UACrC6G,WAAWoR,EAAOC,OAAO/Z,KAAK8Z,GAAS,IAI3C,SAASE,EAAkBP,GACzB,IAAIQ,EAAKxb,SAASoD,eAAe,gBACjC,IAAIqY,EAAoB,WACtB,GAAIT,EAAOlQ,MAAMxF,SAAW,EAAG,CACpCkW,EAAGtX,UAAUC,IAAI,aACL,CACZqX,EAAGtX,UAAUmI,OAAO,WAKjBoP,IACAD,EAAGxa,iBAAiB,QAAS,WAC3Bga,EAAOlQ,MAAM,GACbkQ,EAAOlU,QACP2U,MAEFT,EAAOha,iBAAiB,QAASya,EAAmB,OAGtDvc,EAAMmC,MAAM,WACV2Z,EAAS5b,EAAEgE,eAAe2X,GAE1B,SAASW,EAAqBnb,GAC5B,GAAIua,EAAY,CACdG,EAAiBD,GACjBF,EAAa,UACR,GAKT,GAAIE,IAAW,KAAM,CAEnBO,EAAkBP,GAGlB,GAAI9b,EAAMyc,cAAe,CACvBzc,EAAM0c,aAAehX,aAAapE,KAAKrB,EAAG,CACxCmM,IAAK,kBACLX,aAAczL,EAAM2c,cACpBzQ,WAAYlM,EAAMuC,OAClB0J,SAAU,EACVjB,MAAO,KACN,IAAM6Q,GAGT5b,EAAE6B,iBAAiB,SAAU,WAC3B,IAAIiG,EAAQ,IAAI6U,YAAY,YAC5Bd,EAAOe,cAAc9U,KAIzB+T,EAAOha,iBAAiB,QAAS0a,EAAsB,OACvDV,EAAOlU,QAIT,GAAIkU,IAAW,MAAQ9b,EAAM8c,0BAA2B,CACtD5c,EAAEqM,cAAc,SAASkL,UAAU,YAEnCzX,EAAM0B,GAAG,oBAAqB,SAAU,SAASL,GAC/C,IAAIL,EAAGgW,EAAa9W,EAAEa,iBAAiB,sCACvC,IAAIC,EAAE,EAAGA,EAAEgW,EAAW5Q,OAAQpF,IAAK,CACjC,GAAIgW,EAAWhW,KAAOL,MAAQqW,EAAWhW,GAAG+b,QAAS,CACnD/F,EAAWhW,GAAGgV,SAGlB,IAAMrV,KAAKoc,QAAS,CAClBpc,KAAKqV,QAEPkG,IACA,OAAO,QAGTlc,EAAM0B,GAAGxB,EAAEgE,eAAe,cAAe,SAAUgY,GACnDlc,EAAM0B,GAAGxB,EAAEgE,eAAe,YAAa,SAAUgY,OA/FvD,CAoGGnc,OAAQe,SAAUf,OAAOC","file":"searx.min.js"}
searx/static/themes/simple/js/searx_head/00_init.jsnew file+40
@@ -0,0 +1,40 @@
1+/**
2+* searx is free software: you can redistribute it and/or modify
3+* it under the terms of the GNU Affero General Public License as published by
4+* the Free Software Foundation, either version 3 of the License, or
5+* (at your option) any later version.
6+*
7+* searx is distributed in the hope that it will be useful,
8+* but WITHOUT ANY WARRANTY; without even the implied warranty of
9+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+* GNU Affero General Public License for more details.
11+*
12+* You should have received a copy of the GNU Affero General Public License
13+* along with searx. If not, see < http://www.gnu.org/licenses/ >.
14+*
15+* (C) 2019 by Alexandre Flament
16+*
17+*/
18+(function(w, d) {
19+ 'use strict';
20+
21+ // add data- properties
22+ var script = d.currentScript || (function() {
23+ var scripts = d.getElementsByTagName('script');
24+ return scripts[scripts.length - 1];
25+ })();
26+
27+ // try to detect touch screen
28+ w.searx = {
29+ touch: (("ontouchstart" in w) || w.DocumentTouch && document instanceof DocumentTouch) || false,
30+ method: script.getAttribute('data-method'),
31+ autocompleter: script.getAttribute('data-autocompleter') === 'true',
32+ search_on_category_select: script.getAttribute('data-search-on-category-select') === 'true',
33+ infinite_scroll: script.getAttribute('data-infinite-scroll') === 'true',
34+ static_path: script.getAttribute('data-static-path'),
35+ no_item_found: script.getAttribute('data-no-item-found')
36+ }
37+
38+ // update the css
39+ d.getElementsByTagName("html")[0].className = (w.searx.touch)?"js touch":"js";
40+})(window, document);
searx/static/themes/simple/js/searx_src/00_searx_toolkit.js+5−5
@@ -15,7 +15,7 @@
15* (C) 2017 by Alexandre Flament, <alex@al-f.net>
15* (C) 2017 by Alexandre Flament, <alex@al-f.net>
16*
16*
17*/
17*/
18−(function(w, d, searx) {
18+window.searx = (function(w, d) {
19
19
20 'use strict';
20 'use strict';
21
21
@@ -45,7 +45,7 @@
45 }
45 }
46 }
46 }
47
47
48− searx = searx || {};
48+ var searx = window.searx || {};
49
49
50 searx.on = function(obj, eventType, callback, useCapture) {
50 searx.on = function(obj, eventType, callback, useCapture) {
51 useCapture = useCapture || false;
51 useCapture = useCapture || false;
@@ -110,7 +110,7 @@
110 };
110 };
111
111
112 searx.loadStyle = function(src) {
112 searx.loadStyle = function(src) {
113− var path = searx.staticPath + src,
113+ var path = searx.static_path + src,
114 id = "style_" + src.replace('.', '_'),
114 id = "style_" + src.replace('.', '_'),
115 s = d.getElementById(id);
115 s = d.getElementById(id);
116 if (s === null) {
116 if (s === null) {
@@ -124,7 +124,7 @@
124 };
124 };
125
125
126 searx.loadScript = function(src, callback) {
126 searx.loadScript = function(src, callback) {
127− var path = searx.staticPath + src,
127+ var path = searx.static_path + src,
128 id = "script_" + src.replace('.', '_'),
128 id = "script_" + src.replace('.', '_'),
129 s = d.getElementById(id);
129 s = d.getElementById(id);
130 if (s === null) {
130 if (s === null) {
@@ -161,4 +161,4 @@
161 });
161 });
162
162
163 return searx;
163 return searx;
164−})(window, document, window.searx);
164+})(window, document);
searx/static/themes/simple/js/searx_src/searx_search.js+1−1
@@ -73,7 +73,7 @@
73 if (searx.autocompleter) {
73 if (searx.autocompleter) {
74 searx.autocomplete = AutoComplete.call(w, {
74 searx.autocomplete = AutoComplete.call(w, {
75 Url: "./autocompleter",
75 Url: "./autocompleter",
76− EmptyMessage: searx.noItemFound,
76+ EmptyMessage: searx.no_item_found,
77 HttpMethod: searx.method,
77 HttpMethod: searx.method,
78 MinChars: 4,
78 MinChars: 4,
79 Delay: 300,
79 Delay: 300,
searx/static/themes/simple/leaflet/leaflet.css+636−636
@@ -1,636 +1,636 @@
1−/* required styles */
1+/* required styles */
2−
2+
3−.leaflet-pane,
3+.leaflet-pane,
4−.leaflet-tile,
4+.leaflet-tile,
5−.leaflet-marker-icon,
5+.leaflet-marker-icon,
6−.leaflet-marker-shadow,
6+.leaflet-marker-shadow,
7−.leaflet-tile-container,
7+.leaflet-tile-container,
8−.leaflet-pane > svg,
8+.leaflet-pane > svg,
9−.leaflet-pane > canvas,
9+.leaflet-pane > canvas,
10−.leaflet-zoom-box,
10+.leaflet-zoom-box,
11−.leaflet-image-layer,
11+.leaflet-image-layer,
12−.leaflet-layer {
12+.leaflet-layer {
13− position: absolute;
13+ position: absolute;
14− left: 0;
14+ left: 0;
15− top: 0;
15+ top: 0;
16− }
16+ }
17−.leaflet-container {
17+.leaflet-container {
18− overflow: hidden;
18+ overflow: hidden;
19− }
19+ }
20−.leaflet-tile,
20+.leaflet-tile,
21−.leaflet-marker-icon,
21+.leaflet-marker-icon,
22−.leaflet-marker-shadow {
22+.leaflet-marker-shadow {
23− -webkit-user-select: none;
23+ -webkit-user-select: none;
24− -moz-user-select: none;
24+ -moz-user-select: none;
25− user-select: none;
25+ user-select: none;
26− -webkit-user-drag: none;
26+ -webkit-user-drag: none;
27− }
27+ }
28−/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
28+/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
29−.leaflet-safari .leaflet-tile {
29+.leaflet-safari .leaflet-tile {
30− image-rendering: -webkit-optimize-contrast;
30+ image-rendering: -webkit-optimize-contrast;
31− }
31+ }
32−/* hack that prevents hw layers "stretching" when loading new tiles */
32+/* hack that prevents hw layers "stretching" when loading new tiles */
33−.leaflet-safari .leaflet-tile-container {
33+.leaflet-safari .leaflet-tile-container {
34− width: 1600px;
34+ width: 1600px;
35− height: 1600px;
35+ height: 1600px;
36− -webkit-transform-origin: 0 0;
36+ -webkit-transform-origin: 0 0;
37− }
37+ }
38−.leaflet-marker-icon,
38+.leaflet-marker-icon,
39−.leaflet-marker-shadow {
39+.leaflet-marker-shadow {
40− display: block;
40+ display: block;
41− }
41+ }
42−/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
42+/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
43−/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
43+/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
44−.leaflet-container .leaflet-overlay-pane svg,
44+.leaflet-container .leaflet-overlay-pane svg,
45−.leaflet-container .leaflet-marker-pane img,
45+.leaflet-container .leaflet-marker-pane img,
46−.leaflet-container .leaflet-shadow-pane img,
46+.leaflet-container .leaflet-shadow-pane img,
47−.leaflet-container .leaflet-tile-pane img,
47+.leaflet-container .leaflet-tile-pane img,
48−.leaflet-container img.leaflet-image-layer {
48+.leaflet-container img.leaflet-image-layer {
49− max-width: none !important;
49+ max-width: none !important;
50− max-height: none !important;
50+ max-height: none !important;
51− }
51+ }
52−
52+
53−.leaflet-container.leaflet-touch-zoom {
53+.leaflet-container.leaflet-touch-zoom {
54− -ms-touch-action: pan-x pan-y;
54+ -ms-touch-action: pan-x pan-y;
55− touch-action: pan-x pan-y;
55+ touch-action: pan-x pan-y;
56− }
56+ }
57−.leaflet-container.leaflet-touch-drag {
57+.leaflet-container.leaflet-touch-drag {
58− -ms-touch-action: pinch-zoom;
58+ -ms-touch-action: pinch-zoom;
59− /* Fallback for FF which doesn't support pinch-zoom */
59+ /* Fallback for FF which doesn't support pinch-zoom */
60− touch-action: none;
60+ touch-action: none;
61− touch-action: pinch-zoom;
61+ touch-action: pinch-zoom;
62−}
62+}
63−.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
63+.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
64− -ms-touch-action: none;
64+ -ms-touch-action: none;
65− touch-action: none;
65+ touch-action: none;
66−}
66+}
67−.leaflet-container {
67+.leaflet-container {
68− -webkit-tap-highlight-color: transparent;
68+ -webkit-tap-highlight-color: transparent;
69−}
69+}
70−.leaflet-container a {
70+.leaflet-container a {
71− -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
71+ -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
72−}
72+}
73−.leaflet-tile {
73+.leaflet-tile {
74− filter: inherit;
74+ filter: inherit;
75− visibility: hidden;
75+ visibility: hidden;
76− }
76+ }
77−.leaflet-tile-loaded {
77+.leaflet-tile-loaded {
78− visibility: inherit;
78+ visibility: inherit;
79− }
79+ }
80−.leaflet-zoom-box {
80+.leaflet-zoom-box {
81− width: 0;
81+ width: 0;
82− height: 0;
82+ height: 0;
83− -moz-box-sizing: border-box;
83+ -moz-box-sizing: border-box;
84− box-sizing: border-box;
84+ box-sizing: border-box;
85− z-index: 800;
85+ z-index: 800;
86− }
86+ }
87−/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
87+/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
88−.leaflet-overlay-pane svg {
88+.leaflet-overlay-pane svg {
89− -moz-user-select: none;
89+ -moz-user-select: none;
90− }
90+ }
91−
91+
92−.leaflet-pane { z-index: 400; }
92+.leaflet-pane { z-index: 400; }
93−
93+
94−.leaflet-tile-pane { z-index: 200; }
94+.leaflet-tile-pane { z-index: 200; }
95−.leaflet-overlay-pane { z-index: 400; }
95+.leaflet-overlay-pane { z-index: 400; }
96−.leaflet-shadow-pane { z-index: 500; }
96+.leaflet-shadow-pane { z-index: 500; }
97−.leaflet-marker-pane { z-index: 600; }
97+.leaflet-marker-pane { z-index: 600; }
98−.leaflet-tooltip-pane { z-index: 650; }
98+.leaflet-tooltip-pane { z-index: 650; }
99−.leaflet-popup-pane { z-index: 700; }
99+.leaflet-popup-pane { z-index: 700; }
100−
100+
101−.leaflet-map-pane canvas { z-index: 100; }
101+.leaflet-map-pane canvas { z-index: 100; }
102−.leaflet-map-pane svg { z-index: 200; }
102+.leaflet-map-pane svg { z-index: 200; }
103−
103+
104−.leaflet-vml-shape {
104+.leaflet-vml-shape {
105− width: 1px;
105+ width: 1px;
106− height: 1px;
106+ height: 1px;
107− }
107+ }
108−.lvml {
108+.lvml {
109− behavior: url(#default#VML);
109+ behavior: url(#default#VML);
110− display: inline-block;
110+ display: inline-block;
111− position: absolute;
111+ position: absolute;
112− }
112+ }
113−
113+
114−
114+
115−/* control positioning */
115+/* control positioning */
116−
116+
117−.leaflet-control {
117+.leaflet-control {
118− position: relative;
118+ position: relative;
119− z-index: 800;
119+ z-index: 800;
120− pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
120+ pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
121− pointer-events: auto;
121+ pointer-events: auto;
122− }
122+ }
123−.leaflet-top,
123+.leaflet-top,
124−.leaflet-bottom {
124+.leaflet-bottom {
125− position: absolute;
125+ position: absolute;
126− z-index: 1000;
126+ z-index: 1000;
127− pointer-events: none;
127+ pointer-events: none;
128− }
128+ }
129−.leaflet-top {
129+.leaflet-top {
130− top: 0;
130+ top: 0;
131− }
131+ }
132−.leaflet-right {
132+.leaflet-right {
133− right: 0;
133+ right: 0;
134− }
134+ }
135−.leaflet-bottom {
135+.leaflet-bottom {
136− bottom: 0;
136+ bottom: 0;
137− }
137+ }
138−.leaflet-left {
138+.leaflet-left {
139− left: 0;
139+ left: 0;
140− }
140+ }
141−.leaflet-control {
141+.leaflet-control {
142− float: left;
142+ float: left;
143− clear: both;
143+ clear: both;
144− }
144+ }
145−.leaflet-right .leaflet-control {
145+.leaflet-right .leaflet-control {
146− float: right;
146+ float: right;
147− }
147+ }
148−.leaflet-top .leaflet-control {
148+.leaflet-top .leaflet-control {
149− margin-top: 10px;
149+ margin-top: 10px;
150− }
150+ }
151−.leaflet-bottom .leaflet-control {
151+.leaflet-bottom .leaflet-control {
152− margin-bottom: 10px;
152+ margin-bottom: 10px;
153− }
153+ }
154−.leaflet-left .leaflet-control {
154+.leaflet-left .leaflet-control {
155− margin-left: 10px;
155+ margin-left: 10px;
156− }
156+ }
157−.leaflet-right .leaflet-control {
157+.leaflet-right .leaflet-control {
158− margin-right: 10px;
158+ margin-right: 10px;
159− }
159+ }
160−
160+
161−
161+
162−/* zoom and fade animations */
162+/* zoom and fade animations */
163−
163+
164−.leaflet-fade-anim .leaflet-tile {
164+.leaflet-fade-anim .leaflet-tile {
165− will-change: opacity;
165+ will-change: opacity;
166− }
166+ }
167−.leaflet-fade-anim .leaflet-popup {
167+.leaflet-fade-anim .leaflet-popup {
168− opacity: 0;
168+ opacity: 0;
169− -webkit-transition: opacity 0.2s linear;
169+ -webkit-transition: opacity 0.2s linear;
170− -moz-transition: opacity 0.2s linear;
170+ -moz-transition: opacity 0.2s linear;
171− -o-transition: opacity 0.2s linear;
171+ -o-transition: opacity 0.2s linear;
172− transition: opacity 0.2s linear;
172+ transition: opacity 0.2s linear;
173− }
173+ }
174−.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
174+.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
175− opacity: 1;
175+ opacity: 1;
176− }
176+ }
177−.leaflet-zoom-animated {
177+.leaflet-zoom-animated {
178− -webkit-transform-origin: 0 0;
178+ -webkit-transform-origin: 0 0;
179− -ms-transform-origin: 0 0;
179+ -ms-transform-origin: 0 0;
180− transform-origin: 0 0;
180+ transform-origin: 0 0;
181− }
181+ }
182−.leaflet-zoom-anim .leaflet-zoom-animated {
182+.leaflet-zoom-anim .leaflet-zoom-animated {
183− will-change: transform;
183+ will-change: transform;
184− }
184+ }
185−.leaflet-zoom-anim .leaflet-zoom-animated {
185+.leaflet-zoom-anim .leaflet-zoom-animated {
186− -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
186+ -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
187− -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
187+ -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
188− -o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
188+ -o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
189− transition: transform 0.25s cubic-bezier(0,0,0.25,1);
189+ transition: transform 0.25s cubic-bezier(0,0,0.25,1);
190− }
190+ }
191−.leaflet-zoom-anim .leaflet-tile,
191+.leaflet-zoom-anim .leaflet-tile,
192−.leaflet-pan-anim .leaflet-tile {
192+.leaflet-pan-anim .leaflet-tile {
193− -webkit-transition: none;
193+ -webkit-transition: none;
194− -moz-transition: none;
194+ -moz-transition: none;
195− -o-transition: none;
195+ -o-transition: none;
196− transition: none;
196+ transition: none;
197− }
197+ }
198−
198+
199−.leaflet-zoom-anim .leaflet-zoom-hide {
199+.leaflet-zoom-anim .leaflet-zoom-hide {
200− visibility: hidden;
200+ visibility: hidden;
201− }
201+ }
202−
202+
203−
203+
204−/* cursors */
204+/* cursors */
205−
205+
206−.leaflet-interactive {
206+.leaflet-interactive {
207− cursor: pointer;
207+ cursor: pointer;
208− }
208+ }
209−.leaflet-grab {
209+.leaflet-grab {
210− cursor: -webkit-grab;
210+ cursor: -webkit-grab;
211− cursor: -moz-grab;
211+ cursor: -moz-grab;
212− }
212+ }
213−.leaflet-crosshair,
213+.leaflet-crosshair,
214−.leaflet-crosshair .leaflet-interactive {
214+.leaflet-crosshair .leaflet-interactive {
215− cursor: crosshair;
215+ cursor: crosshair;
216− }
216+ }
217−.leaflet-popup-pane,
217+.leaflet-popup-pane,
218−.leaflet-control {
218+.leaflet-control {
219− cursor: auto;
219+ cursor: auto;
220− }
220+ }
221−.leaflet-dragging .leaflet-grab,
221+.leaflet-dragging .leaflet-grab,
222−.leaflet-dragging .leaflet-grab .leaflet-interactive,
222+.leaflet-dragging .leaflet-grab .leaflet-interactive,
223−.leaflet-dragging .leaflet-marker-draggable {
223+.leaflet-dragging .leaflet-marker-draggable {
224− cursor: move;
224+ cursor: move;
225− cursor: -webkit-grabbing;
225+ cursor: -webkit-grabbing;
226− cursor: -moz-grabbing;
226+ cursor: -moz-grabbing;
227− }
227+ }
228−
228+
229−/* marker & overlays interactivity */
229+/* marker & overlays interactivity */
230−.leaflet-marker-icon,
230+.leaflet-marker-icon,
231−.leaflet-marker-shadow,
231+.leaflet-marker-shadow,
232−.leaflet-image-layer,
232+.leaflet-image-layer,
233−.leaflet-pane > svg path,
233+.leaflet-pane > svg path,
234−.leaflet-tile-container {
234+.leaflet-tile-container {
235− pointer-events: none;
235+ pointer-events: none;
236− }
236+ }
237−
237+
238−.leaflet-marker-icon.leaflet-interactive,
238+.leaflet-marker-icon.leaflet-interactive,
239−.leaflet-image-layer.leaflet-interactive,
239+.leaflet-image-layer.leaflet-interactive,
240−.leaflet-pane > svg path.leaflet-interactive {
240+.leaflet-pane > svg path.leaflet-interactive {
241− pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
241+ pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
242− pointer-events: auto;
242+ pointer-events: auto;
243− }
243+ }
244−
244+
245−/* visual tweaks */
245+/* visual tweaks */
246−
246+
247−.leaflet-container {
247+.leaflet-container {
248− background: #ddd;
248+ background: #ddd;
249− outline: 0;
249+ outline: 0;
250− }
250+ }
251−.leaflet-container a {
251+.leaflet-container a {
252− color: #0078A8;
252+ color: #0078A8;
253− }
253+ }
254−.leaflet-container a.leaflet-active {
254+.leaflet-container a.leaflet-active {
255− outline: 2px solid orange;
255+ outline: 2px solid orange;
256− }
256+ }
257−.leaflet-zoom-box {
257+.leaflet-zoom-box {
258− border: 2px dotted #38f;
258+ border: 2px dotted #38f;
259− background: rgba(255,255,255,0.5);
259+ background: rgba(255,255,255,0.5);
260− }
260+ }
261−
261+
262−
262+
263−/* general typography */
263+/* general typography */
264−.leaflet-container {
264+.leaflet-container {
265− font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
265+ font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
266− }
266+ }
267−
267+
268−
268+
269−/* general toolbar styles */
269+/* general toolbar styles */
270−
270+
271−.leaflet-bar {
271+.leaflet-bar {
272− box-shadow: 0 1px 5px rgba(0,0,0,0.65);
272+ box-shadow: 0 1px 5px rgba(0,0,0,0.65);
273− border-radius: 4px;
273+ border-radius: 4px;
274− }
274+ }
275−.leaflet-bar a,
275+.leaflet-bar a,
276−.leaflet-bar a:hover {
276+.leaflet-bar a:hover {
277− background-color: #fff;
277+ background-color: #fff;
278− border-bottom: 1px solid #ccc;
278+ border-bottom: 1px solid #ccc;
279− width: 26px;
279+ width: 26px;
280− height: 26px;
280+ height: 26px;
281− line-height: 26px;
281+ line-height: 26px;
282− display: block;
282+ display: block;
283− text-align: center;
283+ text-align: center;
284− text-decoration: none;
284+ text-decoration: none;
285− color: black;
285+ color: black;
286− }
286+ }
287−.leaflet-bar a,
287+.leaflet-bar a,
288−.leaflet-control-layers-toggle {
288+.leaflet-control-layers-toggle {
289− background-position: 50% 50%;
289+ background-position: 50% 50%;
290− background-repeat: no-repeat;
290+ background-repeat: no-repeat;
291− display: block;
291+ display: block;
292− }
292+ }
293−.leaflet-bar a:hover {
293+.leaflet-bar a:hover {
294− background-color: #f4f4f4;
294+ background-color: #f4f4f4;
295− }
295+ }
296−.leaflet-bar a:first-child {
296+.leaflet-bar a:first-child {
297− border-top-left-radius: 4px;
297+ border-top-left-radius: 4px;
298− border-top-right-radius: 4px;
298+ border-top-right-radius: 4px;
299− }
299+ }
300−.leaflet-bar a:last-child {
300+.leaflet-bar a:last-child {
301− border-bottom-left-radius: 4px;
301+ border-bottom-left-radius: 4px;
302− border-bottom-right-radius: 4px;
302+ border-bottom-right-radius: 4px;
303− border-bottom: none;
303+ border-bottom: none;
304− }
304+ }
305−.leaflet-bar a.leaflet-disabled {
305+.leaflet-bar a.leaflet-disabled {
306− cursor: default;
306+ cursor: default;
307− background-color: #f4f4f4;
307+ background-color: #f4f4f4;
308− color: #bbb;
308+ color: #bbb;
309− }
309+ }
310−
310+
311−.leaflet-touch .leaflet-bar a {
311+.leaflet-touch .leaflet-bar a {
312− width: 30px;
312+ width: 30px;
313− height: 30px;
313+ height: 30px;
314− line-height: 30px;
314+ line-height: 30px;
315− }
315+ }
316−.leaflet-touch .leaflet-bar a:first-child {
316+.leaflet-touch .leaflet-bar a:first-child {
317− border-top-left-radius: 2px;
317+ border-top-left-radius: 2px;
318− border-top-right-radius: 2px;
318+ border-top-right-radius: 2px;
319− }
319+ }
320−.leaflet-touch .leaflet-bar a:last-child {
320+.leaflet-touch .leaflet-bar a:last-child {
321− border-bottom-left-radius: 2px;
321+ border-bottom-left-radius: 2px;
322− border-bottom-right-radius: 2px;
322+ border-bottom-right-radius: 2px;
323− }
323+ }
324−
324+
325−/* zoom control */
325+/* zoom control */
326−
326+
327−.leaflet-control-zoom-in,
327+.leaflet-control-zoom-in,
328−.leaflet-control-zoom-out {
328+.leaflet-control-zoom-out {
329− font: bold 18px 'Lucida Console', Monaco, monospace;
329+ font: bold 18px 'Lucida Console', Monaco, monospace;
330− text-indent: 1px;
330+ text-indent: 1px;
331− }
331+ }
332−
332+
333−.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
333+.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
334− font-size: 22px;
334+ font-size: 22px;
335− }
335+ }
336−
336+
337−
337+
338−/* layers control */
338+/* layers control */
339−
339+
340−.leaflet-control-layers {
340+.leaflet-control-layers {
341− box-shadow: 0 1px 5px rgba(0,0,0,0.4);
341+ box-shadow: 0 1px 5px rgba(0,0,0,0.4);
342− background: #fff;
342+ background: #fff;
343− border-radius: 5px;
343+ border-radius: 5px;
344− }
344+ }
345−.leaflet-control-layers-toggle {
345+.leaflet-control-layers-toggle {
346− background-image: url(images/layers.png);
346+ background-image: url(images/layers.png);
347− width: 36px;
347+ width: 36px;
348− height: 36px;
348+ height: 36px;
349− }
349+ }
350−.leaflet-retina .leaflet-control-layers-toggle {
350+.leaflet-retina .leaflet-control-layers-toggle {
351− background-image: url(images/layers-2x.png);
351+ background-image: url(images/layers-2x.png);
352− background-size: 26px 26px;
352+ background-size: 26px 26px;
353− }
353+ }
354−.leaflet-touch .leaflet-control-layers-toggle {
354+.leaflet-touch .leaflet-control-layers-toggle {
355− width: 44px;
355+ width: 44px;
356− height: 44px;
356+ height: 44px;
357− }
357+ }
358−.leaflet-control-layers .leaflet-control-layers-list,
358+.leaflet-control-layers .leaflet-control-layers-list,
359−.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
359+.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
360− display: none;
360+ display: none;
361− }
361+ }
362−.leaflet-control-layers-expanded .leaflet-control-layers-list {
362+.leaflet-control-layers-expanded .leaflet-control-layers-list {
363− display: block;
363+ display: block;
364− position: relative;
364+ position: relative;
365− }
365+ }
366−.leaflet-control-layers-expanded {
366+.leaflet-control-layers-expanded {
367− padding: 6px 10px 6px 6px;
367+ padding: 6px 10px 6px 6px;
368− color: #333;
368+ color: #333;
369− background: #fff;
369+ background: #fff;
370− }
370+ }
371−.leaflet-control-layers-scrollbar {
371+.leaflet-control-layers-scrollbar {
372− overflow-y: scroll;
372+ overflow-y: scroll;
373− overflow-x: hidden;
373+ overflow-x: hidden;
374− padding-right: 5px;
374+ padding-right: 5px;
375− }
375+ }
376−.leaflet-control-layers-selector {
376+.leaflet-control-layers-selector {
377− margin-top: 2px;
377+ margin-top: 2px;
378− position: relative;
378+ position: relative;
379− top: 1px;
379+ top: 1px;
380− }
380+ }
381−.leaflet-control-layers label {
381+.leaflet-control-layers label {
382− display: block;
382+ display: block;
383− }
383+ }
384−.leaflet-control-layers-separator {
384+.leaflet-control-layers-separator {
385− height: 0;
385+ height: 0;
386− border-top: 1px solid #ddd;
386+ border-top: 1px solid #ddd;
387− margin: 5px -10px 5px -6px;
387+ margin: 5px -10px 5px -6px;
388− }
388+ }
389−
389+
390−/* Default icon URLs */
390+/* Default icon URLs */
391−.leaflet-default-icon-path {
391+.leaflet-default-icon-path {
392− background-image: url(images/marker-icon.png);
392+ background-image: url(images/marker-icon.png);
393− }
393+ }
394−
394+
395−
395+
396−/* attribution and scale controls */
396+/* attribution and scale controls */
397−
397+
398−.leaflet-container .leaflet-control-attribution {
398+.leaflet-container .leaflet-control-attribution {
399− background: #fff;
399+ background: #fff;
400− background: rgba(255, 255, 255, 0.7);
400+ background: rgba(255, 255, 255, 0.7);
401− margin: 0;
401+ margin: 0;
402− }
402+ }
403−.leaflet-control-attribution,
403+.leaflet-control-attribution,
404−.leaflet-control-scale-line {
404+.leaflet-control-scale-line {
405− padding: 0 5px;
405+ padding: 0 5px;
406− color: #333;
406+ color: #333;
407− }
407+ }
408−.leaflet-control-attribution a {
408+.leaflet-control-attribution a {
409− text-decoration: none;
409+ text-decoration: none;
410− }
410+ }
411−.leaflet-control-attribution a:hover {
411+.leaflet-control-attribution a:hover {
412− text-decoration: underline;
412+ text-decoration: underline;
413− }
413+ }
414−.leaflet-container .leaflet-control-attribution,
414+.leaflet-container .leaflet-control-attribution,
415−.leaflet-container .leaflet-control-scale {
415+.leaflet-container .leaflet-control-scale {
416− font-size: 11px;
416+ font-size: 11px;
417− }
417+ }
418−.leaflet-left .leaflet-control-scale {
418+.leaflet-left .leaflet-control-scale {
419− margin-left: 5px;
419+ margin-left: 5px;
420− }
420+ }
421−.leaflet-bottom .leaflet-control-scale {
421+.leaflet-bottom .leaflet-control-scale {
422− margin-bottom: 5px;
422+ margin-bottom: 5px;
423− }
423+ }
424−.leaflet-control-scale-line {
424+.leaflet-control-scale-line {
425− border: 2px solid #777;
425+ border: 2px solid #777;
426− border-top: none;
426+ border-top: none;
427− line-height: 1.1;
427+ line-height: 1.1;
428− padding: 2px 5px 1px;
428+ padding: 2px 5px 1px;
429− font-size: 11px;
429+ font-size: 11px;
430− white-space: nowrap;
430+ white-space: nowrap;
431− overflow: hidden;
431+ overflow: hidden;
432− -moz-box-sizing: border-box;
432+ -moz-box-sizing: border-box;
433− box-sizing: border-box;
433+ box-sizing: border-box;
434−
434+
435− background: #fff;
435+ background: #fff;
436− background: rgba(255, 255, 255, 0.5);
436+ background: rgba(255, 255, 255, 0.5);
437− }
437+ }
438−.leaflet-control-scale-line:not(:first-child) {
438+.leaflet-control-scale-line:not(:first-child) {
439− border-top: 2px solid #777;
439+ border-top: 2px solid #777;
440− border-bottom: none;
440+ border-bottom: none;
441− margin-top: -2px;
441+ margin-top: -2px;
442− }
442+ }
443−.leaflet-control-scale-line:not(:first-child):not(:last-child) {
443+.leaflet-control-scale-line:not(:first-child):not(:last-child) {
444− border-bottom: 2px solid #777;
444+ border-bottom: 2px solid #777;
445− }
445+ }
446−
446+
447−.leaflet-touch .leaflet-control-attribution,
447+.leaflet-touch .leaflet-control-attribution,
448−.leaflet-touch .leaflet-control-layers,
448+.leaflet-touch .leaflet-control-layers,
449−.leaflet-touch .leaflet-bar {
449+.leaflet-touch .leaflet-bar {
450− box-shadow: none;
450+ box-shadow: none;
451− }
451+ }
452−.leaflet-touch .leaflet-control-layers,
452+.leaflet-touch .leaflet-control-layers,
453−.leaflet-touch .leaflet-bar {
453+.leaflet-touch .leaflet-bar {
454− border: 2px solid rgba(0,0,0,0.2);
454+ border: 2px solid rgba(0,0,0,0.2);
455− background-clip: padding-box;
455+ background-clip: padding-box;
456− }
456+ }
457−
457+
458−
458+
459−/* popup */
459+/* popup */
460−
460+
461−.leaflet-popup {
461+.leaflet-popup {
462− position: absolute;
462+ position: absolute;
463− text-align: center;
463+ text-align: center;
464− margin-bottom: 20px;
464+ margin-bottom: 20px;
465− }
465+ }
466−.leaflet-popup-content-wrapper {
466+.leaflet-popup-content-wrapper {
467− padding: 1px;
467+ padding: 1px;
468− text-align: left;
468+ text-align: left;
469− border-radius: 12px;
469+ border-radius: 12px;
470− }
470+ }
471−.leaflet-popup-content {
471+.leaflet-popup-content {
472− margin: 13px 19px;
472+ margin: 13px 19px;
473− line-height: 1.4;
473+ line-height: 1.4;
474− }
474+ }
475−.leaflet-popup-content p {
475+.leaflet-popup-content p {
476− margin: 18px 0;
476+ margin: 18px 0;
477− }
477+ }
478−.leaflet-popup-tip-container {
478+.leaflet-popup-tip-container {
479− width: 40px;
479+ width: 40px;
480− height: 20px;
480+ height: 20px;
481− position: absolute;
481+ position: absolute;
482− left: 50%;
482+ left: 50%;
483− margin-left: -20px;
483+ margin-left: -20px;
484− overflow: hidden;
484+ overflow: hidden;
485− pointer-events: none;
485+ pointer-events: none;
486− }
486+ }
487−.leaflet-popup-tip {
487+.leaflet-popup-tip {
488− width: 17px;
488+ width: 17px;
489− height: 17px;
489+ height: 17px;
490− padding: 1px;
490+ padding: 1px;
491−
491+
492− margin: -10px auto 0;
492+ margin: -10px auto 0;
493−
493+
494− -webkit-transform: rotate(45deg);
494+ -webkit-transform: rotate(45deg);
495− -moz-transform: rotate(45deg);
495+ -moz-transform: rotate(45deg);
496− -ms-transform: rotate(45deg);
496+ -ms-transform: rotate(45deg);
497− -o-transform: rotate(45deg);
497+ -o-transform: rotate(45deg);
498− transform: rotate(45deg);
498+ transform: rotate(45deg);
499− }
499+ }
500−.leaflet-popup-content-wrapper,
500+.leaflet-popup-content-wrapper,
501−.leaflet-popup-tip {
501+.leaflet-popup-tip {
502− background: white;
502+ background: white;
503− color: #333;
503+ color: #333;
504− box-shadow: 0 3px 14px rgba(0,0,0,0.4);
504+ box-shadow: 0 3px 14px rgba(0,0,0,0.4);
505− }
505+ }
506−.leaflet-container a.leaflet-popup-close-button {
506+.leaflet-container a.leaflet-popup-close-button {
507− position: absolute;
507+ position: absolute;
508− top: 0;
508+ top: 0;
509− right: 0;
509+ right: 0;
510− padding: 4px 4px 0 0;
510+ padding: 4px 4px 0 0;
511− border: none;
511+ border: none;
512− text-align: center;
512+ text-align: center;
513− width: 18px;
513+ width: 18px;
514− height: 14px;
514+ height: 14px;
515− font: 16px/14px Tahoma, Verdana, sans-serif;
515+ font: 16px/14px Tahoma, Verdana, sans-serif;
516− color: #c3c3c3;
516+ color: #c3c3c3;
517− text-decoration: none;
517+ text-decoration: none;
518− font-weight: bold;
518+ font-weight: bold;
519− background: transparent;
519+ background: transparent;
520− }
520+ }
521−.leaflet-container a.leaflet-popup-close-button:hover {
521+.leaflet-container a.leaflet-popup-close-button:hover {
522− color: #999;
522+ color: #999;
523− }
523+ }
524−.leaflet-popup-scrolled {
524+.leaflet-popup-scrolled {
525− overflow: auto;
525+ overflow: auto;
526− border-bottom: 1px solid #ddd;
526+ border-bottom: 1px solid #ddd;
527− border-top: 1px solid #ddd;
527+ border-top: 1px solid #ddd;
528− }
528+ }
529−
529+
530−.leaflet-oldie .leaflet-popup-content-wrapper {
530+.leaflet-oldie .leaflet-popup-content-wrapper {
531− zoom: 1;
531+ zoom: 1;
532− }
532+ }
533−.leaflet-oldie .leaflet-popup-tip {
533+.leaflet-oldie .leaflet-popup-tip {
534− width: 24px;
534+ width: 24px;
535− margin: 0 auto;
535+ margin: 0 auto;
536−
536+
537− -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
537+ -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
538− filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
538+ filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
539− }
539+ }
540−.leaflet-oldie .leaflet-popup-tip-container {
540+.leaflet-oldie .leaflet-popup-tip-container {
541− margin-top: -1px;
541+ margin-top: -1px;
542− }
542+ }
543−
543+
544−.leaflet-oldie .leaflet-control-zoom,
544+.leaflet-oldie .leaflet-control-zoom,
545−.leaflet-oldie .leaflet-control-layers,
545+.leaflet-oldie .leaflet-control-layers,
546−.leaflet-oldie .leaflet-popup-content-wrapper,
546+.leaflet-oldie .leaflet-popup-content-wrapper,
547−.leaflet-oldie .leaflet-popup-tip {
547+.leaflet-oldie .leaflet-popup-tip {
548− border: 1px solid #999;
548+ border: 1px solid #999;
549− }
549+ }
550−
550+
551−
551+
552−/* div icon */
552+/* div icon */
553−
553+
554−.leaflet-div-icon {
554+.leaflet-div-icon {
555− background: #fff;
555+ background: #fff;
556− border: 1px solid #666;
556+ border: 1px solid #666;
557− }
557+ }
558−
558+
559−
559+
560−/* Tooltip */
560+/* Tooltip */
561−/* Base styles for the element that has a tooltip */
561+/* Base styles for the element that has a tooltip */
562−.leaflet-tooltip {
562+.leaflet-tooltip {
563− position: absolute;
563+ position: absolute;
564− padding: 6px;
564+ padding: 6px;
565− background-color: #fff;
565+ background-color: #fff;
566− border: 1px solid #fff;
566+ border: 1px solid #fff;
567− border-radius: 3px;
567+ border-radius: 3px;
568− color: #222;
568+ color: #222;
569− white-space: nowrap;
569+ white-space: nowrap;
570− -webkit-user-select: none;
570+ -webkit-user-select: none;
571− -moz-user-select: none;
571+ -moz-user-select: none;
572− -ms-user-select: none;
572+ -ms-user-select: none;
573− user-select: none;
573+ user-select: none;
574− pointer-events: none;
574+ pointer-events: none;
575− box-shadow: 0 1px 3px rgba(0,0,0,0.4);
575+ box-shadow: 0 1px 3px rgba(0,0,0,0.4);
576− }
576+ }
577−.leaflet-tooltip.leaflet-clickable {
577+.leaflet-tooltip.leaflet-clickable {
578− cursor: pointer;
578+ cursor: pointer;
579− pointer-events: auto;
579+ pointer-events: auto;
580− }
580+ }
581−.leaflet-tooltip-top:before,
581+.leaflet-tooltip-top:before,
582−.leaflet-tooltip-bottom:before,
582+.leaflet-tooltip-bottom:before,
583−.leaflet-tooltip-left:before,
583+.leaflet-tooltip-left:before,
584−.leaflet-tooltip-right:before {
584+.leaflet-tooltip-right:before {
585− position: absolute;
585+ position: absolute;
586− pointer-events: none;
586+ pointer-events: none;
587− border: 6px solid transparent;
587+ border: 6px solid transparent;
588− background: transparent;
588+ background: transparent;
589− content: "";
589+ content: "";
590− }
590+ }
591−
591+
592−/* Directions */
592+/* Directions */
593−
593+
594−.leaflet-tooltip-bottom {
594+.leaflet-tooltip-bottom {
595− margin-top: 6px;
595+ margin-top: 6px;
596−}
596+}
597−.leaflet-tooltip-top {
597+.leaflet-tooltip-top {
598− margin-top: -6px;
598+ margin-top: -6px;
599−}
599+}
600−.leaflet-tooltip-bottom:before,
600+.leaflet-tooltip-bottom:before,
601−.leaflet-tooltip-top:before {
601+.leaflet-tooltip-top:before {
602− left: 50%;
602+ left: 50%;
603− margin-left: -6px;
603+ margin-left: -6px;
604− }
604+ }
605−.leaflet-tooltip-top:before {
605+.leaflet-tooltip-top:before {
606− bottom: 0;
606+ bottom: 0;
607− margin-bottom: -12px;
607+ margin-bottom: -12px;
608− border-top-color: #fff;
608+ border-top-color: #fff;
609− }
609+ }
610−.leaflet-tooltip-bottom:before {
610+.leaflet-tooltip-bottom:before {
611− top: 0;
611+ top: 0;
612− margin-top: -12px;
612+ margin-top: -12px;
613− margin-left: -6px;
613+ margin-left: -6px;
614− border-bottom-color: #fff;
614+ border-bottom-color: #fff;
615− }
615+ }
616−.leaflet-tooltip-left {
616+.leaflet-tooltip-left {
617− margin-left: -6px;
617+ margin-left: -6px;
618−}
618+}
619−.leaflet-tooltip-right {
619+.leaflet-tooltip-right {
620− margin-left: 6px;
620+ margin-left: 6px;
621−}
621+}
622−.leaflet-tooltip-left:before,
622+.leaflet-tooltip-left:before,
623−.leaflet-tooltip-right:before {
623+.leaflet-tooltip-right:before {
624− top: 50%;
624+ top: 50%;
625− margin-top: -6px;
625+ margin-top: -6px;
626− }
626+ }
627−.leaflet-tooltip-left:before {
627+.leaflet-tooltip-left:before {
628− right: 0;
628+ right: 0;
629− margin-right: -12px;
629+ margin-right: -12px;
630− border-left-color: #fff;
630+ border-left-color: #fff;
631− }
631+ }
632−.leaflet-tooltip-right:before {
632+.leaflet-tooltip-right:before {
633− left: 0;
633+ left: 0;
634− margin-left: -12px;
634+ margin-left: -12px;
635− border-right-color: #fff;
635+ border-right-color: #fff;
636− }
636+ }
searx/templates/courgette/result_templates/key-value.htmlnew file+13
@@ -0,0 +1,13 @@
1+<div class="result">
2+<table>
3+ {% for key, value in result.items() %}
4+ {% if key in ['engine', 'engines', 'template', 'score', 'category', 'positions'] %}
5+ {% continue %}
6+ {% endif %}
7+ <tr>
8+ <td><b>{{ key|upper }}</b>: {{ value|safe }}</td>
9+ </tr>
10+ {% endfor %}
11+</table>
12+<p class="engines">{{ result.engines|join(', ') }}</p>
13+</div>
searx/templates/courgette/result_templates/torrent.html+1−1
@@ -4,7 +4,7 @@
4 {% endif %}
4 {% endif %}
5 <h3 class="result_title"><a href="{{ result.url }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ result.title|safe }}</a></h3>
5 <h3 class="result_title"><a href="{{ result.url }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ result.title|safe }}</a></h3>
6 {% if result.content %}<span class="content">{{ result.content|safe }}</span><br />{% endif %}
6 {% if result.content %}<span class="content">{{ result.content|safe }}</span><br />{% endif %}
7− {% if result.seed %}<span class="stats">{{ _('Seeder') }} : {{ result.seed }}, {{ _('Leecher') }} : {{ result.leech }}</span><br />{% endif %}
7+ {% if result.seed is defined %}<span class="stats">{{ _('Seeder') }} : {{ result.seed }}, {{ _('Leecher') }} : {{ result.leech }}</span><br />{% endif %}
8 <span>
8 <span>
9 {% if result.magnetlink %}<a href="{{ result.magnetlink }}" class="magnetlink">{{ _('magnet link') }}</a>{% endif %}
9 {% if result.magnetlink %}<a href="{{ result.magnetlink }}" class="magnetlink">{{ _('magnet link') }}</a>{% endif %}
10 {% if result.torrentfile %}<a href="{{ result.torrentfile }}" class="torrentfile" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ _('torrent file') }}</a>{% endif %}
10 {% if result.torrentfile %}<a href="{{ result.torrentfile }}" class="torrentfile" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ _('torrent file') }}</a>{% endif %}
searx/templates/legacy/result_templates/key-value.htmlnew file+13
@@ -0,0 +1,13 @@
1+<table class="result-table">
2+ {% for key, value in result.items() %}
3+ {% if key in ['engine', 'engines', 'template', 'score', 'category', 'positions'] %}
4+ {% continue %}
5+ {% endif %}
6+ <tr>
7+ <td><b>{{ key|upper }}</b>: {{ value|safe }}</td>
8+ </tr>
9+ {% endfor %}
10+ <tr>
11+ <td><b>ENGINES</b>: {{ result.engines|join(', ') }}</td>
12+ </tr>
13+</table>
searx/templates/legacy/result_templates/torrent.html+1−1
@@ -8,6 +8,6 @@
8 <p>
8 <p>
9 {% if result.magnetlink %}<a href="{{ result.magnetlink }}" class="magnetlink">{{ _('magnet link') }}</a>{% endif %}
9 {% if result.magnetlink %}<a href="{{ result.magnetlink }}" class="magnetlink">{{ _('magnet link') }}</a>{% endif %}
10 {% if result.torrentfile %}<a href="{{ result.torrentfile }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %} class="torrentfile">{{ _('torrent file') }}</a>{% endif %} -
10 {% if result.torrentfile %}<a href="{{ result.torrentfile }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %} class="torrentfile">{{ _('torrent file') }}</a>{% endif %} -
11− {% if result.seed %}<span class="stats">{{ _('Seeder') }} : {{ result.seed }}, {{ _('Leecher') }} : {{ result.leech }}</span>{% endif %}
11+ {% if result.seed is defined %}<span class="stats">{{ _('Seeder') }} : {{ result.seed }}, {{ _('Leecher') }} : {{ result.leech }}</span>{% endif %}
12 </p>
12 </p>
13</div>
13</div>
searx/templates/oscar/advanced.html+5−4
@@ -1,16 +1,17 @@
1<input type="checkbox" name="advanced_search" id="check-advanced" {% if advanced_search %} checked="checked"{% endif %}>
1<input type="checkbox" name="advanced_search" id="check-advanced" {% if advanced_search %} checked="checked"{% endif %}>
2−<label for="check-advanced">
2+<label for="check-advanced">{{- "" -}}
3 <span class="glyphicon glyphicon-cog"></span>
3 <span class="glyphicon glyphicon-cog"></span>
4− {{ _('Advanced settings') }}
4+ {{- _('Advanced settings') -}}
5</label>
5</label>
6<div id="advanced-search-container">
6<div id="advanced-search-container">
7 {% include 'oscar/categories.html' %}
7 {% include 'oscar/categories.html' %}
8+
8 <div class="row">
9 <div class="row">
9 <div class="col-xs-6">
10 <div class="col-xs-6">
10− {% include 'oscar/time-range.html' %}
11+ {%- include 'oscar/time-range.html' -%}
11 </div>
12 </div>
12 <div class="col-xs-6">
13 <div class="col-xs-6">
13− {% include 'oscar/languages.html' %}
14+ {%- include 'oscar/languages.html' -%}
14 </div>
15 </div>
15 </div>
16 </div>
16</div>
17</div>
searx/templates/oscar/base.html+15−16
@@ -10,16 +10,17 @@
10 <meta name="referrer" content="no-referrer">
10 <meta name="referrer" content="no-referrer">
11 <meta name="viewport" content="width=device-width, initial-scale=1 , maximum-scale=1.0, user-scalable=1" />
11 <meta name="viewport" content="width=device-width, initial-scale=1 , maximum-scale=1.0, user-scalable=1" />
12 {% block meta %}{% endblock %}
12 {% block meta %}{% endblock %}
13− <title>{% block title %}{% endblock %}{{ instance_name }}</title>
14
13
14+ <title>{% block title %}{% endblock %}{{ instance_name }}</title>
15 <link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}" type="text/css" />
15 <link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}" type="text/css" />
16− {% if preferences.get_value('oscar-style') %}
16+ {% if preferences.get_value('oscar-style') -%}
17− <link rel="stylesheet" href="{{ url_for('static', filename='css/'+preferences.get_value('oscar-style')+'.min.css') }}" type="text/css" />
17+ {{' '}}<link rel="stylesheet" href="{{ url_for('static', filename='css/'+preferences.get_value('oscar-style')+'.min.css') }}" type="text/css" />
18− {% else %}
18+ {%- else -%}
19− <link rel="stylesheet" href="{{ url_for('static', filename='css/logicodev.min.css') }}" type="text/css" />
19+ {{' '}}<link rel="stylesheet" href="{{ url_for('static', filename='css/logicodev.min.css') }}" type="text/css" />
20− {% endif %}
20+ {%- endif %}
21+
21 <link rel="stylesheet" href="{{ url_for('static', filename='css/leaflet.min.css') }}" type="text/css" />
22 <link rel="stylesheet" href="{{ url_for('static', filename='css/leaflet.min.css') }}" type="text/css" />
22− {% for css in styles %}
23+ {%- for css in styles %}
23 <link rel="stylesheet" href="{{ url_for('static', filename=css) }}" type="text/css" />
24 <link rel="stylesheet" href="{{ url_for('static', filename=css) }}" type="text/css" />
24 {% endfor %}
25 {% endfor %}
25
26
@@ -37,12 +38,6 @@
37 {% endblock %}
38 {% endblock %}
38
39
39 <link title="{{ instance_name }}" type="application/opensearchdescription+xml" rel="search" href="{{ url_for('opensearch') }}"/>
40 <link title="{{ instance_name }}" type="application/opensearchdescription+xml" rel="search" href="{{ url_for('opensearch') }}"/>
40−
41− <script type="text/javascript">
42− searx = {};
43− searx.method = "{{ method or 'POST' }}";
44− searx.autocompleter = {% if autocomplete %}true{% else %}false{% endif %};
45− </script>
46 <noscript>
41 <noscript>
47 <style type="text/css">
42 <style type="text/css">
48 .tab-content > .active_if_nojs, .active_if_nojs {display: block !important; visibility: visible !important;}
43 .tab-content > .active_if_nojs, .active_if_nojs {display: block !important; visibility: visible !important;}
@@ -54,6 +49,7 @@
54</head>
49</head>
55<body>
50<body>
56 {% include 'oscar/navbar.html' %}
51 {% include 'oscar/navbar.html' %}
52+
57 <div class="container">
53 <div class="container">
58 {% if errors %}
54 {% if errors %}
59 <div class="alert alert-danger fade in" role="alert">
55 <div class="alert alert-danger fade in" role="alert">
@@ -99,11 +95,14 @@
99 </div>
95 </div>
100 <script src="{{ url_for('static', filename='js/jquery-1.11.1.min.js') }}"></script>
96 <script src="{{ url_for('static', filename='js/jquery-1.11.1.min.js') }}"></script>
101 <script src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script>
97 <script src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script>
102− {% if autocomplete %}<script src="{{ url_for('static', filename='js/typeahead.bundle.min.js') }}"></script>{% endif %}
98+ {% if autocomplete %} <script src="{{ url_for('static', filename='js/typeahead.bundle.min.js') }}"></script>{% endif %}
99+
103 <script src="{{ url_for('static', filename='js/require-2.1.15.min.js') }}"></script>
100 <script src="{{ url_for('static', filename='js/require-2.1.15.min.js') }}"></script>
104− <script src="{{ url_for('static', filename='js/searx.min.js') }}"></script>
101+ <script src="{{ url_for('static', filename='js/searx.min.js') }}"
102+ data-method="{{ method or 'POST' }}"
103+ data-autocompleter="{% if autocomplete %}true{% else %}false{% endif %}"></script>
105 {% for script in scripts %}
104 {% for script in scripts %}
106− <script src="{{ url_for('static', filename=script) }}"></script>
105+ {{""}}<script src="{{ url_for('static', filename=script) }}"></script>
107 {% endfor %}
106 {% endfor %}
108 <noscript>
107 <noscript>
109 <style>
108 <style>
searx/templates/oscar/categories.html+9−9
@@ -1,13 +1,13 @@
1<div id="categories">
1<div id="categories">
2−{% if rtl %}
2+{%- if rtl -%}
3− {% for category in categories | reverse %}
3+ {% for category in categories | reverse -%}
4− <input class="hidden" type="checkbox" id="checkbox_{{ category|replace(' ', '_') }}" name="category_{{ category }}" {% if category in selected_categories %}checked="checked"{% endif %} />
4+ <input class="hidden" type="checkbox" id="checkbox_{{ category|replace(' ', '_') }}" name="category_{{ category }}" {% if category in selected_categories %}checked="checked"{% endif %} />{{- '' -}}
5 <label for="checkbox_{{ category|replace(' ', '_') }}">{{ _(category) }}</label>
5 <label for="checkbox_{{ category|replace(' ', '_') }}">{{ _(category) }}</label>
6− {% endfor %}
6+ {%- endfor %}
7−{% else %}
7+{%- else -%}
8− {% for category in categories %}
8+ {% for category in categories -%}
9− <input class="hidden" type="checkbox" id="checkbox_{{ category|replace(' ', '_') }}" name="category_{{ category }}" {% if category in selected_categories %}checked="checked"{% endif %} />
9+ <input class="hidden" type="checkbox" id="checkbox_{{ category|replace(' ', '_') }}" name="category_{{ category }}" {% if category in selected_categories %}checked="checked"{% endif %} />{{- '' -}}
10 <label for="checkbox_{{ category|replace(' ', '_') }}">{{ _(category) }}</label>
10 <label for="checkbox_{{ category|replace(' ', '_') }}">{{ _(category) }}</label>
11− {% endfor %}
11+ {%- endfor %}
12−{% endif %}
12+{%- endif -%}
13</div>
13</div>
searx/templates/oscar/infobox.html+17−16
@@ -1,34 +1,35 @@
1{% from 'oscar/macros.html' import result_link with context %}
1{% from 'oscar/macros.html' import result_link with context %}
2<div class="panel panel-default infobox">
2<div class="panel panel-default infobox">
3− <div class="panel-heading">
3+ <div class="panel-heading">{{- "" -}}
4− <h4 class="panel-title infobox_part"><bdi>{{ infobox.infobox }}</bdi></h4>
4+ <h4 class="panel-title infobox_part"><bdi>{{ infobox.infobox }}</bdi></h4>{{- "" -}}
5 </div>
5 </div>
6 <div class="panel-body">
6 <div class="panel-body">
7 {% if infobox.img_src %}<img class="img-responsive center-block infobox_part" src="{{ image_proxify(infobox.img_src) }}" alt="{{ infobox.infobox }}" />{% endif %}
7 {% if infobox.img_src %}<img class="img-responsive center-block infobox_part" src="{{ image_proxify(infobox.img_src) }}" alt="{{ infobox.infobox }}" />{% endif %}
8− {% if infobox.content %}<bdi><p class="infobox_part">{{ infobox.content }}</bdi></p>{% endif %}
9
8
9+ {% if infobox.content %}<bdi><p class="infobox_part">{{ infobox.content | safe }}</p></bdi>{% endif %}
10+
10− {% if infobox.attributes %}
11+ {% if infobox.attributes -%}
11 <table class="table table-striped infobox_part">
12 <table class="table table-striped infobox_part">
12− {% for attribute in infobox.attributes %}
13+ {% for attribute in infobox.attributes -%}
13− <tr>
14+ <tr>{{- "" -}}
14 <td><bdi>{{ attribute.label }}</bdi></td>
15 <td><bdi>{{ attribute.label }}</bdi></td>
15− {% if attribute.image %}
16+ {%- if attribute.image -%}
16 <td><img class="img-responsive" src="{{ image_proxify(attribute.image.src) }}" alt="{{ attribute.image.alt }}" /></td>
17 <td><img class="img-responsive" src="{{ image_proxify(attribute.image.src) }}" alt="{{ attribute.image.alt }}" /></td>
17− {% else %}
18+ {%- else -%}
18 <td><bdi>{{ attribute.value }}</bdi></td>
19 <td><bdi>{{ attribute.value }}</bdi></td>
19− {% endif %}
20+ {%- endif -%}
20 </tr>
21 </tr>
21− {% endfor %}
22+ {% endfor -%}
22 </table>
23 </table>
23 {% endif %}
24 {% endif %}
24
25
25− {% if infobox.urls %}
26+ {% if infobox.urls -%}
26− <div class="infobox_part">
27+ <div class="infobox_part">{{- "\n" -}}
27 <bdi>
28 <bdi>
28− {% for url in infobox.urls %}
29+ {%- for url in infobox.urls -%}
29− <p class="btn btn-default btn-xs">{{ result_link(url.url, url.title) }}</a></p>
30+ <p class="btn btn-default btn-xs">{{ result_link(url.url, url.title) }}</p>
30− {% endfor %}
31+ {% endfor -%}
31− </bdi>
32+ </bdi>{{- "" -}}
32 </div>
33 </div>
33 {% endif %}
34 {% endif %}
34 </div>
35 </div>
searx/templates/oscar/languages.html+7−11
@@ -1,12 +1,8 @@
1−{% if preferences %}
2−<select class="custom-select form-control" name='language'>
3−{% else %}
4−<select class="time_range custom-select form-control" id='language' name='language'>
1+<select class="language custom-select form-control" id="language" name="language" accesskey="l">
5−{% endif %}
6− <option value="all" {% if current_language == 'all' %}selected="selected"{% endif %}>{{ _('Default language') }}</option>
2+ <option value="all" {% if current_language == 'all' %}selected="selected"{% endif %}>{{ _('Default language') }}</option>
7− {% for lang_id,lang_name,country_name,english_name in language_codes | sort(attribute=1) %}
3+{%- for lang_id,lang_name,country_name,english_name in language_codes | sort(attribute=1) -%}
8− <option value="{{ lang_id }}" {% if lang_id == current_language %}selected="selected"{% endif %}>
4+ <option value="{{ lang_id }}" {% if lang_id == current_language %}selected="selected"{% endif %}>
9− {{ lang_name }} {% if country_name %}({{ country_name }}) {% endif %}- {{ lang_id }}
5+ {{- lang_name }} {% if country_name %}({{ country_name }}) {% endif %}- {{ lang_id -}}
10− </option>
6+ </option>
11− {% endfor %}
7+{%- endfor -%}
12</select>
8</select>
searx/templates/oscar/macros.html+24−16
@@ -14,7 +14,7 @@
14
14
15<!-- Draw result header -->
15<!-- Draw result header -->
16{% macro result_header(result, favicons) -%}
16{% macro result_header(result, favicons) -%}
17−<h4 class="result_header">{% if result.engine~".png" in favicons %}{{ draw_favicon(result.engine) }} {% endif %}{{ result_link(result.url, result.title|safe) }}</h4>
17+<h4 class="result_header">{% if result.engine~".png" in favicons %}{{ draw_favicon(result.engine) }} {% endif %}{% if result.url %}{{ result_link(result.url, result.title|safe) }}{% else %}{{ result.title|safe}}{% endif %}</h4>
18{%- endmacro %}
18{%- endmacro %}
19
19
20<!-- Draw result sub header -->
20<!-- Draw result sub header -->
@@ -26,30 +26,38 @@
26
26
27<!-- Draw result footer -->
27<!-- Draw result footer -->
28{% macro result_footer(result) -%}
28{% macro result_footer(result) -%}
29− <div class="clearfix"></div>
29+ <div class="clearfix"></div>{{- "" -}}
30 <div class="pull-right">
30 <div class="pull-right">
31− {% for engine in result.engines %}
31+ {%- for engine in result.engines -%}
32− <span class="label label-default">{{ engine }}</span>
32+ <span class="label label-default">{{ engine }}</span>
33− {% endfor %}
33+ {%- endfor -%}
34+ {%- if result.url -%}
34− <small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
35+ <small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
36+ {%- endif -%}
35− {% if proxify %}
37+ {%- if proxify -%}
36− <small>{{ result_link(proxify(result.url), icon('sort') + _('proxied'), "text-info") }}</small>
38+ <small>{{ result_link(proxify(result.url), icon('sort') + _('proxied'), "text-info") }}</small>
37− {% endif %}
39+ {%- endif -%}
38−</div>
40+ </div>
41+ {%- if result.pretty_url -%}
39−<div class="external-link">{{ result.pretty_url }}</div>
42+ <div class="external-link">{{ result.pretty_url }}</div>
43+ {%- endif -%}
40{%- endmacro %}
44{%- endmacro %}
41
45
42<!-- Draw result footer -->
46<!-- Draw result footer -->
43{% macro result_footer_rtl(result) -%}
47{% macro result_footer_rtl(result) -%}
44− <div class="clearfix"></div>
48+ <div class="clearfix"></div>{{- "" -}}
45− {% for engine in result.engines %}
49+ {% for engine in result.engines -%}
46 <span class="label label-default">{{ engine }}</span>
50 <span class="label label-default">{{ engine }}</span>
47− {% endfor %}
51+ {%- endfor %}
52+ {%- if result.url -%}
48 <small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
53 <small>{{ result_link("https://web.archive.org/web/" + result.url, icon('link') + _('cached'), "text-info") }}</small>
54+ {%- endif -%}
49− {% if proxify %}
55+ {% if proxify -%}
50 <small>{{ result_link(proxify(result.url), icon('sort') + _('proxied'), "text-info") }}</small>
56 <small>{{ result_link(proxify(result.url), icon('sort') + _('proxied'), "text-info") }}</small>
51− {% endif %}
57+ {%- endif %}
58+ {%- if result.pretty_url -%}
52 <div class="external-link">{{ result.pretty_url }}</div>
59 <div class="external-link">{{ result.pretty_url }}</div>
60+ {%- endif %}
53{%- endmacro %}
61{%- endmacro %}
54
62
55{% macro preferences_item_header(info, label, rtl) -%}
63{% macro preferences_item_header(info, label, rtl) -%}
searx/templates/oscar/navbar.html+8−8
@@ -1,9 +1,9 @@
1−<div class="searx-navbar">
1+<div class="searx-navbar">{{- "" -}}
2− <span class="instance {% if rtl %}pull-right{% else %}pull-left{% endif%}">
2+ <span class="instance {% if rtl %}pull-right{% else %}pull-left{% endif%}">{{- "" -}}
3− <a href="{{ url_for('index') }}">{{ instance_name }}</a>
3+ <a href="{{ url_for('index') }}">{{ instance_name }}</a>{{- "" -}}
4− </span>
4+ </span>{{- "" -}}
5− <span class="{% if rtl %}pull-left{% else %}pull-right{% endif %}">
5+ <span class="{% if rtl %}pull-left{% else %}pull-right{% endif %}">{{- "" -}}
6− <a href="{{ url_for('about') }}">{{ _('about') }}</a>
6+ <a href="{{ url_for('about') }}">{{ _('about') }}</a>{{- "" -}}
7− <a href="{{ url_for('preferences') }}">{{ _('preferences') }}</a>
7+ <a href="{{ url_for('preferences') }}">{{ _('preferences') }}</a>{{- "" -}}
8− </span>
8+ </span>{{- "" -}}
9</div>
9</div>
searx/templates/oscar/preferences.html+33−33
@@ -41,7 +41,7 @@
41 {% set language_label = _('Search language') %}
41 {% set language_label = _('Search language') %}
42 {% set language_info = _('What language do you prefer for search?') %}
42 {% set language_info = _('What language do you prefer for search?') %}
43 {{ preferences_item_header(language_info, language_label, rtl) }}
43 {{ preferences_item_header(language_info, language_label, rtl) }}
44− {% include 'oscar/languages.html' %}
44+ {% include 'oscar/languages.html' %}
45 {{ preferences_item_footer(language_info, language_label, rtl) }}
45 {{ preferences_item_footer(language_info, language_label, rtl) }}
46
46
47 {% set locale_label = _('Interface language') %}
47 {% set locale_label = _('Interface language') %}
@@ -156,26 +156,26 @@
156 <div class="container-fluid">
156 <div class="container-fluid">
157 <fieldset>
157 <fieldset>
158 <div class="table-responsive">
158 <div class="table-responsive">
159− <table class="table table-hover table-condensed table-striped">
159+ <table class="table table-hover table-condensed table-striped">
160− <tr>
160+ <tr>
161 {% if not rtl %}
161 {% if not rtl %}
162− <th>{{ _("Allow") }}</th>
162+ <th>{{ _("Allow") }}</th>
163− <th>{{ _("Engine name") }}</th>
163+ <th>{{ _("Engine name") }}</th>
164− <th>{{ _("Shortcut") }}</th>
164+ <th>{{ _("Shortcut") }}</th>
165− <th>{{ _("Selected language") }}</th>
165+ <th>{{ _("Selected language") }}</th>
166− <th>{{ _("SafeSearch") }}</th>
166+ <th>{{ _("SafeSearch") }}</th>
167− <th>{{ _("Time range") }}</th>
167+ <th>{{ _("Time range") }}</th>
168− <th>{{ _("Avg. time") }}</th>
168+ <th>{{ _("Avg. time") }}</th>
169− <th>{{ _("Max time") }}</th>
169+ <th>{{ _("Max time") }}</th>
170 {% else %}
170 {% else %}
171− <th>{{ _("Max time") }}</th>
171+ <th>{{ _("Max time") }}</th>
172− <th>{{ _("Avg. time") }}</th>
172+ <th>{{ _("Avg. time") }}</th>
173− <th>{{ _("Time range") }}</th>
173+ <th>{{ _("Time range") }}</th>
174− <th>{{ _("SafeSearch") }}</th>
174+ <th>{{ _("SafeSearch") }}</th>
175− <th>{{ _("Selected language") }}</th>
175+ <th>{{ _("Selected language") }}</th>
176− <th>{{ _("Shortcut") }}</th>
176+ <th>{{ _("Shortcut") }}</th>
177− <th>{{ _("Engine name") }}</th>
177+ <th>{{ _("Engine name") }}</th>
178− <th>{{ _("Allow") }}</th>
178+ <th>{{ _("Allow") }}</th>
179 {% endif %}
179 {% endif %}
180 </tr>
180 </tr>
181 {% for search_engine in engines_by_category[categ] %}
181 {% for search_engine in engines_by_category[categ] %}
@@ -186,19 +186,19 @@
186 {{ checkbox_toggle('engine_' + search_engine.name|replace(' ', '_') + '__' + categ|replace(' ', '_'), (search_engine.name, categ) in disabled_engines) }}
186 {{ checkbox_toggle('engine_' + search_engine.name|replace(' ', '_') + '__' + categ|replace(' ', '_'), (search_engine.name, categ) in disabled_engines) }}
187 </td>
187 </td>
188 <th>{{ search_engine.name }}</th>
188 <th>{{ search_engine.name }}</th>
189− <td class="name">{{ shortcuts[search_engine.name] }}</td>
189+ <td class="name">{{ shortcuts[search_engine.name] }}</td>
190− <td>{{ support_toggle(stats[search_engine.name].supports_selected_language) }}</td>
190+ <td>{{ support_toggle(stats[search_engine.name].supports_selected_language) }}</td>
191− <td>{{ support_toggle(search_engine.safesearch==True) }}</td>
191+ <td>{{ support_toggle(search_engine.safesearch==True) }}</td>
192− <td>{{ support_toggle(search_engine.time_range_support==True) }}</td>
192+ <td>{{ support_toggle(search_engine.time_range_support==True) }}</td>
193− <td class="{{ 'danger' if stats[search_engine.name]['warn_time'] else '' }}">{{ 'N/A' if stats[search_engine.name].time==None else stats[search_engine.name].time }}</td>
193+ <td class="{{ 'danger' if stats[search_engine.name]['warn_time'] else '' }}">{{ 'N/A' if stats[search_engine.name].time==None else stats[search_engine.name].time }}</td>
194− <td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{{ search_engine.timeout }}</td>
194+ <td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{{ search_engine.timeout }}</td>
195− {% else %}
195+ {% else %}
196− <td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{{ search_engine.timeout }}</td>
196+ <td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{{ search_engine.timeout }}</td>
197− <td class="{{ 'danger' if stats[search_engine.name]['warn_time'] else '' }}">{{ 'N/A' if stats[search_engine.name].time==None else stats[search_engine.name].time }}</td>
197+ <td class="{{ 'danger' if stats[search_engine.name]['warn_time'] else '' }}">{{ 'N/A' if stats[search_engine.name].time==None else stats[search_engine.name].time }}</td>
198− <td>{{ support_toggle(search_engine.time_range_support==True) }}</td>
198+ <td>{{ support_toggle(search_engine.time_range_support==True) }}</td>
199− <td>{{ support_toggle(search_engine.safesearch==True) }}</td>
199+ <td>{{ support_toggle(search_engine.safesearch==True) }}</td>
200− <td>{{ support_toggle(stats[search_engine.name].supports_selected_language) }}</td>
200+ <td>{{ support_toggle(stats[search_engine.name].supports_selected_language) }}</td>
201− <td>{{ shortcuts[search_engine.name] }}</td>
201+ <td>{{ shortcuts[search_engine.name] }}</td>
202 <th>{{ search_engine.name }}</th>
202 <th>{{ search_engine.name }}</th>
203 <td class="onoff-checkbox">
203 <td class="onoff-checkbox">
204 {{ checkbox_toggle('engine_' + search_engine.name|replace(' ', '_') + '__' + categ|replace(' ', '_'), (search_engine.name, categ) in disabled_engines) }}
204 {{ checkbox_toggle('engine_' + search_engine.name|replace(' ', '_') + '__' + categ|replace(' ', '_'), (search_engine.name, categ) in disabled_engines) }}
@@ -207,7 +207,7 @@
207 </tr>
207 </tr>
208 {% endif %}
208 {% endif %}
209 {% endfor %}
209 {% endfor %}
210− </table>
210+ </table>
211 </div>
211 </div>
212 </fieldset>
212 </fieldset>
213 </div>
213 </div>
searx/templates/oscar/result_templates/code.html+18−18
@@ -1,18 +1,18 @@
1−{% from 'oscar/macros.html' import result_header, result_sub_header, result_footer, result_footer_rtl, icon %}
1+{% from 'oscar/macros.html' import result_header, result_sub_header, result_footer, result_footer_rtl, icon %}
2−
2+
3−{{ result_header(result, favicons) }}
3+{{ result_header(result, favicons) }}
4−{{ result_sub_header(result) }}
4+{{ result_sub_header(result) }}
5−
5+
6−{% if result.content %}<p class="result-content">{{ result.content|safe }}</p>{% endif %}
6+{% if result.content %}<p class="result-content">{{ result.content|safe }}</p>{% endif %}
7−
7+
8−{% if result.repository %}<p class="result-content">{{ icon('file') }} <a href="{{ result.repository }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ result.repository }}</a></p>{% endif %}
8+{% if result.repository %}<p class="result-content">{{ icon('file') }} <a href="{{ result.repository }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}>{{ result.repository }}</a></p>{% endif %}
9−
9+
10−<div dir="ltr">
10+<div dir="ltr">
11−{{ result.codelines|code_highlighter(result.code_language)|safe }}
11+{{ result.codelines|code_highlighter(result.code_language)|safe }}
12−</div>
12+</div>
13−
13+
14−{% if rtl %}
14+{% if rtl %}
15−{{ result_footer_rtl(result) }}
15+{{ result_footer_rtl(result) }}
16−{% else %}
16+{% else %}
17−{{ result_footer(result) }}
17+{{ result_footer(result) }}
18−{% endif %}
18+{% endif %}
searx/templates/oscar/result_templates/default.html+31−31
@@ -1,31 +1,31 @@
1−{% from 'oscar/macros.html' import result_header, result_sub_header, result_footer, result_footer_rtl, icon with context %}
1+{% from 'oscar/macros.html' import result_header, result_sub_header, result_footer, result_footer_rtl, icon with context %}
2−
2+
3−{{ result_header(result, favicons) }}
3+{{- result_header(result, favicons) -}}
4−{{ result_sub_header(result) }}
4+{{- result_sub_header(result) -}}
5−
5+
6−{% if result.embedded %}
6+{%- if result.embedded -%}
7− <small> &bull; <a class="text-info btn-collapse collapsed cursor-pointer media-loader disabled_if_nojs" data-toggle="collapse" data-target="#result-media-{{ index }}" data-btn-text-collapsed="{{ _('show media') }}" data-btn-text-not-collapsed="{{ _('hide media') }}">{{ icon('music') }} {{ _('show media') }}</a></small>
7+ <small> &bull; <a class="text-info btn-collapse collapsed cursor-pointer media-loader disabled_if_nojs" data-toggle="collapse" data-target="#result-media-{{ index }}" data-btn-text-collapsed="{{ _('show media') }}" data-btn-text-not-collapsed="{{ _('hide media') }}">{{ icon('music') }} {{ _('show media') }}</a></small>
8−{% endif %}
8+{%- endif -%}
9−
9+
10−{% if result.embedded %}
10+{%- if result.embedded -%}
11−<div id="result-media-{{ index }}" class="collapse">
11+<div id="result-media-{{ index }}" class="collapse">
12− {{ result.embedded|safe }}
12+ {{ result.embedded|safe }}
13−</div>
13+</div>
14−{% endif %}
14+{%- endif -%}
15−
15+
16−{% if result.img_src %}
16+{%- if result.img_src -%}
17−<div class="container-fluid">
17+<div class="container-fluid">
18− <div class="row">
18+ <div class="row">
19−<img src="{{ image_proxify(result.img_src) }}" alt="{{ result.title|striptags }}" title="{{ result.title|striptags }}" style="width: auto; max-height: 60px; min-height: 60px;" class="col-xs-2 col-sm-4 col-md-4 result-content">
19+<img src="{{ image_proxify(result.img_src) }}" alt="{{ result.title|striptags }}" title="{{ result.title|striptags }}" style="width: auto; max-height: 60px; min-height: 60px;" class="col-xs-2 col-sm-4 col-md-4 result-content">
20−{% if result.content %}<p class="result-content col-xs-8 col-sm-8 col-md-8">{{ result.content|safe }}</p>{% endif %}
20+{% if result.content %}<p class="result-content col-xs-8 col-sm-8 col-md-8">{{ result.content|safe }}</p>{% endif -%}
21− </div>
21+ </div>
22−</div>
22+</div>
23−{% else %}
23+{%- else -%}
24−{% if result.content %}<p class="result-content">{{ result.content|safe }}</p>{% endif %}
24+{%- if result.content %}<p class="result-content">{{ result.content|safe }}</p>{% endif -%}
25−{% endif %}
25+{%- endif -%}
26−
26+
27−{% if rtl %}
27+{%- if rtl -%}
28−{{ result_footer_rtl(result) }}
28+{{ result_footer_rtl(result) }}
29−{% else %}
29+{%- else -%}
30−{{ result_footer(result) }}
30+{{ result_footer(result) }}
31−{% endif %}
31+{%- endif -%}
searx/templates/oscar/result_templates/images.html+36−39
@@ -1,39 +1,36 @@
1−{% from 'oscar/macros.html' import draw_favicon %}
1+{%- from 'oscar/macros.html' import draw_favicon -%}
2−
2+
3−<a href="{{ result.img_src }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %} data-toggle="modal" data-target="#modal-{{ index }}-{{pageno}}">
3+<a href="{{ result.img_src }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %} data-toggle="modal" data-target="#modal-{{ index }}-{{pageno}}">{{- "" -}}
4− <img src="{% if result.thumbnail_src %}{{ image_proxify(result.thumbnail_src) }}{% else %}{{ image_proxify(result.img_src) }}{% endif %}" alt="{{ result.title|striptags }}" title="{{ result.title|striptags }}" class="img-thumbnail">
4+ <img src="{% if result.thumbnail_src %}{{ image_proxify(result.thumbnail_src) }}{% else %}{{ image_proxify(result.img_src) }}{% endif %}" alt="{{ result.title|striptags }}" title="{{ result.title|striptags }}" class="img-thumbnail">{{- "" -}}
5−</a>
5+</a>
6−
7−<div class="modal fade" id="modal-{{ index }}-{{ pageno }}" tabindex="-1" role="dialog" aria-hidden="true">
6+<div class="modal fade" id="modal-{{ index }}-{{ pageno }}" tabindex="-1" role="dialog" aria-hidden="true">{{- "" -}}
8− <div class="modal-dialog">
7+ <div class="modal-dialog">{{- "" -}}
9− <div class="modal-wrapper">
8+ <div class="modal-wrapper">{{- "" -}}
10− <div class="modal-header">
9+ <div class="modal-header">{{- "" -}}
11− <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
10+ <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>{{- "" -}}
12− <h4 class="modal-title">{% if result.engine~".png" in favicons %}{{ draw_favicon(result.engine) }} {% endif %}{{ result.title|striptags }}</h4>
11+ <h4 class="modal-title">{% if result.engine~".png" in favicons %}{{ draw_favicon(result.engine) }} {% endif %}{{ result.title|striptags }}</h4>{{- "" -}}
13− </div>
12+ </div>{{- "" -}}
14− <div class="modal-body">
13+ <div class="modal-body">{{- "" -}}
15− <img class="img-responsive center-block" src="{% if result.thumbnail_src %}{{ image_proxify(result.thumbnail_src) }}{% else %}{{ image_proxify(result.img_src) }}{% endif %}" alt="{{ result.title|striptags }}">
14+ <img class="img-responsive center-block" src="{% if result.thumbnail_src %}{{ image_proxify(result.thumbnail_src) }}{% else %}{{ image_proxify(result.img_src) }}{% endif %}" alt="{{ result.title|striptags }}">
16− {% if result.author %}<span class="photo-author">{{ result.author }}</span><br />{% endif %}
15+ {%- if result.author %}<span class="photo-author">{{ result.author }}</span><br />{% endif -%}
17− {% if result.content %}
18− <p class="result-content">
16+ {%- if result.content %}<p class="result-content">{{ result.content|striptags }}</p>{% endif -%}
19− {{ result.content }}
17+ {%- if result.img_format %}<p class="result-format">{{ result.img_format }}</p>{% endif -%}
20− </p>
18+ {%- if result.source %}<p class="result-source">{{ result.source }}</p>{% endif -%}
21− {% endif %}
22− </div>
19+ </div>{{- "" -}}
23− <div class="modal-footer">
20+ <div class="modal-footer">{{- "" -}}
24− <div class="clearfix"></div>
21+ <div class="clearfix"></div>{{- "" -}}
25− <span class="label label-default pull-right">{{ result.engine }}</span>
22+ <span class="label label-default pull-right">{{ result.engine }}</span>{{- "" -}}
26− <p class="text-muted pull-left">{{ result.pretty_url }}</p>
23+ <p class="text-muted pull-left">{{ result.pretty_url }}</p>{{- "" -}}
27− <div class="clearfix"></div>
24+ <div class="clearfix"></div>{{- "" -}}
28− <div class="row">
25+ <div class="row">{{- "" -}}
29− <div class="col-md-6">
26+ <div class="col-md-6">{{- "" -}}
30− <a href="{{ result.img_src }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %} class="btn btn-default">{{ _('Get image') }}</a>
27+ <a href="{{ result.img_src }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %} class="btn btn-default">{{ _('Get image') }}</a>{{- "" -}}
31− </div>
28+ </div>{{- "" -}}
32− <div class="col-md-6">
29+ <div class="col-md-6">{{- "" -}}
33− <a href="{{ result.url }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %} class="btn btn-default">{{ _('View source') }}</a>
30+ <a href="{{ result.url }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %} class="btn btn-default">{{ _('View source') }}</a>{{- "" -}}
34− </div>
31+ </div>{{- "" -}}
35− </div>
32+ </div>{{- "" -}}
36− </div>
33+ </div>{{- "" -}}
37− </div>
34+ </div>{{- "" -}}
38− </div>
35+ </div>{{- "" -}}
39−</div>
36+</div>{{- "" -}}
searx/templates/oscar/result_templates/key-value.htmlnew file+19
@@ -0,0 +1,19 @@
1+{% from 'oscar/macros.html' import result_footer, result_footer_rtl with context %}
2+<div class="panel panel-default">
3+<table class="table table-responsive table-bordered table-condensed">
4+ {% for key, value in result.items() %}
5+ {% if key in ['engine', 'engines', 'template', 'score', 'category', 'positions'] %}
6+ {% continue %}
7+ {% endif %}
8+ <tr>
9+ <td><b>{{ key|upper }}</b>: {{ value }}</td>
10+ </tr>
11+ {% endfor %}
12+</table>
13+
14+{% if rtl %}
15+{{ result_footer_rtl(result) }}
16+{% else %}
17+{{ result_footer(result) }}
18+{% endif %}
19+</div>
searx/templates/oscar/result_templates/map.html+72−72
@@ -1,72 +1,72 @@
1−{% from 'oscar/macros.html' import result_header, result_sub_header, result_footer, result_footer_rtl, icon %}
1+{% from 'oscar/macros.html' import result_header, result_sub_header, result_footer, result_footer_rtl, icon %}
2−
2+
3−{{ result_header(result, favicons) }}
3+{{ result_header(result, favicons) }}
4−{{ result_sub_header(result) }}
4+{{ result_sub_header(result) }}
5−
5+
6−{% if (result.latitude and result.longitude) or result.boundingbox %}
6+{% if (result.latitude and result.longitude) or result.boundingbox %}
7− <small> &bull; <a class="text-info btn-collapse collapsed searx_init_map cursor-pointer disabled_if_nojs" data-toggle="collapse" data-target="#result-map-{{ index }}" data-leaflet-target="osm-map-{{ index }}" data-map-lon="{{ result.longitude }}" data-map-lat="{{ result.latitude }}" {% if result.boundingbox %}data-map-boundingbox='{{ result.boundingbox|tojson|safe }}'{% endif %} {% if result.geojson %}data-map-geojson='{{ result.geojson|tojson|safe }}'{% endif %} data-btn-text-collapsed="{{ _('show map') }}" data-btn-text-not-collapsed="{{ _('hide map') }}">{{ icon('globe') }} {{ _('show map') }}</a></small>
7+ <small> &bull; <a class="text-info btn-collapse collapsed searx_init_map cursor-pointer disabled_if_nojs" data-toggle="collapse" data-target="#result-map-{{ index }}" data-leaflet-target="osm-map-{{ index }}" data-map-lon="{{ result.longitude }}" data-map-lat="{{ result.latitude }}" {% if result.boundingbox %}data-map-boundingbox='{{ result.boundingbox|tojson|safe }}'{% endif %} {% if result.geojson %}data-map-geojson='{{ result.geojson|tojson|safe }}'{% endif %} data-btn-text-collapsed="{{ _('show map') }}" data-btn-text-not-collapsed="{{ _('hide map') }}">{{ icon('globe') }} {{ _('show map') }}</a></small>
8−{% endif %}
8+{% endif %}
9−
9+
10−{% if result.osm and (result.osm.type and result.osm.id) %}
10+{% if result.osm and (result.osm.type and result.osm.id) %}
11− <small> &bull; <a class="text-info btn-collapse collapsed cursor-pointer searx_overpass_request disabled_if_nojs" data-toggle="collapse" data-target="#result-overpass-{{ index }}" data-osm-type="{{ result.osm.type }}" data-osm-id="{{ result.osm.id }}" data-result-table="result-overpass-table-{{ index }}" data-result-table-loadicon="result-overpass-table-loading-{{ index }}" data-btn-text-collapsed="{{ _('show details') }}" data-btn-text-not-collapsed="{{ _('hide details') }}">{{ icon('map-marker') }} {{ _('show details') }}</a></small>
11+ <small> &bull; <a class="text-info btn-collapse collapsed cursor-pointer searx_overpass_request disabled_if_nojs" data-toggle="collapse" data-target="#result-overpass-{{ index }}" data-osm-type="{{ result.osm.type }}" data-osm-id="{{ result.osm.id }}" data-result-table="result-overpass-table-{{ index }}" data-result-table-loadicon="result-overpass-table-loading-{{ index }}" data-btn-text-collapsed="{{ _('show details') }}" data-btn-text-not-collapsed="{{ _('hide details') }}">{{ icon('map-marker') }} {{ _('show details') }}</a></small>
12−{% endif %}
12+{% endif %}
13−
13+
14−{# {% if (result.latitude and result.longitude) %}
14+{# {% if (result.latitude and result.longitude) %}
15− <small> &bull; <a class="text-info btn-collapse collapsed cursor-pointer disabled_if_nojs" data-toggle="collapse" data-target="#result-geodata-{{ index }}" data-btn-text-collapsed="{{ _('show geodata') }}" data-btn-text-not-collapsed="{{ _('hide geodata') }}">{{ icon('map-marker') }} {{ _('show geodata') }}</a></small>
15+ <small> &bull; <a class="text-info btn-collapse collapsed cursor-pointer disabled_if_nojs" data-toggle="collapse" data-target="#result-geodata-{{ index }}" data-btn-text-collapsed="{{ _('show geodata') }}" data-btn-text-not-collapsed="{{ _('hide geodata') }}">{{ icon('map-marker') }} {{ _('show geodata') }}</a></small>
16−{% endif %} #}
16+{% endif %} #}
17−
17+
18−<div class="container-fluid">
18+<div class="container-fluid">
19−
19+
20−{% if result.address %}
20+{% if result.address %}
21−<p class="row result-content result-adress col-xs-12 col-sm-5 col-md-4" itemscope itemtype="http://schema.org/PostalAddress">
21+<p class="row result-content result-adress col-xs-12 col-sm-5 col-md-4" itemscope itemtype="http://schema.org/PostalAddress">
22− {% if result.address.name %}
22+ {% if result.address.name %}
23− <strong itemprop="name">{{ result.address.name }}</strong><br/>
23+ <strong itemprop="name">{{ result.address.name }}</strong><br/>
24− {% endif %}
24+ {% endif %}
25− {% if result.address.road %}
25+ {% if result.address.road %}
26− <span itemprop="streetAddress">
26+ <span itemprop="streetAddress">
27− {% if result.address.house_number %}{{ result.address.house_number }}, {% endif %}
27+ {% if result.address.house_number %}{{ result.address.house_number }}, {% endif %}
28− {{ result.address.road }}
28+ {{ result.address.road }}
29− </span><br/>
29+ </span><br/>
30− {% endif %}
30+ {% endif %}
31− {% if result.address.locality %}
31+ {% if result.address.locality %}
32− <span itemprop="addressLocality">{{ result.address.locality }}</span>
32+ <span itemprop="addressLocality">{{ result.address.locality }}</span>
33− {% if result.address.postcode %}, <span itemprop="postalCode">{{ result.address.postcode }}</span>{% endif %}
33+ {% if result.address.postcode %}, <span itemprop="postalCode">{{ result.address.postcode }}</span>{% endif %}
34− <br/>
34+ <br/>
35− {% endif %}
35+ {% endif %}
36− {% if result.address.country %}
36+ {% if result.address.country %}
37− <span itemprop="addressCountry">{{ result.address.country }}</span>
37+ <span itemprop="addressCountry">{{ result.address.country }}</span>
38− {% endif %}
38+ {% endif %}
39−</p>
39+</p>
40−{% endif %}
40+{% endif %}
41−
41+
42−{% if result.osm and (result.osm.type and result.osm.id) %}
42+{% if result.osm and (result.osm.type and result.osm.id) %}
43− <div class="row result-content collapse col-xs-12 col-sm-7 col-md-8" id="result-overpass-{{ index }}"{% if rtl %} dir="ltr"{% endif %}>
43+ <div class="row result-content collapse col-xs-12 col-sm-7 col-md-8" id="result-overpass-{{ index }}"{% if rtl %} dir="ltr"{% endif %}>
44− <div class="text-center" id="result-overpass-table-loading-{{ index }}"><img src="{{ url_for('static', filename='img/loader.gif') }}" alt="Loading ..."/></div>
44+ <div class="text-center" id="result-overpass-table-loading-{{ index }}"><img src="{{ url_for('static', filename='img/loader.gif') }}" alt="Loading ..."/></div>
45− <table class="table table-striped table-condensed hidden" id="result-overpass-table-{{ index }}">
45+ <table class="table table-striped table-condensed hidden" id="result-overpass-table-{{ index }}">
46− <tr><th>key</th><th>value</th></tr>
46+ <tr><th>key</th><th>value</th></tr>
47− </table>
47+ </table>
48− </div>
48+ </div>
49−{% endif %}
49+{% endif %}
50−
50+
51−{# {% if (result.latitude and result.longitude) %}
51+{# {% if (result.latitude and result.longitude) %}
52− <div class="row collapse col-xs-12 col-sm-5 col-md-4" id="result-geodata-{{ index }}">
52+ <div class="row collapse col-xs-12 col-sm-5 col-md-4" id="result-geodata-{{ index }}">
53− <strong>Longitude:</strong> {{ result.longitude }} <br/>
53+ <strong>Longitude:</strong> {{ result.longitude }} <br/>
54− <strong>Latitude:</strong> {{ result.latitude }}
54+ <strong>Latitude:</strong> {{ result.latitude }}
55− </div>
55+ </div>
56−{% endif %} #}
56+{% endif %} #}
57−
57+
58−{% if result.content %}<p class="row result-content col-xs-12 col-sm-12 col-md-12">{{ result.content|safe }}</p>{% endif %}
58+{% if result.content %}<p class="row result-content col-xs-12 col-sm-12 col-md-12">{{ result.content|safe }}</p>{% endif %}
59−
59+
60−</div>
60+</div>
61−
61+
62−{% if (result.latitude and result.longitude) or result.boundingbox %}
62+{% if (result.latitude and result.longitude) or result.boundingbox %}
63− <div class="collapse" id="result-map-{{ index }}">
63+ <div class="collapse" id="result-map-{{ index }}">
64− <div style="height:300px; width:100%; margin: 10px 0;" id="osm-map-{{ index }}"></div>
64+ <div style="height:300px; width:100%; margin: 10px 0;" id="osm-map-{{ index }}"></div>
65− </div>
65+ </div>
66−{% endif %}
66+{% endif %}
67−
67+
68−{% if rtl %}
68+{% if rtl %}
69−{{ result_footer_rtl(result) }}
69+{{ result_footer_rtl(result) }}
70−{% else %}
70+{% else %}
71−{{ result_footer(result) }}
71+{{ result_footer(result) }}
72−{% endif %}
72+{% endif %}
searx/templates/oscar/result_templates/torrent.html+1−1
@@ -3,7 +3,7 @@
3{{ result_header(result, favicons) }}
3{{ result_header(result, favicons) }}
4{{ result_sub_header(result) }}
4{{ result_sub_header(result) }}
5
5
6−{% if result.seed %}<p class="result-content">{{ icon('transfer') }} {{ _('Seeder') }} <span class="badge">{{ result.seed }}</span> &bull; {{ _('Leecher') }} <span class="badge">{{ result.leech }}</span>{% endif %}
6+{% if result.seed is defined %}<p class="result-content">{{ icon('transfer') }} {{ _('Seeder') }} <span class="badge">{{ result.seed }}</span> &bull; {{ _('Leecher') }} <span class="badge">{{ result.leech }}</span>{% endif %}
7{% if result.filesize %}<br />{{ icon('floppy-disk') }} {{ _('Filesize') }}
7{% if result.filesize %}<br />{{ icon('floppy-disk') }} {{ _('Filesize') }}
8 <span class="badge">
8 <span class="badge">
9 {% if result.filesize < 1024 %}{{ result.filesize }} {{ _('Bytes') }}
9 {% if result.filesize < 1024 %}{{ result.filesize }} {{ _('Bytes') }}
searx/templates/oscar/result_templates/videos.html+27−27
@@ -1,27 +1,27 @@
1−{% from 'oscar/macros.html' import result_header, result_sub_header, result_footer, result_footer_rtl, icon %}
1+{% from 'oscar/macros.html' import result_header, result_sub_header, result_footer, result_footer_rtl, icon %}
2−
2+
3−{{ result_header(result, favicons) }}
3+{{ result_header(result, favicons) }}
4−{{ result_sub_header(result) }}
4+{{ result_sub_header(result) }}
5−
5+
6−{% if result.embedded %}
6+{% if result.embedded %}
7− <small> &bull; <a class="text-info btn-collapse collapsed cursor-pointer media-loader disabled_if_nojs" data-toggle="collapse" data-target="#result-video-{{ index }}" data-btn-text-collapsed="{{ _('show video') }}" data-btn-text-not-collapsed="{{ _('hide video') }}">{{ icon('film') }} {{ _('show video') }}</a></small>
7+ <small> &bull; <a class="text-info btn-collapse collapsed cursor-pointer media-loader disabled_if_nojs" data-toggle="collapse" data-target="#result-video-{{ index }}" data-btn-text-collapsed="{{ _('show video') }}" data-btn-text-not-collapsed="{{ _('hide video') }}">{{ icon('film') }} {{ _('show video') }}</a></small>
8−{% endif %}
8+{% endif %}
9−
9+
10−{% if result.embedded %}
10+{% if result.embedded %}
11−<div id="result-video-{{ index }}" class="collapse">
11+<div id="result-video-{{ index }}" class="collapse">
12− {{ result.embedded|safe }}
12+ {{ result.embedded|safe }}
13−</div>
13+</div>
14−{% endif %}
14+{% endif %}
15−
15+
16−<div class="container-fluid">
16+<div class="container-fluid">
17− <div class="row">
17+ <div class="row">
18− <a href="{{ result.url }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}><img class="thumbnail col-xs-6 col-sm-4 col-md-4 result-content" src="{{ image_proxify(result.thumbnail) }}" alt="{{ result.title|striptags }} {{ result.engine }}" /></a>
18+ <a href="{{ result.url }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}><img class="thumbnail col-xs-6 col-sm-4 col-md-4 result-content" src="{{ image_proxify(result.thumbnail) }}" alt="{{ result.title|striptags }} {{ result.engine }}" /></a>
19− {% if result.content %}<p class="col-xs-12 col-sm-8 col-md-8 result-content">{{ result.content|safe }}</p>{% endif %}
19+ {% if result.content %}<p class="col-xs-12 col-sm-8 col-md-8 result-content">{{ result.content|safe }}</p>{% endif %}
20− </div>
20+ </div>
21−</div>
21+</div>
22−
22+
23−{% if rtl %}
23+{% if rtl %}
24−{{ result_footer_rtl(result) }}
24+{{ result_footer_rtl(result) }}
25−{% else %}
25+{% else %}
26−{{ result_footer(result) }}
26+{{ result_footer(result) }}
27−{% endif %}
27+{% endif %}
searx/templates/oscar/results.html+156−155
@@ -1,155 +1,156 @@
1−{% extends "oscar/base.html" %}
1+{% extends "oscar/base.html" %}
2−{% macro search_form_attrs(pageno) -%}
2+{% macro search_form_attrs(pageno) -%}
3− {% for category in selected_categories %}<input type="hidden" name="category_{{ category }}" value="1"/>{% endfor %}
3+ {%- for category in selected_categories -%}<input type="hidden" name="category_{{ category }}" value="1"/>{%- endfor -%}
4− <input type="hidden" name="q" value="{{ q|e }}" />
4+ <input type="hidden" name="q" value="{{ q|e }}" />{{- "" -}}
5− <input type="hidden" name="pageno" value="{{ pageno }}" />
5+ <input type="hidden" name="pageno" value="{{ pageno }}" />{{- "" -}}
6− <input type="hidden" name="time_range" value="{{ time_range }}" />
6+ <input type="hidden" name="time_range" value="{{ time_range }}" />{{- "" -}}
7− <input type="hidden" name="language" value="{{ current_language }}" />
7+ <input type="hidden" name="language" value="{{ current_language }}" />{{- "" -}}
8+ {% if timeout_limit %}<input type="hidden" name="timeout_limit" value="{{ timeout_limit|e }}" />{% endif -%}
8−{%- endmacro %}
9+{%- endmacro %}
9−{%- macro search_url() %}{{ base_url }}?q={{ q|urlencode }}{% if selected_categories %}&amp;categories={{ selected_categories|join(",") | replace(' ','+') }}{% endif %}{% if pageno > 1 %}&amp;pageno={{ pageno }}{% endif %}{% if time_range %}&amp;time_range={{ time_range }}{% endif %}{% if current_language != 'all' %}&amp;language={{ current_language }}{% endif %}{% endmacro -%}
10+{%- macro search_url() %}{{ base_url }}?q={{ q|urlencode }}{% if selected_categories %}&amp;categories={{ selected_categories|join(",") | replace(' ','+') }}{% endif %}{% if pageno > 1 %}&amp;pageno={{ pageno }}{% endif %}{% if time_range %}&amp;time_range={{ time_range }}{% endif %}{% if current_language != 'all' %}&amp;language={{ current_language }}{% endif %}{% endmacro -%}
10−
11+
11−{% block title %}{{ q|e }} - {% endblock %}
12+{% block title %}{{ q|e }} - {% endblock %}
12−{% block meta %}<link rel="alternate" type="application/rss+xml" title="Searx search: {{ q|e }}" href="{{ search_url() }}&amp;format=rss">{% endblock %}
13+{% block meta %}{{" "}}<link rel="alternate" type="application/rss+xml" title="Searx search: {{ q|e }}" href="{{ search_url() }}&amp;format=rss">{% endblock %}
13−{% block content %}
14+{% block content %}
14− {% include 'oscar/search.html' %}
15+ {% include 'oscar/search.html' %}
16+
15− <div class="row">
17+ <div class="row">
16− <div class="col-sm-8" id="main_results">
18+ <div class="col-sm-8" id="main_results">
17− <h1 class="sr-only">{{ _('Search results') }}</h1>
19+ <h1 class="sr-only">{{ _('Search results') }}</h1>
18−
20+
19− {% if corrections %}
21+ {% if corrections -%}
20− <div class="result">
22+ <div class="result">
21− <span class="result_header text-muted form-inline pull-left suggestion_item">{{ _('Try searching for:') }}</span>
23+ <span class="result_header text-muted form-inline pull-left suggestion_item">{{ _('Try searching for:') }}</span>
22− {% for correction in corrections %}
24+ {% for correction in corrections -%}
23− <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" role="navigation" class="form-inline pull-left suggestion_item">
25+ <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" role="navigation" class="form-inline pull-left suggestion_item">{{- "" -}}
24− <input type="hidden" name="q" value="{{ query_prefix + correction }}">
26+ <input type="hidden" name="q" value="{{ correction.url }}">{{- "" -}}
25− <button type="submit" class="btn btn-default btn-xs">{{ correction }}</button>
27+ <button type="submit" class="btn btn-default btn-xs">{{ correction.title }}</button>{{- "" -}}
26− </form>
28+ </form>
27− {% endfor %}
29+ {% endfor %}
28− </div>
30+ </div>
29− {% endif %}
31+ {%- endif %}
30−
32+
31− {% if answers %}
33+ {% if answers -%}
32− {% for answer in answers %}
34+ {%- for answer in answers %}
33− <div class="result well">
35+ <div class="result well">
34− <span>{{ answer }}</span>
36+ <span>{{ answer }}</span>
35− </div>
37+ </div>
36− {% endfor %}
38+ {%- endfor %}
37− {% endif %}
39+ {%- endif %}
38−
40+
39− {% for result in results %}
41+ {% for result in results -%}
40− <div class="result {% if result['template'] %}result-{{ result.template|replace('.html', '') }}{% else %}result-default{% endif %}">
42+ <div class="result {% if result['template'] %}result-{{ result.template|replace('.html', '') }}{% else %}result-default{% endif %}">
41− {% set index = loop.index %}
43+ {%- set index = loop.index -%}
42− {% if result.template %}
44+ {%- if result.template -%}
43− {% include get_result_template('oscar', result['template']) %}
45+ {% include get_result_template('oscar', result['template']) %}
44− {% else %}
46+ {%- else -%}
45− {% include 'oscar/result_templates/default.html' %}
47+ {% include 'oscar/result_templates/default.html' %}
46− {% endif %}
48+ {%- endif -%}
47− </div>
49+ </div>
48− {% endfor %}
50+ {% endfor %}
49−
51+
50− {% if not results and not answers %}
52+ {% if not results and not answers -%}
51− {% include 'oscar/messages/no_results.html' %}
53+ {% include 'oscar/messages/no_results.html' %}
52− {% endif %}
54+ {% endif %}
53−
55+
54− <div class="clearfix"></div>
56+ <div class="clearfix"></div>
55−
57+
56− {% if paging %}
58+ {% if paging -%}
57− {% if rtl %}
59+ {% if rtl %}
58− <div id="pagination">
60+ <div id="pagination">
59− <div class="pull-left">
61+ <div class="pull-left">{{- "" -}}
60− <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" class="pull-left">
62+ <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" class="pull-left">
61− {{ search_form_attrs(pageno+1) }}
63+ {{- search_form_attrs(pageno+1) -}}
62− <button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-backward"></span> {{ _('next page') }}</button>
64+ <button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-backward"></span> {{ _('next page') }}</button>{{- "" -}}
63− </form>
65+ </form>{{- "" -}}
64− </div>
66+ </div>
65− <div class="pull-right">
67+ <div class="pull-right">{{- "" -}}
66− <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" class="pull-left">
68+ <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" class="pull-left">
67− {{ search_form_attrs(pageno-1) }}
69+ {{- search_form_attrs(pageno-1) -}}
68− <button type="submit" class="btn btn-default" {% if pageno == 1 %}disabled{% endif %}><span class="glyphicon glyphicon-forward"></span> {{ _('previous page') }}</button>
70+ <button type="submit" class="btn btn-default" {% if pageno == 1 %}disabled{% endif %}><span class="glyphicon glyphicon-forward"></span> {{ _('previous page') }}</button>{{- "" -}}
69− </form>
71+ </form>{{- "" -}}
70− </div>
72+ </div>
71− </div><!-- /#pagination -->
73+ </div><!-- /#pagination -->
72− <div class="clearfix"></div>
74+ <div class="clearfix"></div>
73− {% else %}
75+ {% else %}
74− <div id="pagination">
76+ <div id="pagination">
75− <div class="pull-left">
77+ <div class="pull-left">{{- "" -}}
76− <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" class="pull-left">
78+ <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" class="pull-left">
77− {{ search_form_attrs(pageno-1) }}
79+ {{- search_form_attrs(pageno-1) -}}
78− <button type="submit" class="btn btn-default" {% if pageno == 1 %}disabled{% endif %}><span class="glyphicon glyphicon-backward"></span> {{ _('previous page') }}</button>
80+ <button type="submit" class="btn btn-default" {% if pageno == 1 %}disabled{% endif %}><span class="glyphicon glyphicon-backward"></span> {{ _('previous page') }}</button>{{- "" -}}
79− </form>
81+ </form>{{- "" -}}
80− </div>
82+ </div>
81− <div class="pull-right">
83+ <div class="pull-right">{{- "" -}}
82− <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" class="pull-left">
84+ <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" class="pull-left">
83− {{ search_form_attrs(pageno+1) }}
85+ {{- search_form_attrs(pageno+1) -}}
84− <button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-forward"></span> {{ _('next page') }}</button>
86+ <button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-forward"></span> {{ _('next page') }}</button>{{- "" -}}
85− </form>
87+ </form>{{- "" -}}
86− </div>
88+ </div>
87− </div><!-- /#pagination -->
89+ </div><!-- /#pagination -->
88− <div class="clearfix"></div>
90+ <div class="clearfix"></div>
89− {% endif %}
91+ {% endif %}
90− {% endif %}
92+ {% endif %}
91− </div><!-- /#main_results -->
93+ </div><!-- /#main_results -->
92−
94+
93− <div class="col-sm-4" id="sidebar_results">
95+ <div class="col-sm-4" id="sidebar_results">
94− {% if number_of_results != '0' %}
96+ {% if number_of_results != '0' -%}
95− <p><small>{{ _('Number of results') }}: {{ number_of_results }}</small></p>
97+ <p><small>{{ _('Number of results') }}: {{ number_of_results }}</small></p>
96− {% endif %}
98+ {%- endif %}
97−
99+
98− {% if unresponsive_engines and results|length >= 1 %}
100+ {% if unresponsive_engines and results|length >= 1 -%}
99− <div class="alert alert-danger fade in" role="alert">
101+ <div class="alert alert-danger fade in" role="alert">
100− <p>{{ _('Engines cannot retrieve results') }}:</p>
102+ <p>{{ _('Engines cannot retrieve results') }}:</p>
101− {% for engine_name, error_type in unresponsive_engines %}
103+ {%- for engine_name, error_type in unresponsive_engines -%}
102− {{ engine_name }} ({{ error_type }}){% if not loop.last %}, {% endif %}
104+ {{- engine_name }} ({{ error_type }}){% if not loop.last %}, {% endif %}{{- "" -}}
103− {% endfor %}
105+ {%- endfor -%}
104− </div>
106+ </div>
105− {% endif %}
107+ {%- endif %}
106−
108+
107− {% if infoboxes %}
109+ {% if infoboxes -%}
108− {% for infobox in infoboxes %}
110+ {% for infobox in infoboxes %}
109− {% include 'oscar/infobox.html' %}
111+ {% include 'oscar/infobox.html' %}{{- "\n\n" -}}
110− {% endfor %}
112+ {% endfor %}
111− {% endif %}
113+ {%- endif %}
112−
114+
113− {% if suggestions %}
115+ {% if suggestions %}
114− <div class="panel panel-default">
116+ <div class="panel panel-default">
115− <div class="panel-heading">
117+ <div class="panel-heading">
116− <h4 class="panel-title">{{ _('Suggestions') }}</h4>
118+ <h4 class="panel-title">{{ _('Suggestions') }}</h4>
117− </div>
119+ </div>
118− <div class="panel-body">
120+ <div class="panel-body">
119− {% for suggestion in suggestions %}
121+ {% for suggestion in suggestions %}
120− <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" role="navigation" class="form-inline pull-{% if rtl %}right{% else %}left{% endif %} suggestion_item">
122+ <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" role="navigation" class="form-inline pull-{% if rtl %}right{% else %}left{% endif %} suggestion_item">
121− <input type="hidden" name="q" value="{{ suggestion.url }}">
123+ <input type="hidden" name="q" value="{{ suggestion.url }}">
122− <button type="submit" class="btn btn-default btn-xs">{{ suggestion.title }}</button>
124+ <button type="submit" class="btn btn-default btn-xs">{{ suggestion.title }}</button>
123− </form>
125+ </form>
124− {% endfor %}
126+ {% endfor %}
125− </div>
127+ </div>
126− </div>
128+ </div>
127− {% endif %}
129+ {%- endif %}
128−
130+
129− <div class="panel panel-default">
131+ <div class="panel panel-default">
130− <div class="panel-heading">
132+ <div class="panel-heading">{{- "" -}}
131− <h4 class="panel-title">{{ _('Links') }}</h4>
133+ <h4 class="panel-title">{{ _('Links') }}</h4>{{- "" -}}
132− </div>
134+ </div>
133− <div class="panel-body">
135+ <div class="panel-body">
134− <form role="form">
136+ <form role="form">{{- "" -}}
135− <div class="form-group">
137+ <div class="form-group">{{- "" -}}
136− <label for="search_url">{{ _('Search URL') }}</label>
138+ <label for="search_url">{{ _('Search URL') }}</label>{{- "" -}}
137− <input id="search_url" type="url" class="form-control select-all-on-click cursor-text" name="search_url" value="{{ search_url() }}" readonly>
139+ <input id="search_url" type="url" class="form-control select-all-on-click cursor-text" name="search_url" value="{{ search_url() }}" readonly>{{- "" -}}
138− </div>
140+ </div>{{- "" -}}
139− </form>
141+ </form>
140−
141− <label>{{ _('Download results') }}</label>
142+ <label>{{ _('Download results') }}</label>
142− <div class="clearfix"></div>
143+ <div class="clearfix"></div>
143− {% for output_type in ('csv', 'json', 'rss') %}
144+ {% for output_type in ('csv', 'json', 'rss') %}
144− <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" class="form-inline pull-{% if rtl %}right{% else %}left{% endif %} result_download">
145+ <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" class="form-inline pull-{% if rtl %}right{% else %}left{% endif %} result_download">
145− {{ search_form_attrs(pageno) }}
146+ {{- search_form_attrs(pageno) -}}
146− <input type="hidden" name="format" value="{{ output_type }}">
147+ <input type="hidden" name="format" value="{{ output_type }}">{{- "" -}}
147− <button type="submit" class="btn btn-default">{{ output_type }}</button>
148+ <button type="submit" class="btn btn-default">{{ output_type }}</button>{{- "" -}}
148− </form>
149+ </form>
149− {% endfor %}
150+ {% endfor %}
150− <div class="clearfix"></div>
151+ <div class="clearfix"></div>
151− </div>
152+ </div>
152− </div>
153+ </div>
153− </div><!-- /#sidebar_results -->
154+ </div><!-- /#sidebar_results -->
154− </div>
155+ </div>
155−{% endblock %}
156+{% endblock %}
searx/templates/oscar/search.html+24−24
@@ -1,24 +1,24 @@
1−{% from 'oscar/macros.html' import icon %}
1+{% from 'oscar/macros.html' import icon %}
2−<form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" id="search_form" role="search">
2+<form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" id="search_form" role="search">
3− <div class="row">
3+ <div class="row">
4− <div class="col-xs-12 col-md-8">
4+ <div class="col-xs-12 col-md-8">
5− <div class="input-group search-margin">
5+ <div class="input-group search-margin">
6− <input type="search" name="q" class="form-control" id="q" placeholder="{{ _('Search for...') }}" autocomplete="off" value="{{ q }}">
6+ <input type="search" name="q" class="form-control" id="q" placeholder="{{ _('Search for...') }}" aria-label="{{ _('Search for...') }}" autocomplete="off" value="{{ q }}" accesskey="s">
7− <span class="input-group-btn">
7+ <span class="input-group-btn">
8− <button type="submit" class="btn btn-default"><span class="hide_if_nojs">{{ icon('search') }}</span><span class="hidden active_if_nojs">{{ _('Start search') }}</span></button>
8+ <button type="submit" class="btn btn-default" aria-label="{{ _('Start search') }}"><span class="hide_if_nojs">{{ icon('search') }}</span><span class="hidden active_if_nojs">{{ _('Start search') }}</span></button>
9− </span>
9+ </span>
10− </div>
10+ </div>
11− </div>
11+ </div>
12− <div class="col-xs-6 col-md-2 search-margin">
12+ <div class="col-xs-6 col-md-2 search-margin">
13− {% include 'oscar/time-range.html' %}
13+ {%- include 'oscar/time-range.html' -%}
14− </div>
14+ </div>
15− <div class="col-xs-6 col-md-2 search-margin">
15+ <div class="col-xs-6 col-md-2 search-margin">
16− {% include 'oscar/languages.html' %}
16+ {%- include 'oscar/languages.html' -%}
17− </div>
17+ </div>
18− </div>
18+ </div>
19− <div class="row">
19+ <div class="row">
20− <div class="col-sm-12">
20+ <div class="col-sm-12">
21− {% include 'oscar/categories.html' %}
21+ {%- include 'oscar/categories.html' -%}
22− </div>
22+ </div>
23− </div>
23+ </div>
24−</form><!-- / #search_form_full -->
24+</form><!-- / #search_form_full -->
searx/templates/oscar/search_full.html+18−18
@@ -1,18 +1,18 @@
1−{% from 'oscar/macros.html' import icon %}
1+{% from 'oscar/macros.html' import icon %}
2−
2+
3−<form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" id="search_form" role="search">
3+<form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" id="search_form" role="search">
4− {% if rtl %}
4+ {% if rtl %}
5− <div class="input-group">
5+ <div class="input-group">
6− {% else %}
6+ {% else %}
7− <div class="input-group col-md-8 col-md-offset-2">
7+ <div class="input-group col-md-8 col-md-offset-2">
8− {% endif %}
8+ {% endif %}
9− <input type="search" name="q" class="form-control input-lg autofocus" id="q" placeholder="{{ _('Search for...') }}" autocomplete="off" value="{{ q }}">
9+ <input type="search" name="q" class="form-control input-lg autofocus" id="q" placeholder="{{ _('Search for...') }}" aria-label="{{ _('Search for...') }}" autocomplete="off" value="{{ q }}" accesskey="s">
10− <span class="input-group-btn">
10+ <span class="input-group-btn">
11− <button type="submit" class="btn btn-default input-lg"><span class="hide_if_nojs">{{ icon('search') }}</span><span class="hidden active_if_nojs">{{ _('Start search') }}</span></button>
11+ <button type="submit" class="btn btn-default input-lg" aria-label="{{ _('Start search') }}"><span class="hide_if_nojs">{{ icon('search') }}</span><span class="hidden active_if_nojs">{{ _('Start search') }}</span></button>
12− </span>
12+ </span>
13− </div>
13+ </div>
14− <div class="col-md-8 col-md-offset-2 advanced">
14+ <div class="col-md-8 col-md-offset-2 advanced">
15− {% include 'oscar/advanced.html' %}
15+ {% include 'oscar/advanced.html' %}
16− </div>
16+ </div>
17−
17+
18−</form><!-- / #search_form_full -->
18+</form><!-- / #search_form_full -->
searx/templates/oscar/time-range.html+11−11
@@ -1,17 +1,17 @@
1−<select name="time_range" id="time-range" class="custom-select form-control">
1+<select name="time_range" id="time-range" class="custom-select form-control" accesskey="t">{{- "" -}}
2 <option id="time-range-anytime" value="" {{ "selected" if time_range=="" or not time_range else ""}}>
2 <option id="time-range-anytime" value="" {{ "selected" if time_range=="" or not time_range else ""}}>
3− {{ _('Anytime') }}
3+ {{- _('Anytime') -}}
4− </option>
4+ </option>{{- "" -}}
5 <option id="time-range-day" value="day" {{ "selected" if time_range=="day" else ""}}>
5 <option id="time-range-day" value="day" {{ "selected" if time_range=="day" else ""}}>
6− {{ _('Last day') }}
6+ {{- _('Last day') -}}
7− </option>
7+ </option>{{- "" -}}
8 <option id="time-range-week" value="week" {{ "selected" if time_range=="week" else ""}}>
8 <option id="time-range-week" value="week" {{ "selected" if time_range=="week" else ""}}>
9− {{ _('Last week') }}
9+ {{- _('Last week') -}}
10− </option>
10+ </option>{{- "" -}}
11 <option id="time-range-month" value="month" {{ "selected" if time_range=="month" else ""}}>
11 <option id="time-range-month" value="month" {{ "selected" if time_range=="month" else ""}}>
12− {{ _('Last month') }}
12+ {{- _('Last month') -}}
13− </option>
13+ </option>{{- "" -}}
14 <option id="time-range-year" value="year" {{ "selected" if time_range=="year" else ""}}>
14 <option id="time-range-year" value="year" {{ "selected" if time_range=="year" else ""}}>
15− {{ _('Last year') }}
15+ {{- _('Last year') -}}
16− </option>
16+ </option>{{- "" -}}
17</select>
17</select>
searx/templates/simple/base.html+11−14
@@ -11,29 +11,26 @@
11 <meta name="HandheldFriendly" content="True">
11 <meta name="HandheldFriendly" content="True">
12 <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
12 <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
13 <title>{% block title %}{% endblock %}{{ instance_name }}</title>
13 <title>{% block title %}{% endblock %}{{ instance_name }}</title>
14+ {% block meta %}{% endblock %}
14 {% if rtl %}
15 {% if rtl %}
15 <link rel="stylesheet" href="{{ url_for('static', filename='css/searx-rtl.min.css') }}" type="text/css" media="screen" />
16 <link rel="stylesheet" href="{{ url_for('static', filename='css/searx-rtl.min.css') }}" type="text/css" media="screen" />
16 {% else %}
17 {% else %}
17 <link rel="stylesheet" href="{{ url_for('static', filename='css/searx.min.css') }}" type="text/css" media="screen" />
18 <link rel="stylesheet" href="{{ url_for('static', filename='css/searx.min.css') }}" type="text/css" media="screen" />
18 {% endif %}
19 {% endif %}
19 {% block styles %}{% endblock %}
20 {% block styles %}{% endblock %}
20− {% block meta %}{% endblock %}
21+ <!--[if gte IE 9]>-->
22+ <script src="{{ url_for('static', filename='js/searx.head.min.js') }}"
23+ data-method="{{ method or 'POST' }}"
24+ data-autocompleter="{% if autocomplete %}true{% else %}false{% endif %}"
25+ data-search-on-category-select="{{ 'true' if 'plugins/js/search_on_category_select.js' in scripts else 'false'}}"
26+ data-infinite-scroll="{{ 'true' if 'plugins/js/infinite_scroll.js' in scripts else 'false' }}"
27+ data-static-path="{{ url_for('static', filename='themes/simple') }}/"
28+ data-no-item-found="{{ _('No item found') }}"></script>
29+ <!--<![endif]-->
21 {% block head %}
30 {% block head %}
22 <link title="{{ instance_name }}" type="application/opensearchdescription+xml" rel="search" href="{{ url_for('opensearch') }}"/>
31 <link title="{{ instance_name }}" type="application/opensearchdescription+xml" rel="search" href="{{ url_for('opensearch') }}"/>
23 {% endblock %}
32 {% endblock %}
24 <link rel="shortcut icon" href="{{ url_for('static', filename='img/favicon.png') }}" />
33 <link rel="shortcut icon" href="{{ url_for('static', filename='img/favicon.png') }}" />
25− <script type="text/javascript">
26− var searx = {
27− autocompleter: {% if autocomplete %}true{% else %}false{% endif %},
28− method: "{{ method or 'POST' }}",
29− touch: (("ontouchstart" in window) || window.DocumentTouch && document instanceof DocumentTouch) || false,
30− staticPath: "{{ url_for('static', filename='themes/simple') }}/",
31− noItemFound: "{{ _('No item found') }}",
32− search_on_category_select: {{ 'true' if 'plugins/js/search_on_category_select.js' in scripts else 'false'}},
33− infinite_scroll: {{ 'true' if 'plugins/js/infinite_scroll.js' in scripts else 'false' }}
34− };
35− document.getElementsByTagName("html")[0].className = (searx.touch)?"js touch":"js";
36− </script>
37</head>
34</head>
38<body>
35<body>
39 <main id="main_{{ self._TemplateReference__context.name|replace("simple/", "")|replace(".html", "") }}">
36 <main id="main_{{ self._TemplateReference__context.name|replace("simple/", "")|replace(".html", "") }}">
@@ -60,7 +57,7 @@
60 </p>
57 </p>
61 </footer>
58 </footer>
62 <!--[if gte IE 9]>-->
59 <!--[if gte IE 9]>-->
63− <script src="{{ url_for('static', filename='js/searx.min.js') }}" ></script>
60+ <script src="{{ url_for('static', filename='js/searx.min.js') }}"></script>
64 <!--<![endif]-->
61 <!--<![endif]-->
65</body>
62</body>
66</html>
63</html>
searx/templates/simple/infobox.html+5
@@ -36,6 +36,11 @@
36 {% for suggestion in topic.suggestions %}
36 {% for suggestion in topic.suggestions %}
37 <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}">
37 <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}">
38 <input type="hidden" name="q" value="{{ suggestion }}">
38 <input type="hidden" name="q" value="{{ suggestion }}">
39+ <input type="hidden" name="time_range" value="{{ time_range }}">
40+ <input type="hidden" name="language" value="{{ current_language }}">
41+ <input type="hidden" name="safesearch" value="{{ safesearch }}">
42+ <input type="hidden" name="theme" value="{{ theme }}">
43+ {% if timeout_limit %}<input type="hidden" name="timeout_limit" value="{{ timeout_limit|e }}" >{% endif %}
39 <input type="submit" value="{{ suggestion }}" />
44 <input type="submit" value="{{ suggestion }}" />
40 </form>
45 </form>
41 {% endfor %}
46 {% endfor %}
searx/templates/simple/result_templates/key-value.htmlnew file+11
@@ -0,0 +1,11 @@
1+<table>
2+ {% for key, value in result.items() %}
3+ {% if key in ['engine', 'engines', 'template', 'score', 'category', 'positions'] %}
4+ {% continue %}
5+ {% endif %}
6+ <tr>
7+ <td><b>{{ key|upper }}</b>: {{ value }}</td>
8+ </tr>
9+ {% endfor %}
10+</table>
11+<div class="engines">{% for engine in result.engines %}<span>{{ engine }}</span>{% endfor %}</div>{{- '' -}}
searx/templates/simple/result_templates/torrent.html+1−1
@@ -6,7 +6,7 @@
6{% if result.magnetlink %}<p class="altlink"> &bull; {{ result_link(result.magnetlink, icon('magnet') + _('magnet link'), "magnetlink") }}</p>{% endif %}
6{% if result.magnetlink %}<p class="altlink"> &bull; {{ result_link(result.magnetlink, icon('magnet') + _('magnet link'), "magnetlink") }}</p>{% endif %}
7{% if result.torrentfile %}<p class="altlink"> &bull; {{ result_link(result.torrentfile, icon('download-alt') + _('torrent file'), "torrentfile") }}</p>{% endif %}
7{% if result.torrentfile %}<p class="altlink"> &bull; {{ result_link(result.torrentfile, icon('download-alt') + _('torrent file'), "torrentfile") }}</p>{% endif %}
8
8
9−{% if result.seed %}<p class="stat"> &bull; {{ icon('arrow-swap') }} {{ _('Seeder') }} <span class="badge">{{ result.seed }}</span> &bull; {{ _('Leecher') }} <span class="badge">{{ result.leech }}</span></p>{% endif %}
9+{% if result.seed is defined %}<p class="stat"> &bull; {{ icon('arrow-swap') }} {{ _('Seeder') }} <span class="badge">{{ result.seed }}</span> &bull; {{ _('Leecher') }} <span class="badge">{{ result.leech }}</span></p>{% endif %}
10
10
11{%- if result.filesize %}<p class="stat">{{ icon('floppy-disk') }} {{ _('Filesize') }}<span class="badge">
11{%- if result.filesize %}<p class="stat">{{ icon('floppy-disk') }} {{ _('Filesize') }}<span class="badge">
12 {%- if result.filesize < 1024 %}{{ result.filesize }} {{ _('Bytes') }}
12 {%- if result.filesize < 1024 %}{{ result.filesize }} {{ _('Bytes') }}
searx/templates/simple/results.html+11−5
@@ -51,9 +51,11 @@
51 {% for suggestion in suggestions %}
51 {% for suggestion in suggestions %}
52 <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}">
52 <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}">
53 <input type="hidden" name="q" value="{{ suggestion.url }}">
53 <input type="hidden" name="q" value="{{ suggestion.url }}">
54+ <input type="hidden" name="time_range" value="{{ time_range }}">
54 <input type="hidden" name="language" value="{{ current_language }}">
55 <input type="hidden" name="language" value="{{ current_language }}">
55 <input type="hidden" name="safesearch" value="{{ safesearch }}">
56 <input type="hidden" name="safesearch" value="{{ safesearch }}">
56 <input type="hidden" name="theme" value="{{ theme }}">
57 <input type="hidden" name="theme" value="{{ theme }}">
58+ {% if timeout_limit %}<input type="hidden" name="timeout_limit" value="{{ timeout_limit|e }}" >{% endif %}
57 <input type="submit" class="suggestion" value="&bull; {{ suggestion.title }}">
59 <input type="submit" class="suggestion" value="&bull; {{ suggestion.title }}">
58 </form>
60 </form>
59 {% endfor %}
61 {% endfor %}
@@ -63,7 +65,7 @@
63
65
64 <div id="search_url">
66 <div id="search_url">
65 <h4 class="title">{{ _('Search URL') }} :</h4>
67 <h4 class="title">{{ _('Search URL') }} :</h4>
66− <div class="selectable_url"><pre>{{ base_url }}?q={{ q|urlencode }}&amp;language={{ current_language }}&amp;time_range={{ time_range }}&amp;safesearch={{ safesearch }}{% if pageno > 1 %}&amp;pageno={{ pageno }}{% endif %}{% if selected_categories %}&amp;categories={{ selected_categories|join(",") | replace(' ','+') }}{% endif %}</pre></div>
68+ <div class="selectable_url"><pre>{{ base_url }}?q={{ q|urlencode }}&amp;language={{ current_language }}&amp;time_range={{ time_range }}&amp;safesearch={{ safesearch }}{% if pageno > 1 %}&amp;pageno={{ pageno }}{% endif %}{% if selected_categories %}&amp;categories={{ selected_categories|join(",") | replace(' ','+') }}{% endif %}{% if timeout_limit %}&amp;timeout_limit={{ timeout_limit|urlencode }}{% endif %}</pre></div>
67 </div>
69 </div>
68 <div id="apis">
70 <div id="apis">
69 <h4 class="title">{{ _('Download results') }}</h4>
71 <h4 class="title">{{ _('Download results') }}</h4>
@@ -79,6 +81,7 @@
79 <input type="hidden" name="language" value="{{ current_language }}">
81 <input type="hidden" name="language" value="{{ current_language }}">
80 <input type="hidden" name="safesearch" value="{{ safesearch }}">
82 <input type="hidden" name="safesearch" value="{{ safesearch }}">
81 <input type="hidden" name="format" value="{{ output_type }}">
83 <input type="hidden" name="format" value="{{ output_type }}">
84+ {% if timeout_limit %}<input type="hidden" name="timeout_limit" value="{{ timeout_limit|e }}" >{% endif %}
82 <input type="submit" value="{{ output_type }}">
85 <input type="submit" value="{{ output_type }}">
83 </form>
86 </form>
84 </div>
87 </div>
@@ -92,12 +95,13 @@
92 {% for correction in corrections %}
95 {% for correction in corrections %}
93 <div class="left">
96 <div class="left">
94 <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" role="navigation">
97 <form method="{{ method or 'POST' }}" action="{{ url_for('index') }}" role="navigation">
95− <input type="hidden" name="q" value="{{ correction }}">
98+ <input type="hidden" name="q" value="{{ correction.url }}">
96 <input type="hidden" name="time_range" value="{{ time_range }}">
99 <input type="hidden" name="time_range" value="{{ time_range }}">
97 <input type="hidden" name="language" value="{{ current_language }}">
100 <input type="hidden" name="language" value="{{ current_language }}">
98 <input type="hidden" name="safesearch" value="{{ safesearch }}">
101 <input type="hidden" name="safesearch" value="{{ safesearch }}">
99 <input type="hidden" name="theme" value="{{ theme }}">
102 <input type="hidden" name="theme" value="{{ theme }}">
103+ {% if timeout_limit %}<input type="hidden" name="timeout_limit" value="{{ timeout_limit }}" >{% endif %}
100− <input type="submit" value="{{ correction }}">
104+ <input type="submit" value="{{ correction.title }}">
101 </form>
105 </form>
102 </div>
106 </div>
103 {% endfor %}
107 {% endfor %}
@@ -134,7 +138,8 @@
134 <input type="hidden" name="language" value="{{ current_language }}" >
138 <input type="hidden" name="language" value="{{ current_language }}" >
135 <input type="hidden" name="safesearch" value="{{ safesearch }}" >
139 <input type="hidden" name="safesearch" value="{{ safesearch }}" >
136 <input type="hidden" name="theme" value="{{ theme }}" >
140 <input type="hidden" name="theme" value="{{ theme }}" >
141+ {% if timeout_limit %}<input type="hidden" name="timeout_limit" value="{{ timeout_limit|e }}" >{% endif %}
137− <button type="submit">{{ icon_small('chevron-left') }} {{ _('previous page') }}</button>
142+ <button type="submit">{{ icon_small('chevron-left') }} {{ _('previous page') }}</button>
138 </div>
143 </div>
139 </form>
144 </form>
140 {% endif %}
145 {% endif %}
@@ -149,7 +154,8 @@
149 <input type="hidden" name="language" value="{{ current_language }}" >
154 <input type="hidden" name="language" value="{{ current_language }}" >
150 <input type="hidden" name="safesearch" value="{{ safesearch }}" >
155 <input type="hidden" name="safesearch" value="{{ safesearch }}" >
151 <input type="hidden" name="theme" value="{{ theme }}" >
156 <input type="hidden" name="theme" value="{{ theme }}" >
157+ {% if timeout_limit %}<input type="hidden" name="timeout_limit" value="{{ timeout_limit|e }}" >{% endif %}
152− <button type="submit">{{ _('next page') }} {{ icon_small('chevron-right') }}</button>
158+ <button type="submit">{{ _('next page') }} {{ icon_small('chevron-right') }}</button>
153 </div>
159 </div>
154 </form>
160 </form>
155 </nav>
161 </nav>
searx/templates/simple/search.html+1
@@ -14,4 +14,5 @@
14 {% include 'simple/categories.html' %}
14 {% include 'simple/categories.html' %}
15 <input type="hidden" name="safesearch" value="{{ safesearch }}" >
15 <input type="hidden" name="safesearch" value="{{ safesearch }}" >
16 <input type="hidden" name="theme" value="{{ theme }}" >
16 <input type="hidden" name="theme" value="{{ theme }}" >
17+ {% if timeout_limit %}<input type="hidden" name="timeout_limit" value="{{ timeout_limit|e }}" >{% endif %}
17</form>
18</form>
searx/testing.py+12
@@ -80,6 +80,18 @@ class SearxTestCase(TestCase):
80
80
81 layer = SearxTestLayer
81 layer = SearxTestLayer
82
82
83+ def setattr4test(self, obj, attr, value):
84+ """
85+ setattr(obj, attr, value)
86+ but reset to the previous value in the cleanup.
87+ """
88+ previous_value = getattr(obj, attr)
89+
90+ def cleanup_patch():
91+ setattr(obj, attr, previous_value)
92+ self.addCleanup(cleanup_patch)
93+ setattr(obj, attr, value)
94+
83
95
84if __name__ == '__main__':
96if __name__ == '__main__':
85 import sys
97 import sys
searx/utils.py+52−2
@@ -1,3 +1,4 @@
1+# -*- coding: utf-8 -*-
1import csv
2import csv
2import hashlib
3import hashlib
3import hmac
4import hmac
@@ -12,6 +13,7 @@ from numbers import Number
12from os.path import splitext, join
13from os.path import splitext, join
13from io import open
14from io import open
14from random import choice
15from random import choice
16+from lxml.etree import XPath
15import sys
17import sys
16import json
18import json
17
19
@@ -44,9 +46,13 @@ logger = logger.getChild('utils')
44blocked_tags = ('script',
46blocked_tags = ('script',
45 'style')
47 'style')
46
48
49+ecma_unescape4_re = re.compile(r'%u([0-9a-fA-F]{4})', re.UNICODE)
50+ecma_unescape2_re = re.compile(r'%([0-9a-fA-F]{2})', re.UNICODE)
51+
47useragents = json.loads(open(os.path.dirname(os.path.realpath(__file__))
52useragents = json.loads(open(os.path.dirname(os.path.realpath(__file__))
48 + "/data/useragents.json", 'r', encoding='utf-8').read())
53 + "/data/useragents.json", 'r', encoding='utf-8').read())
49
54
55+xpath_cache = dict()
50lang_to_lc_cache = dict()
56lang_to_lc_cache = dict()
51
57
52
58
@@ -304,14 +310,15 @@ def int_or_zero(num):
304
310
305def is_valid_lang(lang):
311def is_valid_lang(lang):
306 is_abbr = (len(lang) == 2)
312 is_abbr = (len(lang) == 2)
313+ lang = lang.lower().decode('utf-8')
307 if is_abbr:
314 if is_abbr:
308 for l in language_codes:
315 for l in language_codes:
309− if l[0][:2] == lang.lower():
316+ if l[0][:2] == lang:
310 return (True, l[0][:2], l[3].lower())
317 return (True, l[0][:2], l[3].lower())
311 return False
318 return False
312 else:
319 else:
313 for l in language_codes:
320 for l in language_codes:
314− if l[1].lower() == lang.lower():
321+ if l[1].lower() == lang or l[3].lower() == lang:
315 return (True, l[0][:2], l[3].lower())
322 return (True, l[0][:2], l[3].lower())
316 return False
323 return False
317
324
@@ -415,3 +422,46 @@ def to_string(obj):
415 return obj.__str__()
422 return obj.__str__()
416 if hasattr(obj, '__repr__'):
423 if hasattr(obj, '__repr__'):
417 return obj.__repr__()
424 return obj.__repr__()
425+
426+
427+def ecma_unescape(s):
428+ """
429+ python implementation of the unescape javascript function
430+
431+ https://www.ecma-international.org/ecma-262/6.0/#sec-unescape-string
432+ https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/unescape
433+ """
434+ # s = unicode(s)
435+ # "%u5409" becomes "吉"
436+ s = ecma_unescape4_re.sub(lambda e: unichr(int(e.group(1), 16)), s)
437+ # "%20" becomes " ", "%F3" becomes "ó"
438+ s = ecma_unescape2_re.sub(lambda e: unichr(int(e.group(1), 16)), s)
439+ return s
440+
441+
442+def get_engine_from_settings(name):
443+ """Return engine configuration from settings.yml of a given engine name"""
444+
445+ if 'engines' not in settings:
446+ return {}
447+
448+ for engine in settings['engines']:
449+ if 'name' not in engine:
450+ continue
451+ if name == engine['name']:
452+ return engine
453+
454+ return {}
455+
456+
457+def get_xpath(xpath_str):
458+ result = xpath_cache.get(xpath_str, None)
459+ if result is None:
460+ result = XPath(xpath_str)
461+ xpath_cache[xpath_str] = result
462+ return result
463+
464+
465+def eval_xpath(element, xpath_str):
466+ xpath = get_xpath(xpath_str)
467+ return xpath(element)
searx/webapp.py+30−19
@@ -41,7 +41,10 @@ except:
41 logger.critical("cannot import dependency: pygments")
41 logger.critical("cannot import dependency: pygments")
42 from sys import exit
42 from sys import exit
43 exit(1)
43 exit(1)
44+try:
44−from cgi import escape
45+ from cgi import escape
46+except:
47+ from html import escape
45from datetime import datetime, timedelta
48from datetime import datetime, timedelta
46from time import time
49from time import time
47from werkzeug.contrib.fixers import ProxyFix
50from werkzeug.contrib.fixers import ProxyFix
@@ -124,6 +127,7 @@ app = Flask(
124
127
125app.jinja_env.trim_blocks = True
128app.jinja_env.trim_blocks = True
126app.jinja_env.lstrip_blocks = True
129app.jinja_env.lstrip_blocks = True
130+app.jinja_env.add_extension('jinja2.ext.loopcontrols')
127app.secret_key = settings['server']['secret_key']
131app.secret_key = settings['server']['secret_key']
128
132
129if not searx_debug \
133if not searx_debug \
@@ -153,20 +157,18 @@ outgoing_proxies = settings['outgoing'].get('proxies') or None
153
157
154@babel.localeselector
158@babel.localeselector
155def get_locale():
159def get_locale():
156− locale = request.accept_languages.best_match(settings['locales'].keys())
160+ if 'locale' in request.form\
157−
161+ and request.form['locale'] in settings['locales']:
158− if request.preferences.get_value('locale') != '':
159− locale = request.preferences.get_value('locale')
162+ return request.form['locale']
160
163
161 if 'locale' in request.args\
164 if 'locale' in request.args\
162 and request.args['locale'] in settings['locales']:
165 and request.args['locale'] in settings['locales']:
163− locale = request.args['locale']
166+ return request.args['locale']
164
167
165− if 'locale' in request.form\
168+ if request.preferences.get_value('locale') != '':
166− and request.form['locale'] in settings['locales']:
167− locale = request.form['locale']
169+ return request.preferences.get_value('locale')
168
170
169− return locale
171+ return request.accept_languages.best_match(settings['locales'].keys())
170
172
171
173
172# code-highlighter
174# code-highlighter
@@ -538,14 +540,16 @@ def index():
538 if output_format == 'html':
540 if output_format == 'html':
539 if 'content' in result and result['content']:
541 if 'content' in result and result['content']:
540 result['content'] = highlight_content(escape(result['content'][:1024]), search_query.query)
542 result['content'] = highlight_content(escape(result['content'][:1024]), search_query.query)
543+ if 'title' in result and result['title']:
541− result['title'] = highlight_content(escape(result['title'] or u''), search_query.query)
544+ result['title'] = highlight_content(escape(result['title'] or u''), search_query.query)
542 else:
545 else:
543 if result.get('content'):
546 if result.get('content'):
544 result['content'] = html_to_text(result['content']).strip()
547 result['content'] = html_to_text(result['content']).strip()
545 # removing html content and whitespace duplications
548 # removing html content and whitespace duplications
546 result['title'] = ' '.join(html_to_text(result['title']).strip().split())
549 result['title'] = ' '.join(html_to_text(result['title']).strip().split())
547
550
551+ if 'url' in result:
548− result['pretty_url'] = prettify_url(result['url'])
552+ result['pretty_url'] = prettify_url(result['url'])
549
553
550 # TODO, check if timezone is calculated right
554 # TODO, check if timezone is calculated right
551 if 'publishedDate' in result:
555 if 'publishedDate' in result:
@@ -602,11 +606,17 @@ def index():
602 # HTML output format
606 # HTML output format
603
607
604 # suggestions: use RawTextQuery to get the suggestion URLs with the same bang
608 # suggestions: use RawTextQuery to get the suggestion URLs with the same bang
605− suggestion_urls = map(lambda suggestion: {
609+ suggestion_urls = list(map(lambda suggestion: {
606− 'url': raw_text_query.changeSearchQuery(suggestion).getFullQuery(),
610+ 'url': raw_text_query.changeSearchQuery(suggestion).getFullQuery(),
607− 'title': suggestion
611+ 'title': suggestion
608− },
612+ },
609− result_container.suggestions)
613+ result_container.suggestions))
614+
615+ correction_urls = list(map(lambda correction: {
616+ 'url': raw_text_query.changeSearchQuery(correction).getFullQuery(),
617+ 'title': correction
618+ },
619+ result_container.corrections))
610 #
620 #
611 return render(
621 return render(
612 'results.html',
622 'results.html',
@@ -619,7 +629,7 @@ def index():
619 advanced_search=advanced_search,
629 advanced_search=advanced_search,
620 suggestions=suggestion_urls,
630 suggestions=suggestion_urls,
621 answers=result_container.answers,
631 answers=result_container.answers,
622− corrections=result_container.corrections,
632+ corrections=correction_urls,
623 infoboxes=result_container.infoboxes,
633 infoboxes=result_container.infoboxes,
624 paging=result_container.paging,
634 paging=result_container.paging,
625 unresponsive_engines=result_container.unresponsive_engines,
635 unresponsive_engines=result_container.unresponsive_engines,
@@ -628,7 +638,8 @@ def index():
628 fallback=settings['search']['language']),
638 fallback=settings['search']['language']),
629 base_url=get_base_url(),
639 base_url=get_base_url(),
630 theme=get_current_theme_name(),
640 theme=get_current_theme_name(),
631− favicons=global_favicons[themes.index(get_current_theme_name())]
641+ favicons=global_favicons[themes.index(get_current_theme_name())],
642+ timeout_limit=request.form.get('timeout_limit', None)
632 )
643 )
633
644
634
645
setup.py+6−6
@@ -11,14 +11,14 @@ import sys
11sys.path.insert(0, './searx')
11sys.path.insert(0, './searx')
12from version import VERSION_STRING
12from version import VERSION_STRING
13
13
14+with open('README.rst') as f:
15+ long_description = f.read()
14
16
15−def read(*rnames):
17+with open('requirements.txt') as f:
16− return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
18+ requirements = [ l.strip() for l in f.readlines()]
17
19
18−
19−long_description = read('README.rst')
20−requirements = map(str.strip, open('requirements.txt').readlines())
21−dev_requirements = map(str.strip, open('requirements-dev.txt').readlines())
20+with open('requirements-dev.txt') as f:
21+ dev_requirements = [ l.strip() for l in f.readlines()]
22
22
23setup(
23setup(
24 name='searx',
24 name='searx',
tests/unit/engines/__init__.pydeleted

No changes to the content.

tests/unit/engines/pubmed.pydeleted−37
@@ -1,37 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import pubmed
5−from searx.testing import SearxTestCase
6−
7−
8−class TestPubmedEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dicto = defaultdict(dict)
13− dicto['pageno'] = 1
14− params = pubmed.request(query, dicto)
15− self.assertIn('url', params)
16− self.assertIn('eutils.ncbi.nlm.nih.gov/', params['url'])
17− self.assertIn('term', params['url'])
18−
19− def test_response(self):
20− self.assertRaises(AttributeError, pubmed.response, None)
21− self.assertRaises(AttributeError, pubmed.response, [])
22− self.assertRaises(AttributeError, pubmed.response, '')
23− self.assertRaises(AttributeError, pubmed.response, '[]')
24−
25− response = mock.Mock(text='<PubmedArticleSet></PubmedArticleSet>')
26− self.assertEqual(pubmed.response(response), [])
27−
28− xml_mock = """<eSearchResult><Count>1</Count><RetMax>1</RetMax><RetStart>0</RetStart><IdList>
29−<Id>1</Id>
30−</IdList></eSearchResult>
31−"""
32−
33− response = mock.Mock(text=xml_mock.encode('utf-8'))
34− results = pubmed.response(response)
35− self.assertEqual(type(results), list)
36− self.assertEqual(len(results), 1)
37− self.assertEqual(results[0]['content'], 'No abstract is available for this publication.')
tests/unit/engines/seedpeer_fixture.htmldeleted−110
@@ -1,110 +0,0 @@
1−<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2− <html xmlns="http://www.w3.org/1999/xhtml">
3− <head>
4− </head>
5− <body>
6− <div id="header">
7− <div id="whoIsYou">
8− <a href="/lang.php"><small>SeedPeer in your own language?</small></a>&nbsp;&nbsp;&nbsp;<a href="http://www.seedpeer.eu"><img src="/images/flags/uk.gif" width="16px" alt="Torrents EN" /></a> <a href="http://spanish.seedpeer.eu"><img src="/images/flags/es.gif" width="16px" alt="Torrents ES" /></a> <a href="http://german.seedpeer.eu"><img src="/images/flags/de.gif" width="16px" alt="Torrents DE" /></a> <a href="http://french.seedpeer.eu"><img src="/images/flags/fr.gif" width="16px" alt="Torrents FR" /></a> <a href="http://portuguese.seedpeer.eu"><img src="/images/flags/pt.gif" width="16px" alt="Torrents Portuguese" /></a> <a href="http://swedish.seedpeer.eu"><img src="/images/flags/se.gif" width="16px" alt="Torrents Sweden" /></a>
9− </div>
10−
11− <script type="text/javascript">
12− whoIsYou();
13− </script>
14− <div id="search">
15− <form action="/search.php" method="get">
16− <input id="topsearchbar" name="search" value="narcos season 2" />
17− <input type="submit" class="searchbutton" value="Torrents" />
18− <input style="color:#000" type="submit" class="searchbutton" name="usenet" value="Usenet Binaries" />
19− </form>
20− <div id="suggestion"></div>
21− </div>
22− <div id="logo"><a href="/"><img src="/images/logo2.gif" alt="Seedpeer homepage" width="415" height="143" /></a></div>
23− <div id="subtext"><a href="/">Home</a> &gt; <a href="/search.html">Torrent search</a> &gt; Narcos season 2 | page 1</div>
24− </div>
25− <div id="nav">
26− <ul>
27− <!--
28− <li><font style="color:red;font-size:9px;font-weight:bold;">NEW</font><a title="Download TOP Games for FREE" rel="nofollow" href="http://www.bigrebelads.com/affiliate/index?ref=9301" target="_blank">FREE Games</a></li>
29−
30− -->
31− <li style="border-left:none" id="categories"><a title="Browse Torrent Categories" href="/browse.html">Categories</a>
32− <ul>
33− <li><a title="Browse Anime Torrents" href="/browse.html#6">Anime</a></li>
34− <li><a title="Browse Game Torrents" href="/browse.html#4">Games</a></li>
35− <li><a title="Browse Movie Torrents" href="/browse.html#1">Movies</a></li>
36− <li><a title="Browse Music Torrents" href="/browse.html#3">Music</a></li>
37− <li><a title="Browse Software Torrents" href="/browse.html#5">Software</a></li>
38− <li><a title="Browse TV Torrents" href="/browse.html#2">TV Shows</a></li>
39− <li><a title="Browse Other Torrents" href="/browse.html#7">Others</a></li>
40− </ul>
41− </li>
42− <li><a title="Upload A Torrents" href="/upload.html">Upload torrent</a></li>
43− <li id="verified"><a title="Verified Torrents" href="/verified.html">Verified</a></li>
44− <li id="searchoptions"><a title="Search Torrents" href="/search.html">Torrent search</a></li>
45− <li id="newsgroups"><a style="color:#212b3e" title="News Groups" href="/usenet.html">Usenet Binaries</a></li>
46− <li id="about" style="border-right:none"><a rel="nofollow" href="/faq.html">About Us</a>
47− <ul>
48− <li><a title="SeedPeer Statistics" href="/stats.html">Statistics</a></li>
49− <li><a title="Contact Us" href="/contact.html">Contact</a></li>
50− <li><a title="Frequently Asked Questions" href="/faq.html">FAQ</a></li>
51− <li><a title="SeedPeer API" href="http://api.seedpeer.eu">Our API</a></li>
52− <li><a title="SeedPeer Blog" href="/blog">Blog</a></li>
53− </ul>
54− </li>
55− <!--<li><a href="/toolbar.php">Our Toolbar</a></li>-->
56− </ul>
57− <div class="clear"></div>
58− </div>
59− <div id="body"><div id="pageTop"></div>
60− <div id="headerbox"><h1>Verified <font class="colored">Narcos season 2</font> torrents</h1></div><table width="100%"><tr><th>
61− <span style="float:right">
62− <a href="/search/narcos-season-2/8/1.html"><img style="vertical-align:middle" src="/images/comments.gif" alt="comments" /></a> |
63− <a href="/search/narcos-season-2/7/1.html"><img style="vertical-align:middle" src="/images/ver.gif" alt="verified" /></a>
64− </span>
65− <a href="/search/narcos-season-2/1/1.html">Torrent name</a></th><th class="right"><a href="/search/narcos-season-2/2/1.html">Age</a></th><th class="right"><a href="/search/narcos-season-2/3/1.html">Size</a></th><th class="right"><a href="/search/narcos-season-2/4/1.html">Seeds</a></th><th class="right"><a href="/search/narcos-season-2/5/1.html">Peers</a></th><th class="center"><a href="/search/narcos-season-2/6/1.html">Health</a></th><td class="tableAd" rowspan="6"><iframe src="http://creative.wwwpromoter.com/13689?d=300x250" width="300" height="250" style="border: none;" frameborder="0" scrolling="no"></iframe></td></tr><tr class=""><td><a class="pblink" id="pblink_table_item_1" href="" data-tad="431726" data-last-search="narcos+season+2" target="_blank" rel="nofollow"><strong class='colored'>Narcos season 2</strong> Full Version</a></td><td class="right">20 hours</td><td class="right">681.3 MB</td><td class="right"><font color="green">28</font> </td><td class="right"><font color="navy">654</font> </td><td class="center"><img src="/images/h5.gif" alt="Health" /></td></tr><tr class="tdark"><td><a class="pblink" id="pblink_table_item_2" href="" data-tad="431727" data-url="narcos+season+2" target="_blank" rel="nofollow"><strong class='colored'>Narcos season 2</strong> Trusted Source</a></td><td class="right">12 hours</td><td class="right">787.1 MB</td><td class="right"><font color="green">64</font> </td><td class="right"><font color="navy">220</font> </td><td class="center"><img src="/images/h5.gif" alt="Health" /></td></tr><tr class=""><td><a class="pblink" id="pblink_table_item_3" href="" data-tad="431729" data-last-search="narcos+season+2" target="_blank" rel="nofollow"><strong class='colored'>Full Narcos season 2 Download</strong></a> <small><a class="pblink" id="pblink_table_item_4" href="" data-tad="431729" data-last-search="narcos+season+2" target="_blank" rel="nofollow">Usenet</a></small></td><td class="right">24 hours</td><td class="right">775.5 MB</td><td class="right"><font color="green">60</font> </td><td class="right"><font color="navy">236</font> </td><td class="center"><img src="/images/h5.gif" alt="Health" /></td></tr><tr class="tdark"><td><a class="pblink" id="pblink_table_item_5" href="" data-tad="431730" data-last-search="narcos+season+2" target="_blank" rel="nofollow"><strong class='colored'>Narcos season 2</strong> 2014 - DIRECT STREAMING</a> <small><a class="pblink" id="pblink_table_item_6" href="" data-tad="431729" data-last-search="narcos+season+2" target="_blank" rel="nofollow">Movies</a></small></td><td class="right">17 hours</td><td class="right">654.1 MB</td><td class="right"><font color="green">2</font> </td><td class="right"><font color="navy">391</font> </td><td class="center"><img src="/images/h5.gif" alt="Health" /></td></tr><tr class=""><td><a class="pblink" id="pblink_table_item_7" href="" data-tad="431731" data-last-search="narcos+season+2" target="_blank" rel="nofollow"><strong class='colored'>Narcos season 2</strong> 2014</a> <small><a class="pblink" id="pblink_table_item_8" href="" data-tad="431729" data-last-search="narcos+season+2" target="_blank" rel="nofollow">Movies</a></small></td><td class="right">20 hours</td><td class="right">754.5 MB</td><td class="right"><font color="green">21</font> </td><td class="right"><font color="navy">919</font> </td><td class="center"><img src="/images/h5.gif" alt="Health" /></td></tr></table><br /><br /><center><iframe src='http://creative.wwwpromoter.com/13689?d=728x90' width='728' height='90' style='border: none;' frameborder='0' scrolling='no'></iframe><center><span style="float:right;margin:1em .2em 0 0"><a title="Download at the speed of your connection" href="/usenet.php?search=narcos+season+2"><img src="/images/dlf.gif" alt="Search Binaries" /></a></span><div style="margin-bottom:1em;margin-right:290px" id="headerbox"><h1><a href="/searchfeed/narcos+season+2.xml" target="_blank" title="SeedPeer RSS Torrent Search Feed fornarcos season 2"><img src="/images/feedIcon.png" border="0" /></a>&nbsp;2 <font class="colored">Narcos season 2</font> Torrents were found</h1></div><table width="100%"><tr><th>
66− <span style="float:right">
67− <a href="/search/narcos-season-2/8/1.html"><img style="vertical-align:middle" src="/images/comments.gif" alt="comments" /></a> |
68− <a href="/search/narcos-season-2/7/1.html"><img style="vertical-align:middle" src="/images/ver.gif" alt="verified" /></a>
69− </span>
70− <a href="/search/narcos-season-2/1/1.html">Torrent name</a></th><th class="right"><a href="/search/narcos-season-2/2/1.html">Age</a></th><th class="right"><a href="/search/narcos-season-2/3/1.html">Size</a></th><th class="right"><a href="/search/narcos-season-2/4/1.html">Seeds</a></th><th class="right"><a href="/search/narcos-season-2/5/1.html">Peers</a></th><th class="center"><a href="/search/narcos-season-2/6/1.html">Health</a></th></tr><tr class=""><td><small class="comments"><a href="http://www.facebook.com/sharer.php?t=Download%20<strong class='colored'>Narcos</strong> <strong class='colored'>Season</strong> <strong class='colored'>2</strong> Complete 7<strong class='colored'>2</strong>0p WebRip EN-SUB x<strong class='colored'>2</strong>64-[MULVAcoded] S0<strong class='colored'>2</strong>%20 torrent&u=http://seedpeer.seedpeer.eu/details/11686840/Narcos-Season-2-Complete-720p-WebRip-EN-SUB-x264-[MULVAcoded]-S02.html"><img src="/images/facebook.png" alt="Add to Facebook" width="14" height="14" /></a></small><a href="/details/11686840/Narcos-Season-2-Complete-720p-WebRip-EN-SUB-x264-[MULVAcoded]-S02.html"><strong class='colored'>Narcos</strong> <strong class='colored'>Season</strong> <strong class='colored'>2</strong> Complete 7<strong class='colored'>2</strong>0p WebRip EN-SUB x<strong class='colored'>2</strong>64-[MULVAcoded] S0<strong class='colored'>2</strong> <small><a href="/browse.html#11686840"></a></small></a></td><td class="right">19 hours</td><td class="right">4.39 GB</td><td class="right"><font color="green">715</font> </td><td class="right"><font color="navy">183</font> </td><td class="center"><img src="/images/h5.gif" alt="Health" width="40" height="11" /></td></tr><tr class="tdark"><td><small class="comments"><a href="http://www.facebook.com/sharer.php?t=Download%20<strong class='colored'>Narcos</strong> - <strong class='colored'>Season</strong> <strong class='colored'>2</strong> - 7<strong class='colored'>2</strong>0p WEBRiP - x<strong class='colored'>2</strong>65 HEVC - ShAaNiG%20 torrent&u=http://seedpeer.seedpeer.eu/details/11685972/Narcos---Season-2---720p-WEBRiP---x265-HEVC---ShAaNiG.html"><img src="/images/facebook.png" alt="Add to Facebook" width="14" height="14" /></a></small><a href="/details/11685972/Narcos---Season-2---720p-WEBRiP---x265-HEVC---ShAaNiG.html"><strong class='colored'>Narcos</strong> - <strong class='colored'>Season</strong> <strong class='colored'>2</strong> - 7<strong class='colored'>2</strong>0p WEBRiP - x<strong class='colored'>2</strong>65 HEVC - ShAaNiG <small><a href="/browse.html#11685972"></a></small></a></td><td class="right">1 day</td><td class="right">2.48 GB</td><td class="right"><font color="green">861</font> </td><td class="right"><font color="navy">332</font> </td><td class="center"><img src="/images/h5.gif" alt="Health" width="40" height="11" /></td></tr></table><div id="headerbox"><h1>Related searches for: <font class="colored">Narcos season 2</font></h1></div><div id="search_suggestions"><br />Other suggested searches: </div><br /><a href="http://torrentz2.eu/search?f=narcos-season-2">Search for "narcos-season-2" on Torrentz2.eu</a><br /><a href="http://torrent-finder.info/show.php?q=narcos-season-2">Search for "narcos-season-2" on Torrent-Finder</a><br /><center><iframe src='http://creative.wwwpromoter.com/13689?d=300x250' width='300' height='250' style='border: none;' frameborder='0' scrolling='no'></iframe>&nbsp;<iframe src='http://creative.wwwpromoter.com/13689?d=300x250' width='300' height='250' style='border: none;' frameborder='0' scrolling='no'></iframe>&nbsp;<iframe src='http://creative.wwwpromoter.com/13689?d=300x250' width='300' height='250' style='border: none;' frameborder='0' scrolling='no'></iframe></center><div id="footer">
71− <table width="100%">
72− <tr>
73− <td width="30%">
74− <h2>Torrents Download</h2>
75− <a href="/">Torrent search</a><br />
76− <a href="/browse.html">Browse categories</a><br />
77− <a href="/verified.html">Verified Torrents</a><br />
78− <a href="/order-date.html">Today's torrents</a><br />
79− <a href="/yesterday.html">Yesterday's torrents</a><br />
80− <a href="/stats.html">Statistics</a><br />
81− <br />
82− <a href="/faq.html#copyright"><strong>Copyright & Removal</strong></a>
83− </td>
84− <td width="30%"><h2>Cool Stuff</h2>
85− <a href="/promotional.php">Promotional</a><br />
86− <a href="/contact.html">Advertising Information</a><br />
87− <strong><a href="/plugins.php" title="Add a search plugin to Firefox or Internet Explorer">Search Plugin <span style="color:red">*</span></a></strong><br />
88− <a href="http://www.utorrent.com">&micro;Torrent Client</a><br />
89− <a href="/blog">Seedpeer Blog</a><br />
90− </td>
91− <td width="30%"><h2>Links</h2>
92− <a href="http://www.sumotorrent.com" target="_blank"><strong>SumoTorrent</strong></a><br />
93− <a href="http://www.torrent-finder.info" target="_blank"><strong>Torrent Finder</strong></a><br />
94− <a href="http://www.torrentpond.com" target="_blank"><strong>TorrentPond</strong></a><br />
95− <a href="https://www.limetorrents.cc" target="_blank">LimeTorrents.cc</a><br />
96− <a href="http://www.torrents.to/" target="_blank">Torrents.to</a><br />
97− <a href="http://www.torrentfunk.com" target="_blank">TorrentFunk</a><br />
98− <a href="https://monova.org" target="_blank">Monova</a><br />
99− <a href="http://www.torrentroom.com" target="_blank">TorrentRoom</a><br />
100− <a href="http://www.katcr.co/" target="_blank">Kickass Torrents Community</a><br />
101− </td>
102− <td width="10%"><div id="bottomlogo"></div></td>
103− </tr>
104− </table>
105− <br />
106− <br />
107− </div>
108− </div>
109− </body>
110− </html>
tests/unit/engines/test_acgsou.pydeleted−78
@@ -1,78 +0,0 @@
1−# coding=utf-8
2−from collections import defaultdict
3−import mock
4−from searx.engines import acgsou
5−from searx.testing import SearxTestCase
6−
7−
8−class TestAcgsouEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dic = defaultdict(dict)
13− dic['pageno'] = 1
14− params = acgsou.request(query, dic)
15− self.assertTrue('url' in params)
16− self.assertTrue(query in params['url'])
17− self.assertTrue('acgsou.com' in params['url'])
18−
19− def test_response(self):
20− resp = mock.Mock(text='<html></html>')
21− self.assertEqual(acgsou.response(resp), [])
22−
23− html = u"""
24− <html>
25−<table id="listTable" class="list_style table_fixed">
26− <thead class="tcat">
27− <tr>
28− <th axis="string" class="l1 tableHeaderOver">test</th>
29− <th axis="string" class="l2 tableHeaderOver">test</th>
30− <th axis="string" class="l3 tableHeaderOver">test</th>
31− <th axis="size" class="l4 tableHeaderOver">test</th>
32− <th axis="number" class="l5 tableHeaderOver">test</th>
33− <th axis="number" class="l6 tableHeaderOver">test</th>
34− <th axis="number" class="l7 tableHeaderOver">test</th>
35− <th axis="string" class="l8 tableHeaderOver">test</th>
36− </tr>
37− </thead>
38− <tbody class="tbody" id="data_list">
39− <tr class="alt1 ">
40− <td nowrap="nowrap">date</td>
41− <td><a href="category.html">testcategory テスト</a></td>
42− <td style="text-align:left;">
43− <a href="show-torrentid.html" target="_blank">torrentname テスト</a>
44− </td>
45− <td>1MB</td>
46− <td nowrap="nowrap">
47− <span class="bts_1">
48− 29
49− </span>
50− </td>
51− <td nowrap="nowrap">
52− <span class="btl_1">
53− 211
54− </span>
55− </td>
56− <td nowrap="nowrap">
57− <span class="btc_">
58− 168
59− </span>
60− </td>
61− <td><a href="random.html">user</a></td>
62− </tr>
63− </tbody>
64−</table>
65−</html>
66− """
67−
68− resp = mock.Mock(text=html)
69− results = acgsou.response(resp)
70−
71− self.assertEqual(type(results), list)
72− self.assertEqual(len(results), 1)
73−
74− r = results[0]
75− self.assertEqual(r['url'], 'http://www.acgsou.com/show-torrentid.html')
76− self.assertEqual(r['content'], u'Category: "testcategory テスト".')
77− self.assertEqual(r['title'], u'torrentname テスト')
78− self.assertEqual(r['filesize'], 1048576)
tests/unit/engines/test_archlinux.pydeleted−111
@@ -1,111 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import archlinux
4−from searx.testing import SearxTestCase
5−
6−domains = {
7− 'all': 'https://wiki.archlinux.org',
8− 'de': 'https://wiki.archlinux.de',
9− 'fr': 'https://wiki.archlinux.fr',
10− 'ja': 'https://wiki.archlinuxjp.org',
11− 'ro': 'http://wiki.archlinux.ro',
12− 'tr': 'http://archtr.org/wiki'
13−}
14−
15−
16−class TestArchLinuxEngine(SearxTestCase):
17−
18− def test_request(self):
19− query = 'test_query'
20− dic = defaultdict(dict)
21− dic['pageno'] = 1
22− dic['language'] = 'en-US'
23− params = archlinux.request(query, dic)
24− self.assertTrue('url' in params)
25− self.assertTrue(query in params['url'])
26− self.assertTrue('wiki.archlinux.org' in params['url'])
27−
28− for lang, name in archlinux.main_langs:
29− dic['language'] = lang
30− params = archlinux.request(query, dic)
31− self.assertTrue(name in params['url'])
32−
33− for lang, domain in domains.items():
34− dic['language'] = lang
35− params = archlinux.request(query, dic)
36− self.assertTrue(domain in params['url'])
37−
38− def test_response(self):
39− response = mock.Mock(text='<html></html>',
40− search_params={'language': 'en_US'})
41− self.assertEqual(archlinux.response(response), [])
42−
43− html = """
44− <ul class="mw-search-results">
45− <li>
46− <div class="mw-search-result-heading">
47− <a href="/index.php/ATI" title="ATI">ATI</a>
48− </div>
49− <div class="searchresult">
50− Lorem ipsum dolor sit amet
51− </div>
52− <div class="mw-search-result-data">
53− 30 KB (4,630 words) - 19:04, 17 March 2016</div>
54− </li>
55− <li>
56− <div class="mw-search-result-heading">
57− <a href="/index.php/Frequently_asked_questions" title="Frequently asked questions">
58− Frequently asked questions
59− </a>
60− </div>
61− <div class="searchresult">
62− CPUs with AMDs instruction set "AMD64"
63− </div>
64− <div class="mw-search-result-data">
65− 17 KB (2,722 words) - 20:13, 21 March 2016
66− </div>
67− </li>
68− <li>
69− <div class="mw-search-result-heading">
70− <a href="/index.php/CPU_frequency_scaling" title="CPU frequency scaling">CPU frequency scaling</a>
71− </div>
72− <div class="searchresult">
73− ondemand for AMD and older Intel CPU
74− </div>
75− <div class="mw-search-result-data">
76− 15 KB (2,319 words) - 23:46, 16 March 2016
77− </div>
78− </li>
79− </ul>
80− """
81−
82− expected = [
83− {
84− 'title': 'ATI',
85− 'url': 'https://wiki.archlinux.org/index.php/ATI'
86− },
87− {
88− 'title': 'Frequently asked questions',
89− 'url': 'https://wiki.archlinux.org/index.php/Frequently_asked_questions'
90− },
91− {
92− 'title': 'CPU frequency scaling',
93− 'url': 'https://wiki.archlinux.org/index.php/CPU_frequency_scaling'
94− }
95− ]
96−
97− response = mock.Mock(text=html)
98− response.search_params = {
99− 'language': 'en_US'
100− }
101− results = archlinux.response(response)
102−
103− self.assertEqual(type(results), list)
104− self.assertEqual(len(results), len(expected))
105−
106− i = 0
107− for exp in expected:
108− res = results[i]
109− i += 1
110− for key, value in exp.items():
111− self.assertEqual(res[key], value)
tests/unit/engines/test_arxiv.pydeleted−58
@@ -1,58 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import arxiv
5−from searx.testing import SearxTestCase
6−
7−
8−class TestBaseEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dicto = defaultdict(dict)
13− dicto['pageno'] = 1
14− params = arxiv.request(query, dicto)
15− self.assertIn('url', params)
16− self.assertIn('export.arxiv.org/api/', params['url'])
17−
18− def test_response(self):
19− self.assertRaises(AttributeError, arxiv.response, None)
20− self.assertRaises(AttributeError, arxiv.response, [])
21− self.assertRaises(AttributeError, arxiv.response, '')
22− self.assertRaises(AttributeError, arxiv.response, '[]')
23−
24− response = mock.Mock(content=b'''<?xml version="1.0" encoding="UTF-8"?>
25−<feed xmlns="http://www.w3.org/2005/Atom"></feed>''')
26− self.assertEqual(arxiv.response(response), [])
27−
28− xml_mock = b'''<?xml version="1.0" encoding="UTF-8"?>
29−<feed xmlns="http://www.w3.org/2005/Atom">
30− <title type="html">ArXiv Query: search_query=all:test_query&amp;id_list=&amp;start=0&amp;max_results=1</title>
31− <id>http://arxiv.org/api/1</id>
32− <updated>2000-01-21T00:00:00-01:00</updated>
33− <opensearch:totalResults xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">1</opensearch:totalResults>
34− <opensearch:startIndex xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">0</opensearch:startIndex>
35− <opensearch:itemsPerPage xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">1</opensearch:itemsPerPage>
36− <entry>
37− <id>http://arxiv.org/1</id>
38− <updated>2000-01-01T00:00:01Z</updated>
39− <published>2000-01-01T00:00:01Z</published>
40− <title>Mathematical proof.</title>
41− <summary>Mathematical formula.</summary>
42− <author>
43− <name>A. B.</name>
44− </author>
45− <link href="http://arxiv.org/1" rel="alternate" type="text/html"/>
46− <link title="pdf" href="http://arxiv.org/1" rel="related" type="application/pdf"/>
47− <category term="math.QA" scheme="http://arxiv.org/schemas/atom"/>
48− <category term="1" scheme="http://arxiv.org/schemas/atom"/>
49− </entry>
50−</feed>
51−'''
52−
53− response = mock.Mock(content=xml_mock)
54− results = arxiv.response(response)
55− self.assertEqual(type(results), list)
56− self.assertEqual(len(results), 1)
57− self.assertEqual(results[0]['title'], 'Mathematical proof.')
58− self.assertEqual(results[0]['content'], 'Mathematical formula.')
tests/unit/engines/test_base.pydeleted−91
@@ -1,91 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import base
5−from searx.testing import SearxTestCase
6−
7−
8−class TestBaseEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dicto = defaultdict(dict)
13− dicto['pageno'] = 1
14− params = base.request(query, dicto)
15− self.assertIn('url', params)
16− self.assertIn('base-search.net', params['url'])
17−
18− def test_response(self):
19− self.assertRaises(AttributeError, base.response, None)
20− self.assertRaises(AttributeError, base.response, [])
21− self.assertRaises(AttributeError, base.response, '')
22− self.assertRaises(AttributeError, base.response, '[]')
23−
24− response = mock.Mock(content=b'<response></response>')
25− self.assertEqual(base.response(response), [])
26−
27− xml_mock = b"""<?xml version="1.0"?>
28−<response>
29− <lst name="responseHeader">
30− <int name="status">0</int>
31− <int name="QTime">1</int>
32− </lst>
33− <result name="response" numFound="1" start="0">
34− <doc>
35− <date name="dchdate">2000-01-01T01:01:01Z</date>
36− <str name="dcdocid">1</str>
37− <str name="dccontinent">cna</str>
38− <str name="dccountry">us</str>
39− <str name="dccollection">ftciteseerx</str>
40− <str name="dcprovider">CiteSeerX</str>
41− <str name="dctitle">Science and more</str>
42− <arr name="dccreator">
43− <str>Someone</str>
44− </arr>
45− <arr name="dcperson">
46− <str>Someone</str>
47− </arr>
48− <arr name="dcsubject">
49− <str>Science and more</str>
50− </arr>
51− <str name="dcdescription">Science, and even more.</str>
52− <arr name="dccontributor">
53− <str>The neighbour</str>
54− </arr>
55− <str name="dcdate">2001</str>
56− <int name="dcyear">2001</int>
57− <arr name="dctype">
58− <str>text</str>
59− </arr>
60− <arr name="dctypenorm">
61− <str>1</str>
62− </arr>
63− <arr name="dcformat">
64− <str>application/pdf</str>
65− </arr>
66− <arr name="dccontenttype">
67− <str>application/pdf</str>
68− </arr>
69− <arr name="dcidentifier">
70− <str>http://example.org/</str>
71− </arr>
72− <str name="dclink">http://example.org</str>
73− <str name="dcsource">http://example.org</str>
74− <arr name="dclanguage">
75− <str>en</str>
76− </arr>
77− <str name="dcrights">Under the example.org licence</str>
78− <int name="dcoa">1</int>
79− <arr name="dclang">
80− <str>eng</str>
81− </arr>
82− </doc>
83− </result>
84−</response>"""
85−
86− response = mock.Mock(content=xml_mock)
87− results = base.response(response)
88− self.assertEqual(type(results), list)
89− self.assertEqual(len(results), 1)
90− self.assertEqual(results[0]['title'], 'Science and more')
91− self.assertEqual(results[0]['content'], 'Science, and even more.')
tests/unit/engines/test_bing.pydeleted−121
@@ -1,121 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import bing
4−from searx.testing import SearxTestCase
5−
6−
7−class TestBingEngine(SearxTestCase):
8−
9− def test_request(self):
10− bing.supported_languages = ['en', 'fr', 'zh-CHS', 'zh-CHT', 'pt-PT', 'pt-BR']
11− query = u'test_query'
12− dicto = defaultdict(dict)
13− dicto['pageno'] = 0
14− dicto['language'] = 'fr-FR'
15− params = bing.request(query.encode('utf-8'), dicto)
16− self.assertTrue('url' in params)
17− self.assertTrue(query in params['url'])
18− self.assertTrue('language%3AFR' in params['url'])
19− self.assertTrue('bing.com' in params['url'])
20−
21− dicto['language'] = 'all'
22− params = bing.request(query.encode('utf-8'), dicto)
23− self.assertTrue('language' in params['url'])
24−
25− def test_response(self):
26− self.assertRaises(AttributeError, bing.response, None)
27− self.assertRaises(AttributeError, bing.response, [])
28− self.assertRaises(AttributeError, bing.response, '')
29− self.assertRaises(AttributeError, bing.response, '[]')
30−
31− response = mock.Mock(text='<html></html>')
32− self.assertEqual(bing.response(response), [])
33−
34− response = mock.Mock(text='<html></html>')
35− self.assertEqual(bing.response(response), [])
36−
37− html = """
38− <div class="sa_cc" u="0|5109|4755453613245655|UAGjXgIrPH5yh-o5oNHRx_3Zta87f_QO">
39− <div Class="sa_mc">
40− <div class="sb_tlst">
41− <h3>
42− <a href="http://this.should.be.the.link/" h="ID=SERP,5124.1">
43− <strong>This</strong> should be the title</a>
44− </h3>
45− </div>
46− <div class="sb_meta"><cite><strong>this</strong>.meta.com</cite>
47− <span class="c_tlbxTrg">
48− <span class="c_tlbxH" H="BASE:CACHEDPAGEDEFAULT" K="SERP,5125.1">
49− </span>
50− </span>
51− </div>
52− <p><strong>This</strong> should be the content.</p>
53− </div>
54− </div>
55− """
56− response = mock.Mock(text=html)
57− results = bing.response(response)
58− self.assertEqual(type(results), list)
59− self.assertEqual(len(results), 1)
60− self.assertEqual(results[0]['title'], 'This should be the title')
61− self.assertEqual(results[0]['url'], 'http://this.should.be.the.link/')
62− self.assertEqual(results[0]['content'], 'This should be the content.')
63−
64− html = """
65− <li class="b_algo" u="0|5109|4755453613245655|UAGjXgIrPH5yh-o5oNHRx_3Zta87f_QO">
66− <div Class="sa_mc">
67− <div class="sb_tlst">
68− <h2>
69− <a href="http://this.should.be.the.link/" h="ID=SERP,5124.1">
70− <strong>This</strong> should be the title</a>
71− </h2>
72− </div>
73− <div class="sb_meta"><cite><strong>this</strong>.meta.com</cite>
74− <span class="c_tlbxTrg">
75− <span class="c_tlbxH" H="BASE:CACHEDPAGEDEFAULT" K="SERP,5125.1">
76− </span>
77− </span>
78− </div>
79− <p><strong>This</strong> should be the content.</p>
80− </div>
81− </li>
82− """
83− response = mock.Mock(text=html)
84− results = bing.response(response)
85− self.assertEqual(type(results), list)
86− self.assertEqual(len(results), 1)
87− self.assertEqual(results[0]['title'], 'This should be the title')
88− self.assertEqual(results[0]['url'], 'http://this.should.be.the.link/')
89− self.assertEqual(results[0]['content'], 'This should be the content.')
90−
91− def test_fetch_supported_languages(self):
92− html = """<html></html>"""
93− response = mock.Mock(text=html)
94− results = bing._fetch_supported_languages(response)
95− self.assertEqual(type(results), list)
96− self.assertEqual(len(results), 0)
97−
98− html = """
99− <html>
100− <body>
101− <form>
102− <div id="limit-languages">
103− <div>
104− <div><input id="es" value="es"></input></div>
105− </div>
106− <div>
107− <div><input id="pt_BR" value="pt_BR"></input></div>
108− <div><input id="pt_PT" value="pt_PT"></input></div>
109− </div>
110− </div>
111− </form>
112− </body>
113− </html>
114− """
115− response = mock.Mock(text=html)
116− languages = bing._fetch_supported_languages(response)
117− self.assertEqual(type(languages), list)
118− self.assertEqual(len(languages), 3)
119− self.assertIn('es', languages)
120− self.assertIn('pt-BR', languages)
121− self.assertIn('pt-PT', languages)
tests/unit/engines/test_bing_images.pydeleted−132
@@ -1,132 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import bing_images
5−from searx.testing import SearxTestCase
6−
7−
8−class TestBingImagesEngine(SearxTestCase):
9−
10− def test_request(self):
11− bing_images.supported_languages = ['fr-FR', 'en-US']
12− bing_images.language_aliases = {}
13− query = 'test_query'
14− dicto = defaultdict(dict)
15− dicto['pageno'] = 1
16− dicto['language'] = 'fr-FR'
17− dicto['safesearch'] = 1
18− dicto['time_range'] = ''
19− params = bing_images.request(query, dicto)
20− self.assertTrue('url' in params)
21− self.assertTrue(query in params['url'])
22− self.assertTrue('bing.com' in params['url'])
23− self.assertTrue('SRCHHPGUSR' in params['cookies'])
24− self.assertTrue('DEMOTE' in params['cookies']['SRCHHPGUSR'])
25− self.assertTrue('_EDGE_S' in params['cookies'])
26− self.assertTrue('fr-fr' in params['cookies']['_EDGE_S'])
27−
28− dicto['language'] = 'fr'
29− params = bing_images.request(query, dicto)
30− self.assertTrue('_EDGE_S' in params['cookies'])
31− self.assertTrue('fr-fr' in params['cookies']['_EDGE_S'])
32−
33− dicto['language'] = 'all'
34− params = bing_images.request(query, dicto)
35− self.assertTrue('_EDGE_S' in params['cookies'])
36− self.assertTrue('en-us' in params['cookies']['_EDGE_S'])
37−
38− def test_response(self):
39− self.assertRaises(AttributeError, bing_images.response, None)
40− self.assertRaises(AttributeError, bing_images.response, [])
41− self.assertRaises(AttributeError, bing_images.response, '')
42− self.assertRaises(AttributeError, bing_images.response, '[]')
43−
44− response = mock.Mock(text='<html></html>')
45− self.assertEqual(bing_images.response(response), [])
46−
47− response = mock.Mock(text='<html></html>')
48− self.assertEqual(bing_images.response(response), [])
49−
50− html = """
51− <div id="mmComponent_images_1">
52− <ul>
53− <li>
54− <div>
55− <div class="imgpt">
56− <a m='{"purl":"page_url","murl":"img_url","turl":"thumb_url","t":"Page 1 title"}'>
57− <img src="" alt="alt text" />
58− </a>
59− <div class="img_info">
60− <span>1 x 1 - jpeg</span>
61− <a>1.example.org</a>
62− </div>
63− </div>
64− <div></div>
65− </div>
66− <div>
67− <div class="imgpt">
68− <a m='{"purl":"page_url2","murl":"img_url2","turl":"thumb_url2","t":"Page 2 title"}'>
69− <img src="" alt="alt text 2" />
70− </a>
71− <div class="img_info">
72− <span>2 x 2 - jpeg</span>
73− <a>2.example.org</a>
74− </div>
75− </div>
76− </div>
77− </li>
78− </ul>
79− <ul>
80− <li>
81− <div>
82− <div class="imgpt">
83− <a m='{"purl":"page_url3","murl":"img_url3","turl":"thumb_url3","t":"Page 3 title"}'>
84− <img src="" alt="alt text 3" />
85− </a>
86− <div class="img_info">
87− <span>3 x 3 - jpeg</span>
88− <a>3.example.org</a>
89− </div>
90− </div>
91− </div>
92− </li>
93− </ul>
94− </div>
95− """
96− html = html.replace('\r\n', '').replace('\n', '').replace('\r', '')
97− response = mock.Mock(text=html)
98− results = bing_images.response(response)
99− self.assertEqual(type(results), list)
100− self.assertEqual(len(results), 3)
101− self.assertEqual(results[0]['title'], 'Page 1 title')
102− self.assertEqual(results[0]['url'], 'page_url')
103− self.assertEqual(results[0]['content'], '')
104− self.assertEqual(results[0]['thumbnail_src'], 'thumb_url')
105− self.assertEqual(results[0]['img_src'], 'img_url')
106− self.assertEqual(results[0]['img_format'], '1 x 1 - jpeg')
107− self.assertEqual(results[0]['source'], '1.example.org')
108−
109− def test_fetch_supported_languages(self):
110− html = """
111− <div>
112− <div id="region-section-content">
113− <ul class="b_vList">
114− <li>
115− <a href="https://bing...&setmkt=de-DE&s...">Germany</a>
116− <a href="https://bing...&setmkt=nb-NO&s...">Norway</a>
117− </li>
118− </ul>
119− <ul class="b_vList">
120− <li>
121− <a href="https://bing...&setmkt=es-AR&s...">Argentina</a>
122− </li>
123− </ul>
124− </div>
125− </div>
126− """
127− response = mock.Mock(text=html)
128− languages = list(bing_images._fetch_supported_languages(response))
129− self.assertEqual(len(languages), 3)
130− self.assertIn('de-DE', languages)
131− self.assertIn('no-NO', languages)
132− self.assertIn('es-AR', languages)
tests/unit/engines/test_bing_news.pydeleted−147
@@ -1,147 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import bing_news
4−from searx.testing import SearxTestCase
5−import lxml
6−
7−
8−class TestBingNewsEngine(SearxTestCase):
9−
10− def test_request(self):
11− bing_news.supported_languages = ['en', 'fr']
12− query = 'test_query'
13− dicto = defaultdict(dict)
14− dicto['pageno'] = 1
15− dicto['language'] = 'fr-FR'
16− dicto['time_range'] = ''
17− params = bing_news.request(query, dicto)
18− self.assertIn('url', params)
19− self.assertIn(query, params['url'])
20− self.assertIn('bing.com', params['url'])
21− self.assertIn('fr', params['url'])
22−
23− dicto['language'] = 'all'
24− params = bing_news.request(query, dicto)
25− self.assertIn('en', params['url'])
26−
27− def test_no_url_in_request_year_time_range(self):
28− dicto = defaultdict(dict)
29− query = 'test_query'
30− dicto['time_range'] = 'year'
31− params = bing_news.request(query, dicto)
32− self.assertEqual({}, params['url'])
33−
34− def test_response(self):
35− self.assertRaises(AttributeError, bing_news.response, None)
36− self.assertRaises(AttributeError, bing_news.response, [])
37− self.assertRaises(AttributeError, bing_news.response, '')
38− self.assertRaises(AttributeError, bing_news.response, '[]')
39−
40− response = mock.Mock(content='<html></html>')
41− self.assertEqual(bing_news.response(response), [])
42−
43− response = mock.Mock(content='<html></html>')
44− self.assertEqual(bing_news.response(response), [])
45−
46− html = """<?xml version="1.0" encoding="utf-8" ?>
47−<rss version="2.0" xmlns:News="https://www.bing.com:443/news/search?q=python&amp;setmkt=en-US&amp;first=1&amp;format=RSS">
48− <channel>
49− <title>python - Bing News</title>
50− <link>https://www.bing.com:443/news/search?q=python&amp;setmkt=en-US&amp;first=1&amp;format=RSS</link>
51− <description>Search results</description>
52− <image>
53− <url>http://10.53.64.9/rsslogo.gif</url>
54− <title>test</title>
55− <link>https://www.bing.com:443/news/search?q=test&amp;setmkt=en-US&amp;first=1&amp;format=RSS</link>
56− </image>
57− <copyright>Copyright</copyright>
58− <item>
59− <title>Title</title>
60− <link>https://www.bing.com/news/apiclick.aspx?ref=FexRss&amp;aid=&amp;tid=c237eccc50bd4758b106a5e3c94fce09&amp;url=http%3a%2f%2furl.of.article%2f&amp;c=xxxxxxxxx&amp;mkt=en-us</link>
61− <description>Article Content</description>
62− <pubDate>Tue, 02 Jun 2015 13:37:00 GMT</pubDate>
63− <News:Source>Infoworld</News:Source>
64− <News:Image>http://a1.bing4.com/th?id=ON.13371337133713371337133713371337&amp;pid=News</News:Image>
65− <News:ImageSize>w={0}&amp;h={1}&amp;c=7</News:ImageSize>
66− <News:ImageKeepOriginalRatio></News:ImageKeepOriginalRatio>
67− <News:ImageMaxWidth>620</News:ImageMaxWidth>
68− <News:ImageMaxHeight>413</News:ImageMaxHeight>
69− </item>
70− <item>
71− <title>Another Title</title>
72− <link>https://www.bing.com/news/apiclick.aspx?ref=FexRss&amp;aid=&amp;tid=c237eccc50bd4758b106a5e3c94fce09&amp;url=http%3a%2f%2fanother.url.of.article%2f&amp;c=xxxxxxxxx&amp;mkt=en-us</link>
73− <description>Another Article Content</description>
74− <pubDate>Tue, 02 Jun 2015 13:37:00 GMT</pubDate>
75− </item>
76− </channel>
77−</rss>""" # noqa
78− response = mock.Mock(content=html.encode('utf-8'))
79− results = bing_news.response(response)
80− self.assertEqual(type(results), list)
81− self.assertEqual(len(results), 2)
82− self.assertEqual(results[0]['title'], 'Title')
83− self.assertEqual(results[0]['url'], 'http://url.of.article/')
84− self.assertEqual(results[0]['content'], 'Article Content')
85− self.assertEqual(results[0]['img_src'], 'https://www.bing.com/th?id=ON.13371337133713371337133713371337')
86− self.assertEqual(results[1]['title'], 'Another Title')
87− self.assertEqual(results[1]['url'], 'http://another.url.of.article/')
88− self.assertEqual(results[1]['content'], 'Another Article Content')
89− self.assertNotIn('img_src', results[1])
90−
91− html = """<?xml version="1.0" encoding="utf-8" ?>
92−<rss version="2.0" xmlns:News="https://www.bing.com:443/news/search?q=python&amp;setmkt=en-US&amp;first=1&amp;format=RSS">
93− <channel>
94− <title>python - Bing News</title>
95− <link>https://www.bing.com:443/news/search?q=python&amp;setmkt=en-US&amp;first=1&amp;format=RSS</link>
96− <description>Search results</description>
97− <image>
98− <url>http://10.53.64.9/rsslogo.gif</url>
99− <title>test</title>
100− <link>https://www.bing.com:443/news/search?q=test&amp;setmkt=en-US&amp;first=1&amp;format=RSS</link>
101− </image>
102− <copyright>Copyright</copyright>
103− <item>
104− <title>Title</title>
105− <link>http://another.url.of.article/</link>
106− <description>Article Content</description>
107− <pubDate>garbage</pubDate>
108− <News:Source>Infoworld</News:Source>
109− <News:Image>http://another.bing.com/image</News:Image>
110− <News:ImageSize>w={0}&amp;h={1}&amp;c=7</News:ImageSize>
111− <News:ImageKeepOriginalRatio></News:ImageKeepOriginalRatio>
112− <News:ImageMaxWidth>620</News:ImageMaxWidth>
113− <News:ImageMaxHeight>413</News:ImageMaxHeight>
114− </item>
115− </channel>
116−</rss>""" # noqa
117− response = mock.Mock(content=html.encode('utf-8'))
118− results = bing_news.response(response)
119− self.assertEqual(type(results), list)
120− self.assertEqual(len(results), 1)
121− self.assertEqual(results[0]['title'], 'Title')
122− self.assertEqual(results[0]['url'], 'http://another.url.of.article/')
123− self.assertEqual(results[0]['content'], 'Article Content')
124− self.assertEqual(results[0]['img_src'], 'http://another.bing.com/image')
125−
126− html = """<?xml version="1.0" encoding="utf-8" ?>
127−<rss version="2.0" xmlns:News="https://www.bing.com:443/news/search?q=python&amp;setmkt=en-US&amp;first=1&amp;format=RSS">
128− <channel>
129− <title>python - Bing News</title>
130− <link>https://www.bing.com:443/news/search?q=python&amp;setmkt=en-US&amp;first=1&amp;format=RSS</link>
131− <description>Search results</description>
132− <image>
133− <url>http://10.53.64.9/rsslogo.gif</url>
134− <title>test</title>
135− <link>https://www.bing.com:443/news/search?q=test&amp;setmkt=en-US&amp;first=1&amp;format=RSS</link>
136− </image>
137− </channel>
138−</rss>""" # noqa
139−
140− response = mock.Mock(content=html.encode('utf-8'))
141− results = bing_news.response(response)
142− self.assertEqual(type(results), list)
143− self.assertEqual(len(results), 0)
144−
145− html = """<?xml version="1.0" encoding="utf-8" ?>gabarge"""
146− response = mock.Mock(content=html.encode('utf-8'))
147− self.assertRaises(lxml.etree.XMLSyntaxError, bing_news.response, response)
tests/unit/engines/test_bing_videos.pydeleted−72
@@ -1,72 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import bing_videos
5−from searx.testing import SearxTestCase
6−
7−
8−class TestBingVideosEngine(SearxTestCase):
9−
10− def test_request(self):
11− bing_videos.supported_languages = ['fr-FR', 'en-US']
12− bing_videos.language_aliases = {}
13− query = 'test_query'
14− dicto = defaultdict(dict)
15− dicto['pageno'] = 1
16− dicto['language'] = 'fr-FR'
17− dicto['safesearch'] = 0
18− dicto['time_range'] = ''
19− params = bing_videos.request(query, dicto)
20− self.assertTrue('url' in params)
21− self.assertTrue(query in params['url'])
22− self.assertTrue('bing.com' in params['url'])
23− self.assertTrue('SRCHHPGUSR' in params['cookies'])
24− self.assertTrue('OFF' in params['cookies']['SRCHHPGUSR'])
25− self.assertTrue('_EDGE_S' in params['cookies'])
26− self.assertTrue('fr-fr' in params['cookies']['_EDGE_S'])
27−
28− dicto['pageno'] = 2
29− dicto['time_range'] = 'day'
30− dicto['safesearch'] = 2
31− params = bing_videos.request(query, dicto)
32− self.assertTrue('first=29' in params['url'])
33− self.assertTrue('1440' in params['url'])
34− self.assertIn('SRCHHPGUSR', params['cookies'])
35− self.assertTrue('STRICT' in params['cookies']['SRCHHPGUSR'])
36−
37− def test_response(self):
38− self.assertRaises(AttributeError, bing_videos.response, None)
39− self.assertRaises(AttributeError, bing_videos.response, [])
40− self.assertRaises(AttributeError, bing_videos.response, '')
41− self.assertRaises(AttributeError, bing_videos.response, '[]')
42−
43− response = mock.Mock(text='<html></html>')
44− self.assertEqual(bing_videos.response(response), [])
45−
46− response = mock.Mock(text='<html></html>')
47− self.assertEqual(bing_videos.response(response), [])
48−
49− html = """
50− <div class="dg_u">
51− <div>
52− <a>
53− <div>
54− <div>
55− <div class="mc_vtvc_meta_block">
56− <div><span>100 views</span><span>1 year ago</span></div><div><span>ExampleTube</span><span>Channel 1<span></div> #noqa
57− </div>
58− </div>
59− <div class="vrhdata" vrhm='{"du":"01:11","murl":"https://www.example.com/watch?v=DEADBEEF","thid":"OVP.BINGTHUMB1","vt":"Title 1"}'></div> # noqa
60− </div>
61− </a>
62− </div>
63− </div>
64− """
65− response = mock.Mock(text=html)
66− results = bing_videos.response(response)
67− self.assertEqual(type(results), list)
68− self.assertEqual(len(results), 1)
69− self.assertEqual(results[0]['title'], 'Title 1')
70− self.assertEqual(results[0]['url'], 'https://www.example.com/watch?v=DEADBEEF')
71− self.assertEqual(results[0]['content'], '01:11 - 100 views - 1 year ago - ExampleTube - Channel 1')
72− self.assertEqual(results[0]['thumbnail'], 'https://www.bing.com/th?id=OVP.BINGTHUMB1')
tests/unit/engines/test_btdigg.pydeleted−112
@@ -1,112 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import btdigg
5−from searx.testing import SearxTestCase
6−
7−
8−class TestBtdiggEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dicto = defaultdict(dict)
13− dicto['pageno'] = 0
14− params = btdigg.request(query, dicto)
15− self.assertIn('url', params)
16− self.assertIn(query, params['url'])
17− self.assertIn('btdig.com', params['url'])
18−
19− def test_response(self):
20− self.assertRaises(AttributeError, btdigg.response, None)
21− self.assertRaises(AttributeError, btdigg.response, [])
22− self.assertRaises(AttributeError, btdigg.response, '')
23− self.assertRaises(AttributeError, btdigg.response, '[]')
24−
25− response = mock.Mock(text='<html></html>')
26− self.assertEqual(btdigg.response(response), [])
27−
28− html = u"""
29− <div class="one_result" style="display:table-row;background-color:#e8e8e8">
30− <div style="display:table-cell;color:rgb(0, 0, 0)">
31− <div style="display:table">
32− <div style="display:table-row">
33− <div class="torrent_name" style="display:table-cell">
34− <a style="color:rgb(0, 0, 204);text-decoration:underline;font-size:150%"
35− href="http://btdig.com/a72f35b7ee3a10928f02bb799e40ae5db701ed1c/pdf?q=pdf&amp;p=1&amp;order=0"
36− >3.9GBdeLibrosByHuasoFromHell(3de4)</a>
37− </div>
38− </div>
39− </div>
40− <div style="display:table">
41− <div style="display:table-row">
42− <div style="display:table-cell">
43− <span class="torrent_files" style="color:#666;padding-left:10px">4217</span> files <span
44− class="torrent_size" style="color:#666;padding-left:10px">1 GB</span><span
45− class="torrent_age" style="color:rgb(0, 102, 0);padding-left:10px;margin: 0px 4px"
46− >found 3 years ago</span>
47− </div>
48− </div>
49− </div>
50− <div style="display:table;width:100%;padding:10px">
51− <div style="display:table-row">
52− <div class="torrent_magnet" style="display:table-cell">
53− <div class="fa fa-magnet" style="color:#cc0000">
54− <a href="magnet:?xt=urn:btih:a72f35b7ee3a10928f02bb799e40ae5db701ed1c&amp;dn=3.9GBdeLibrosBy..."
55− title="Download via magnet-link"> magnet:?xt=urn:btih:a72f35b7ee...</a>
56− </div>
57− </div>
58− <div style="display:table-cell;color:rgb(0, 0, 0);text-align:right">
59− <span style="color:rgb(136, 136, 136);margin: 0px 0px 0px 4px"></span><span
60− style="color:rgb(0, 102, 0);margin: 0px 4px">found 3 years ago</span>
61− </div>
62− </div>
63− </div>
64− <div class="torrent_excerpt" style="display:table;padding:10px;white-space:nowrap">
65− <div class="fa fa-folder-open" style="padding-left:0em"> 3.9GBdeLibrosByHuasoFromHell(3de4)</div><br/>
66− <div class="fa fa-folder-open" style="padding-left:1em"> Libros H-Z</div><br/>
67− <div class="fa fa-folder-open" style="padding-left:2em"> H</div><br/><div class="fa fa-file-archive-o"
68− style="padding-left:3em"> H.H. Hollis - El truco de la espada-<b
69− style="color:red; background-color:yellow">pdf</b>.zip</div><span
70− style="color:#666;padding-left:10px">17 KB</span><br/>
71− <div class="fa fa-file-archive-o" style="padding-left:3em"> Hagakure - El Libro del Samurai-<b
72− style="color:red; background-color:yellow">pdf</b>.zip</div><span
73− style="color:#666;padding-left:10px">95 KB</span><br/>
74− <div class="fa fa-folder-open" style="padding-left:3em"> Hamsun, Knut (1859-1952)</div><br/>
75− <div class="fa fa-file-archive-o" style="padding-left:4em"> Hamsun, Knut - Hambre-<b
76− style="color:red; background-color:yellow">pdf</b>.zip</div><span
77− style="color:#666;padding-left:10px">786 KB</span><br/>
78− <div class="fa fa-plus-circle"><a
79− href="http://btdig.com/a72f35b7ee3a10928f02bb799e40ae5db701ed1c/pdf?q=pdf&amp;p=1&amp;order=0"
80− > 4214 hidden files<span style="color:#666;padding-left:10px">1 GB</span></a></div>
81− </div>
82− </div>
83− </div>
84− """
85− response = mock.Mock(text=html.encode('utf-8'))
86− results = btdigg.response(response)
87− self.assertEqual(type(results), list)
88− self.assertEqual(len(results), 1)
89− self.assertEqual(results[0]['title'], '3.9GBdeLibrosByHuasoFromHell(3de4)')
90− self.assertEqual(results[0]['url'],
91− 'http://btdig.com/a72f35b7ee3a10928f02bb799e40ae5db701ed1c/pdf?q=pdf&p=1&order=0')
92− self.assertEqual(results[0]['content'],
93− '3.9GBdeLibrosByHuasoFromHell(3de4) | ' +
94− 'Libros H-Z | ' +
95− 'H H.H. Hollis - El truco de la espada-pdf.zip17 KB | ' +
96− 'Hagakure - El Libro del Samurai-pdf.zip95 KB | ' +
97− 'Hamsun, Knut (1859-1952) | Hamsun, Knut - Hambre-pdf.zip786 KB | ' +
98− '4214 hidden files1 GB')
99− self.assertEqual(results[0]['filesize'], 1 * 1024 * 1024 * 1024)
100− self.assertEqual(results[0]['files'], 4217)
101− self.assertEqual(results[0]['magnetlink'],
102− 'magnet:?xt=urn:btih:a72f35b7ee3a10928f02bb799e40ae5db701ed1c&dn=3.9GBdeLibrosBy...')
103−
104− html = """
105− <div style="display:table-row;background-color:#e8e8e8">
106−
107− </div>
108− """
109− response = mock.Mock(text=html.encode('utf-8'))
110− results = btdigg.response(response)
111− self.assertEqual(type(results), list)
112− self.assertEqual(len(results), 0)
tests/unit/engines/test_currency_convert.pydeleted−56
@@ -1,56 +0,0 @@
1−from collections import defaultdict
2−from datetime import datetime
3−import mock
4−from searx.engines import currency_convert
5−from searx.testing import SearxTestCase
6−
7−
8−class TestCurrencyConvertEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = b'test_query'
12− dicto = defaultdict(dict)
13− dicto['pageno'] = 1
14− params = currency_convert.request(query, dicto)
15− self.assertNotIn('url', params)
16−
17− query = b'convert 10 Pound Sterlings to United States Dollars'
18− params = currency_convert.request(query, dicto)
19− self.assertIn('url', params)
20− self.assertIn('duckduckgo.com', params['url'])
21− self.assertIn('GBP', params['url'])
22− self.assertIn('USD', params['url'])
23−
24− def test_response(self):
25− dicto = defaultdict(dict)
26− dicto['amount'] = float(10)
27− dicto['from'] = "GBP"
28− dicto['to'] = "USD"
29− dicto['from_name'] = "pound sterling"
30− dicto['to_name'] = "United States dollar"
31− response = mock.Mock(text='a,b,c,d', search_params=dicto)
32− self.assertEqual(currency_convert.response(response), [])
33− body = """ddg_spice_currency(
34− {
35− "conversion":{
36− "converted-amount": "0.5"
37− },
38− "topConversions":[
39− {
40− },
41− {
42− }
43− ]
44− }
45− );
46− """
47− response = mock.Mock(text=body, search_params=dicto)
48− results = currency_convert.response(response)
49− self.assertEqual(type(results), list)
50− self.assertEqual(len(results), 1)
51− self.assertEqual(results[0]['answer'], '10.0 GBP = 5.0 USD, 1 GBP (pound sterling)' +
52− ' = 0.5 USD (United States dollar)')
53−
54− target_url = 'https://duckduckgo.com/js/spice/currency/1/{}/{}'.format(
55− dicto['from'], dicto['to'])
56− self.assertEqual(results[0]['url'], target_url)
tests/unit/engines/test_dailymotion.pydeleted−112
@@ -1,112 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import dailymotion
5−from searx.testing import SearxTestCase
6−
7−
8−class TestDailymotionEngine(SearxTestCase):
9−
10− def test_request(self):
11− dailymotion.supported_languages = ['en', 'fr']
12− query = 'test_query'
13− dicto = defaultdict(dict)
14− dicto['pageno'] = 0
15− dicto['language'] = 'fr-FR'
16− params = dailymotion.request(query, dicto)
17− self.assertTrue('url' in params)
18− self.assertTrue(query in params['url'])
19− self.assertTrue('dailymotion.com' in params['url'])
20− self.assertTrue('fr' in params['url'])
21−
22− dicto['language'] = 'all'
23− params = dailymotion.request(query, dicto)
24− self.assertTrue('en' in params['url'])
25−
26− def test_response(self):
27− self.assertRaises(AttributeError, dailymotion.response, None)
28− self.assertRaises(AttributeError, dailymotion.response, [])
29− self.assertRaises(AttributeError, dailymotion.response, '')
30− self.assertRaises(AttributeError, dailymotion.response, '[]')
31−
32− response = mock.Mock(text='{}')
33− self.assertEqual(dailymotion.response(response), [])
34−
35− response = mock.Mock(text='{"data": []}')
36− self.assertEqual(dailymotion.response(response), [])
37−
38− json = """
39− {
40− "page": 1,
41− "limit": 5,
42− "explicit": false,
43− "total": 289487,
44− "has_more": true,
45− "list": [
46− {
47− "created_time": 1422173451,
48− "title": "Title",
49− "description": "Description",
50− "duration": 81,
51− "url": "http://www.url",
52− "thumbnail_360_url": "http://thumbnail",
53− "id": "x2fit7q"
54− }
55− ]
56− }
57− """
58− response = mock.Mock(text=json)
59− results = dailymotion.response(response)
60− self.assertEqual(type(results), list)
61− self.assertEqual(len(results), 1)
62− self.assertEqual(results[0]['title'], 'Title')
63− self.assertEqual(results[0]['url'], 'http://www.url')
64− self.assertEqual(results[0]['content'], 'Description')
65− self.assertIn('x2fit7q', results[0]['embedded'])
66−
67− json = r"""
68− {"toto":[
69− {"id":200,"name":"Artist Name",
70− "link":"http:\/\/www.dailymotion.com\/artist\/1217","type":"artist"}
71− ]}
72− """
73− response = mock.Mock(text=json)
74− results = dailymotion.response(response)
75− self.assertEqual(type(results), list)
76− self.assertEqual(len(results), 0)
77−
78− def test_fetch_supported_languages(self):
79− json = r"""
80− {"list":[{"code":"af","name":"Afrikaans","native_name":"Afrikaans",
81− "localized_name":"Afrikaans","display_name":"Afrikaans"},
82− {"code":"ar","name":"Arabic","native_name":"\u0627\u0644\u0639\u0631\u0628\u064a\u0629",
83− "localized_name":"Arabic","display_name":"Arabic"},
84− {"code":"la","name":"Latin","native_name":null,
85− "localized_name":"Latin","display_name":"Latin"}
86− ]}
87− """
88− response = mock.Mock(text=json)
89− languages = dailymotion._fetch_supported_languages(response)
90− self.assertEqual(type(languages), dict)
91− self.assertEqual(len(languages), 3)
92− self.assertIn('af', languages)
93− self.assertIn('ar', languages)
94− self.assertIn('la', languages)
95−
96− self.assertEqual(type(languages['af']), dict)
97− self.assertEqual(type(languages['ar']), dict)
98− self.assertEqual(type(languages['la']), dict)
99−
100− self.assertIn('name', languages['af'])
101− self.assertIn('name', languages['ar'])
102− self.assertNotIn('name', languages['la'])
103−
104− self.assertIn('english_name', languages['af'])
105− self.assertIn('english_name', languages['ar'])
106− self.assertIn('english_name', languages['la'])
107−
108− self.assertEqual(languages['af']['name'], 'Afrikaans')
109− self.assertEqual(languages['af']['english_name'], 'Afrikaans')
110− self.assertEqual(languages['ar']['name'], u'العربية')
111− self.assertEqual(languages['ar']['english_name'], 'Arabic')
112− self.assertEqual(languages['la']['english_name'], 'Latin')
tests/unit/engines/test_deezer.pydeleted−57
@@ -1,57 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import deezer
4−from searx.testing import SearxTestCase
5−
6−
7−class TestDeezerEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dicto = defaultdict(dict)
12− dicto['pageno'] = 0
13− params = deezer.request(query, dicto)
14− self.assertTrue('url' in params)
15− self.assertTrue(query in params['url'])
16− self.assertTrue('deezer.com' in params['url'])
17−
18− def test_response(self):
19− self.assertRaises(AttributeError, deezer.response, None)
20− self.assertRaises(AttributeError, deezer.response, [])
21− self.assertRaises(AttributeError, deezer.response, '')
22− self.assertRaises(AttributeError, deezer.response, '[]')
23−
24− response = mock.Mock(text='{}')
25− self.assertEqual(deezer.response(response), [])
26−
27− response = mock.Mock(text='{"data": []}')
28− self.assertEqual(deezer.response(response), [])
29−
30− json = r"""
31− {"data":[
32− {"id":100, "title":"Title of track",
33− "link":"https:\/\/www.deezer.com\/track\/1094042","duration":232,
34− "artist":{"id":200,"name":"Artist Name",
35− "link":"https:\/\/www.deezer.com\/artist\/1217","type":"artist"},
36− "album":{"id":118106,"title":"Album Title","type":"album"},"type":"track"}
37− ]}
38− """
39− response = mock.Mock(text=json)
40− results = deezer.response(response)
41− self.assertEqual(type(results), list)
42− self.assertEqual(len(results), 1)
43− self.assertEqual(results[0]['title'], 'Title of track')
44− self.assertEqual(results[0]['url'], 'https://www.deezer.com/track/1094042')
45− self.assertEqual(results[0]['content'], 'Artist Name - Album Title - Title of track')
46− self.assertTrue('100' in results[0]['embedded'])
47−
48− json = r"""
49− {"data":[
50− {"id":200,"name":"Artist Name",
51− "link":"https:\/\/www.deezer.com\/artist\/1217","type":"artist"}
52− ]}
53− """
54− response = mock.Mock(text=json)
55− results = deezer.response(response)
56− self.assertEqual(type(results), list)
57− self.assertEqual(len(results), 0)
tests/unit/engines/test_deviantart.pydeleted−95
@@ -1,95 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import deviantart
4−from searx.testing import SearxTestCase
5−
6−
7−class TestDeviantartEngine(SearxTestCase):
8−
9− def test_request(self):
10− dicto = defaultdict(dict)
11− query = 'test_query'
12− dicto['pageno'] = 0
13− dicto['time_range'] = ''
14− params = deviantart.request(query, dicto)
15− self.assertTrue('url' in params)
16− self.assertTrue(query in params['url'])
17− self.assertTrue('deviantart.com' in params['url'])
18−
19− def test_no_url_in_request_year_time_range(self):
20− dicto = defaultdict(dict)
21− query = 'test_query'
22− dicto['time_range'] = 'year'
23− params = deviantart.request(query, dicto)
24− self.assertEqual({}, params['url'])
25−
26− def test_response(self):
27− self.assertRaises(AttributeError, deviantart.response, None)
28− self.assertRaises(AttributeError, deviantart.response, [])
29− self.assertRaises(AttributeError, deviantart.response, '')
30− self.assertRaises(AttributeError, deviantart.response, '[]')
31−
32− response = mock.Mock(text='<html></html>')
33− self.assertEqual(deviantart.response(response), [])
34−
35− response = mock.Mock(status_code=302)
36− self.assertEqual(deviantart.response(response), [])
37−
38− html = """
39− <div id="page-1-results" class="page-results results-page-thumb torpedo-container">
40− <span class="thumb wide" href="http://amai911.deviantart.com/art/Horse-195212845"
41− data-super-full-width="900" data-super-full-height="600">
42− <a class="torpedo-thumb-link" href="https://url.of.image">
43− <img data-sigil="torpedo-img" src="https://url.of.thumbnail" />
44− </a>
45− <span class="info"><span class="title-wrap"><span class="title">Title of image</span></span>
46− </div>
47− """
48− response = mock.Mock(text=html)
49− results = deviantart.response(response)
50− self.assertEqual(type(results), list)
51− self.assertEqual(len(results), 1)
52− self.assertEqual(results[0]['title'], 'Title of image')
53− self.assertEqual(results[0]['url'], 'https://url.of.image')
54− self.assertNotIn('content', results[0])
55− self.assertEqual(results[0]['thumbnail_src'], 'https://url.of.thumbnail')
56−
57− html = """
58− <span class="tt-fh-tc" style="width: 202px;">
59− <span class="tt-bb" style="width: 202px;">
60− </span>
61− <span class="shadow">
62− <a class="thumb" href="http://url.of.result/2nd.part.of.url"
63− title="Behoimi BE Animation Test by test-0, Jan 4,
64− 2010 in Digital Art &gt; Animation"> <i></i>
65− <img width="200" height="200" alt="Test"
66− src="http://url.of.thumbnail" data-src="http://th08.deviantart.net/test.jpg">
67− </a>
68− </span>
69− <!-- ^TTT -->
70− </span>
71− <span class="details">
72− <a href="http://test-0.deviantart.com/art/Test" class="t"
73− title="Behoimi BE Animation Test by test-0, Jan 4, 2010">
74− <span class="tt-fh-oe">Title of image</span> </a>
75− <small>
76− <span class="category">
77− <span class="age">
78− 5 years ago
79− </span>
80− in <a title="Behoimi BE Animation Test by test-0, Jan 4, 2010"
81− href="http://www.deviantart.com/browse/all/digitalart/animation/">Animation</a>
82− </span>
83− <div class="commentcount">
84− <a href="http://test-0.deviantart.com/art/Test#comments">
85− <span class="iconcommentsstats"></span>9 Comments</a>
86− </div>
87− <a class="mlt-link" href="http://www.deviantart.com/morelikethis/149167425">
88− <span class="mlt-icon"></span> <span class="mlt-text">More Like This</span> </a>
89− </span>
90− </small> <!-- TTT$ -->
91− """
92− response = mock.Mock(text=html)
93− results = deviantart.response(response)
94− self.assertEqual(type(results), list)
95− self.assertEqual(len(results), 0)
tests/unit/engines/test_digbt.pydeleted−61
@@ -1,61 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import digbt
4−from searx.testing import SearxTestCase
5−
6−
7−class TestDigBTEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dicto = defaultdict(dict)
12− dicto['pageno'] = 0
13− params = digbt.request(query, dicto)
14− self.assertIn('url', params)
15− self.assertIn(query, params['url'])
16− self.assertIn('digbt.org', params['url'])
17−
18− def test_response(self):
19− self.assertRaises(AttributeError, digbt.response, None)
20− self.assertRaises(AttributeError, digbt.response, [])
21− self.assertRaises(AttributeError, digbt.response, '')
22− self.assertRaises(AttributeError, digbt.response, '[]')
23−
24− response = mock.Mock(text='<html></html>')
25− self.assertEqual(digbt.response(response), [])
26−
27− html = """
28− <table class="table">
29− <tr><td class="x-item">
30− <div>
31− <a title="The Big Bang Theory" class="title" href="/The-Big-Bang-Theory-d2.html">
32− The Big <span class="highlight">Bang</span> Theory
33− </a>
34− <span class="ctime"><span style="color:red;">4 hours ago</span></span>
35− </div>
36− <div class="files">
37− <ul>
38− <li>The Big Bang Theory 2.9 GB</li>
39− <li>....</li>
40− </ul>
41− </div>
42− <div class="tail">
43− Files: 1 Size: 2.9 GB Downloads: 1 Updated: <span style="color:red;">4 hours ago</span>
44− &nbsp; &nbsp;
45− <a class="title" href="magnet:?xt=urn:btih:a&amp;dn=The+Big+Bang+Theory">
46− <span class="glyphicon glyphicon-magnet"></span> magnet-link
47− </a>
48− &nbsp; &nbsp;
49− </div>
50− </td></tr>
51− </table>
52− """
53− response = mock.Mock(text=html.encode('utf-8'))
54− results = digbt.response(response)
55− self.assertEqual(type(results), list)
56− self.assertEqual(len(results), 1)
57− self.assertEqual(results[0]['title'], 'The Big Bang Theory')
58− self.assertEqual(results[0]['url'], 'https://digbt.org/The-Big-Bang-Theory-d2.html')
59− self.assertEqual(results[0]['content'], 'The Big Bang Theory 2.9 GB ....')
60− self.assertEqual(results[0]['filesize'], 3113851289)
61− self.assertEqual(results[0]['magnetlink'], 'magnet:?xt=urn:btih:a&dn=The+Big+Bang+Theory')
tests/unit/engines/test_digg.pydeleted−101
@@ -1,101 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import digg
4−from searx.testing import SearxTestCase
5−
6−
7−class TestDiggEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dicto = defaultdict(dict)
12− dicto['pageno'] = 1
13− params = digg.request(query, dicto)
14− self.assertIn('url', params)
15− self.assertIn(query, params['url'])
16− self.assertIn('digg.com', params['url'])
17−
18− def test_response(self):
19− self.assertRaises(AttributeError, digg.response, None)
20− self.assertRaises(AttributeError, digg.response, [])
21− self.assertRaises(AttributeError, digg.response, '')
22− self.assertRaises(AttributeError, digg.response, '[]')
23−
24− response = mock.Mock(text='{}')
25− self.assertEqual(digg.response(response), [])
26−
27− response = mock.Mock(text='{"data": []}')
28− self.assertEqual(digg.response(response), [])
29−
30− json = """
31− {
32− "status": "ok",
33− "num": 10,
34− "next_position": 20,
35− "html": "<article itemscope itemtype=\\"http://schema.org/Article\\"
36− class=\\"story-container digg-story-el hentry entry story-1sRANah col-1\\"
37− data-content-id=\\"1sRANah\\" data-contenturl=\\"http://url.of.link\\"
38− data-position=\\"0\\" data-diggs=\\"24\\" data-tweets=\\"69\\"
39− data-digg-score=\\"1190\\"> <div class=\\"story-image story-image-thumb\\">
40− <a data-position=\\"0\\" data-content-id=\\"1sRANah\\"
41− class=\\"story-link\\" href=\\"http://www.thedailybeast.com/\\"
42− target=\\"_blank\\"><img class=\\"story-image-img\\"
43− src=\\"http://url.of.image.jpeg\\" width=\\"312\\" height=\\"170\\"
44− alt=\\"\\" /> </a> </div> <div class=\\"story-content\\"><header
45− class=\\"story-header\\"> <div itemprop=\\"alternativeHeadline\\"
46− class=\\"story-kicker\\" >Kicker</div> <h2 itemprop=\\"headline\\"
47− class=\\"story-title entry-title\\"><a class=\\"story-title-link story-link\\"
48− rel=\\"bookmark\\" itemprop=\\"url\\" href=\\"http://www.thedailybeast.com/\\"
49− target=\\"_blank\\">Title of article</h2> <div class=\\"story-meta\\">
50− <div class=\\"story-score \\">
51− <div class=\\"story-score-diggscore diggscore-1sRANah\\">1190</div>
52− <div class=\\"story-score-details\\"> <div class=\\"arrow\\"></div>
53− <ul class=\\"story-score-details-list\\"> <li
54− class=\\"story-score-detail story-score-diggs\\"><span
55− class=\\"label\\">Diggs:</span> <span class=\\"count diggs-1sRANah\\">24</span>
56− </li> <li class=\\"story-score-detail story-score-twitter\\"><span
57− class=\\"label\\">Tweets:</span> <span class=\\"count tweets-1sRANah\\">69</span>
58− </li> <li class=\\"story-score-detail story-score-facebook\\"><span
59− class=\\"label\\">Facebook Shares:</span> <span
60− class=\\"count fb_shares-1sRANah\\">1097</span></li> </ul> </div> </div>
61− <span class=\\"story-meta-item story-source\\"> <a
62− itemprop=\\"publisher copyrightHolder sourceOrganization provider\\"
63− class=\\"story-meta-item-link story-source-link\\"
64− href=\\"/source/thedailybeast.com\\">The Daily Beast </a> </span>
65− <span class=\\"story-meta-item story-tag first-tag\\"> <a
66− itemprop=\\"keywords\\" rel=\\"tag\\"
67− class=\\"story-meta-item-link story-tag-link\\" href=\\"/tag/news\\">News</a>
68− </span> <abbr class=\\"published story-meta-item story-timestamp\\"
69− title=\\"2014-10-18 14:53:45\\"> <time datetime=\\"2014-10-18 14:53:45\\">18 Oct 2014</time>
70− </abbr> </div> </header> </div> <ul class=\\"story-actions\\"> <li
71− class=\\"story-action story-action-digg btn-story-action-container\\">
72− <a class=\\"target digg-1sRANah\\" href=\\"#\\">Digg</a></li> <li
73− class=\\"story-action story-action-save btn-story-action-container\\">
74− <a class=\\"target save-1sRANah\\" href=\\"#\\">Save</a></li> <li
75− class=\\"story-action story-action-share\\"><a
76− class=\\"target share-facebook\\" href=\\"https://www.facebook.com/\\">Facebook</a></li>
77− <li class=\\"story-action story-action-share\\"><a class=\\"target share-twitter\\"
78− href=\\"https://twitter.com/\\">Twitter</a></li> </ul> </article>"
79− }
80− """
81− json = json.replace('\r\n', '').replace('\n', '').replace('\r', '')
82− response = mock.Mock(text=json)
83− results = digg.response(response)
84− self.assertEqual(type(results), list)
85− self.assertEqual(len(results), 1)
86− self.assertEqual(results[0]['title'], 'Title of article')
87− self.assertEqual(results[0]['url'], 'http://url.of.link')
88− self.assertEqual(results[0]['thumbnail'], 'http://url.of.image.jpeg')
89− self.assertEqual(results[0]['content'], '')
90−
91− json = """
92− {
93− "status": "error",
94− "num": 10,
95− "next_position": 20
96− }
97− """
98− response = mock.Mock(text=json)
99− results = digg.response(response)
100− self.assertEqual(type(results), list)
101− self.assertEqual(len(results), 0)
tests/unit/engines/test_doku.pydeleted−79
@@ -1,79 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import doku
5−from searx.testing import SearxTestCase
6−
7−
8−class TestDokuEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dicto = defaultdict(dict)
13− params = doku.request(query, dicto)
14− self.assertIn('url', params)
15− self.assertIn(query, params['url'])
16−
17− def test_response(self):
18− self.assertRaises(AttributeError, doku.response, None)
19− self.assertRaises(AttributeError, doku.response, [])
20− self.assertRaises(AttributeError, doku.response, '')
21− self.assertRaises(AttributeError, doku.response, '[]')
22−
23− response = mock.Mock(text='<html></html>')
24− self.assertEqual(doku.response(response), [])
25−
26− html = u"""
27− <div class="search_quickresult">
28− <h3>Pages trouvées :</h3>
29− <ul class="search_quickhits">
30− <li> <a href="/xfconf-query" class="wikilink1" title="xfconf-query">xfconf-query</a></li>
31− </ul>
32− <div class="clearer"></div>
33− </div>
34− """
35− response = mock.Mock(text=html)
36− results = doku.response(response)
37− expected = [{'content': '', 'title': 'xfconf-query', 'url': 'http://localhost:8090/xfconf-query'}]
38− self.assertEqual(doku.response(response), expected)
39−
40− html = u"""
41− <dl class="search_results">
42− <dt><a href="/xvnc?s[]=query" class="wikilink1" title="xvnc">xvnc</a>: 40 Occurrences trouvées</dt>
43− <dd>er = /usr/bin/Xvnc
44− server_args = -inetd -<strong class="search_hit">query</strong> localhost -geometry 640x480 ... er = /usr/bin/Xvnc
45− server_args = -inetd -<strong class="search_hit">query</strong> localhost -geometry 800x600 ... er = /usr/bin/Xvnc
46− server_args = -inetd -<strong class="search_hit">query</strong> localhost -geometry 1024x768 ... er = /usr/bin/Xvnc
47− server_args = -inetd -<strong class="search_hit">query</strong> localhost -geometry 1280x1024 -depth 8 -Sec</dd>
48− <dt><a href="/postfix_mysql_tls_sasl_1404?s[]=query"
49− class="wikilink1"
50− title="postfix_mysql_tls_sasl_1404">postfix_mysql_tls_sasl_1404</a>: 14 Occurrences trouvées</dt>
51− <dd>tdepasse
52− hosts = 127.0.0.1
53− dbname = postfix
54− <strong class="search_hit">query</strong> = SELECT goto FROM alias WHERE address='%s' AND a... tdepasse
55− hosts = 127.0.0.1
56− dbname = postfix
57− <strong class="search_hit">query</strong> = SELECT domain FROM domain WHERE domain='%s'
58− #optional <strong class="search_hit">query</strong> to use when relaying for backup MX
59− #<strong class="search_hit">query</strong> = SELECT domain FROM domain WHERE domain='%s' and backupmx =</dd>
60− <dt><a href="/bind9?s[]=query" class="wikilink1" title="bind9">bind9</a>: 12 Occurrences trouvées</dt>
61− <dd> printcmd
62−;; Got answer:
63−;; -&gt;&gt;HEADER&lt;&lt;- opcode: <strong class="search_hit">QUERY</strong>, status: NOERROR, id: 13427
64−;; flags: qr aa rd ra; <strong class="search_hit">QUERY</strong>: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
65−
66−[...]
67−
68−;; <strong class="search_hit">Query</strong> time: 1 msec
69−;; SERVER: 127.0.0.1#53(127.0.0.1)
70−;... par la requête (<strong class="search_hit">Query</strong> time) , entre la première et la deuxième requête.</dd>
71− </dl>
72− """
73− response = mock.Mock(text=html)
74− results = doku.response(response)
75− self.assertEqual(type(results), list)
76− self.assertEqual(len(results), 3)
77− self.assertEqual(results[0]['title'], 'xvnc')
78−# FIXME self.assertEqual(results[0]['url'], u'http://this.should.be.the.link/ű')
79−# FIXME self.assertEqual(results[0]['content'], 'This should be the content.')
tests/unit/engines/test_duckduckgo.pydeleted−106
@@ -1,106 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import load_engine, duckduckgo
5−from searx.testing import SearxTestCase
6−
7−
8−class TestDuckduckgoEngine(SearxTestCase):
9−
10− def test_request(self):
11− duckduckgo = load_engine({'engine': 'duckduckgo', 'name': 'duckduckgo'})
12−
13− query = 'test_query'
14− dicto = defaultdict(dict)
15− dicto['pageno'] = 1
16− dicto['time_range'] = ''
17−
18− dicto['language'] = 'de-CH'
19− params = duckduckgo.request(query, dicto)
20− self.assertIn('url', params)
21− self.assertIn(query, params['url'])
22− self.assertIn('duckduckgo.com', params['url'])
23− self.assertIn('ch-de', params['url'])
24− self.assertIn('s=0', params['url'])
25−
26− # when ddg uses non standard codes
27− dicto['language'] = 'zh-HK'
28− params = duckduckgo.request(query, dicto)
29− self.assertIn('hk-tzh', params['url'])
30−
31− dicto['language'] = 'en-GB'
32− params = duckduckgo.request(query, dicto)
33− self.assertIn('uk-en', params['url'])
34−
35− # no country given
36− dicto['language'] = 'en'
37− params = duckduckgo.request(query, dicto)
38− self.assertIn('us-en', params['url'])
39−
40− def test_no_url_in_request_year_time_range(self):
41− dicto = defaultdict(dict)
42− query = 'test_query'
43− dicto['time_range'] = 'year'
44− params = duckduckgo.request(query, dicto)
45− self.assertEqual({}, params['url'])
46−
47− def test_response(self):
48− self.assertRaises(AttributeError, duckduckgo.response, None)
49− self.assertRaises(AttributeError, duckduckgo.response, [])
50− self.assertRaises(AttributeError, duckduckgo.response, '')
51− self.assertRaises(AttributeError, duckduckgo.response, '[]')
52−
53− response = mock.Mock(text='<html></html>')
54− self.assertEqual(duckduckgo.response(response), [])
55−
56− html = u"""
57− <div class="result results_links results_links_deep web-result result--no-result">
58− <div class="links_main links_deep result__body">
59− <h2 class="result__title">
60− </h2>
61− <div class="no-results">No results</div>
62− <div class="result__extras">
63− </div>
64− </div>
65− </div>
66− """
67− response = mock.Mock(text=html)
68− results = duckduckgo.response(response)
69− self.assertEqual(duckduckgo.response(response), [])
70−
71− html = u"""
72− <div class="result results_links results_links_deep web-result ">
73− <div class="links_main links_deep result__body">
74− <h2 class="result__title">
75− <a rel="nofollow" class="result__a" href="http://this.should.be.the.link/ű">
76− This <b>is</b> <b>the</b> title
77− </a>
78− </h2>
79− <a class="result__snippet" href="http://this.should.be.the.link/ű">
80− <b>This</b> should be the content.
81− </a>
82− <div class="result__extras">
83− </div>
84− </div>
85− </div>
86− """
87− response = mock.Mock(text=html)
88− results = duckduckgo.response(response)
89− self.assertEqual(type(results), list)
90− self.assertEqual(len(results), 1)
91− self.assertEqual(results[0]['title'], 'This is the title')
92− self.assertEqual(results[0]['url'], u'http://this.should.be.the.link/ű')
93− self.assertEqual(results[0]['content'], 'This should be the content.')
94−
95− def test_fetch_supported_languages(self):
96− js = """some code...regions:{
97− "wt-wt":"All Results","ar-es":"Argentina","au-en":"Australia","at-de":"Austria","be-fr":"Belgium (fr)"
98− }some more code..."""
99− response = mock.Mock(text=js)
100− languages = list(duckduckgo._fetch_supported_languages(response))
101− self.assertEqual(len(languages), 5)
102− self.assertIn('wt-WT', languages)
103− self.assertIn('es-AR', languages)
104− self.assertIn('en-AU', languages)
105− self.assertIn('de-AT', languages)
106− self.assertIn('fr-BE', languages)
tests/unit/engines/test_duckduckgo_definitions.pydeleted−255
@@ -1,255 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import duckduckgo_definitions
4−from searx.testing import SearxTestCase
5−
6−
7−class TestDDGDefinitionsEngine(SearxTestCase):
8−
9− def test_result_to_text(self):
10− url = ''
11− text = 'Text'
12− html_result = 'Html'
13− result = duckduckgo_definitions.result_to_text(url, text, html_result)
14− self.assertEqual(result, text)
15−
16− html_result = '<a href="url">Text in link</a>'
17− result = duckduckgo_definitions.result_to_text(url, text, html_result)
18− self.assertEqual(result, 'Text in link')
19−
20− def test_request(self):
21− duckduckgo_definitions.supported_languages = ['en-US', 'es-ES']
22− query = 'test_query'
23− dicto = defaultdict(dict)
24− dicto['pageno'] = 1
25− dicto['language'] = 'es'
26− params = duckduckgo_definitions.request(query, dicto)
27− self.assertIn('url', params)
28− self.assertIn(query, params['url'])
29− self.assertIn('duckduckgo.com', params['url'])
30− self.assertIn('headers', params)
31− self.assertIn('Accept-Language', params['headers'])
32− self.assertIn('es', params['headers']['Accept-Language'])
33−
34− def test_response(self):
35− self.assertRaises(AttributeError, duckduckgo_definitions.response, None)
36− self.assertRaises(AttributeError, duckduckgo_definitions.response, [])
37− self.assertRaises(AttributeError, duckduckgo_definitions.response, '')
38− self.assertRaises(AttributeError, duckduckgo_definitions.response, '[]')
39−
40− response = mock.Mock(text='{}')
41− self.assertEqual(duckduckgo_definitions.response(response), [])
42−
43− response = mock.Mock(text='{"data": []}')
44− self.assertEqual(duckduckgo_definitions.response(response), [])
45−
46− json = """
47− {
48− "DefinitionSource": "definition source",
49− "Heading": "heading",
50− "ImageWidth": 0,
51− "RelatedTopics": [
52− {
53− "Result": "Top-level domains",
54− "Icon": {
55− "URL": "",
56− "Height": "",
57− "Width": ""
58− },
59− "FirstURL": "https://first.url",
60− "Text": "text"
61− },
62− {
63− "Topics": [
64− {
65− "Result": "result topic",
66− "Icon": {
67− "URL": "",
68− "Height": "",
69− "Width": ""
70− },
71− "FirstURL": "https://duckduckgo.com/?q=2%2F2",
72− "Text": "result topic text"
73− }
74− ],
75− "Name": "name"
76− }
77− ],
78− "Entity": "Entity",
79− "Type": "A",
80− "Redirect": "",
81− "DefinitionURL": "http://definition.url",
82− "AbstractURL": "https://abstract.url",
83− "Definition": "this is the definition",
84− "AbstractSource": "abstract source",
85− "Infobox": {
86− "content": [
87− {
88− "data_type": "string",
89− "value": "1999",
90− "label": "Introduced",
91− "wiki_order": 0
92− }
93− ],
94− "meta": [
95− {
96− "data_type": "string",
97− "value": ".test",
98− "label": "article_title"
99− }
100− ]
101− },
102− "Image": "image.png",
103− "ImageIsLogo": 0,
104− "Abstract": "abstract",
105− "AbstractText": "abstract text",
106− "AnswerType": "",
107− "ImageHeight": 0,
108− "Results": [{
109− "Result" : "result title",
110− "Icon" : {
111− "URL" : "result url",
112− "Height" : 16,
113− "Width" : 16
114− },
115− "FirstURL" : "result first url",
116− "Text" : "result text"
117− }
118− ],
119− "Answer": "answer"
120− }
121− """
122− response = mock.Mock(text=json)
123− results = duckduckgo_definitions.response(response)
124− self.assertEqual(type(results), list)
125− self.assertEqual(len(results), 4)
126− self.assertEqual(results[0]['answer'], 'answer')
127− self.assertEqual(results[1]['title'], 'heading')
128− self.assertEqual(results[1]['url'], 'result first url')
129− self.assertEqual(results[2]['suggestion'], 'text')
130− self.assertEqual(results[3]['infobox'], 'heading')
131− self.assertEqual(results[3]['id'], 'https://definition.url')
132− self.assertEqual(results[3]['entity'], 'Entity')
133− self.assertIn('abstract', results[3]['content'])
134− self.assertIn('this is the definition', results[3]['content'])
135− self.assertEqual(results[3]['img_src'], 'image.png')
136− self.assertIn('Introduced', results[3]['attributes'][0]['label'])
137− self.assertIn('1999', results[3]['attributes'][0]['value'])
138− self.assertIn({'url': 'https://abstract.url', 'title': 'abstract source'}, results[3]['urls'])
139− self.assertIn({'url': 'http://definition.url', 'title': 'definition source'}, results[3]['urls'])
140− self.assertIn({'name': 'name', 'suggestions': ['result topic text']}, results[3]['relatedTopics'])
141−
142− json = """
143− {
144− "DefinitionSource": "definition source",
145− "Heading": "heading",
146− "ImageWidth": 0,
147− "RelatedTopics": [],
148− "Entity": "Entity",
149− "Type": "A",
150− "Redirect": "",
151− "DefinitionURL": "",
152− "AbstractURL": "https://abstract.url",
153− "Definition": "",
154− "AbstractSource": "abstract source",
155− "Image": "",
156− "ImageIsLogo": 0,
157− "Abstract": "",
158− "AbstractText": "abstract text",
159− "AnswerType": "",
160− "ImageHeight": 0,
161− "Results": [],
162− "Answer": ""
163− }
164− """
165− response = mock.Mock(text=json)
166− results = duckduckgo_definitions.response(response)
167− self.assertEqual(type(results), list)
168− self.assertEqual(len(results), 1)
169− self.assertEqual(results[0]['url'], 'https://abstract.url')
170− self.assertEqual(results[0]['title'], 'heading')
171− self.assertEqual(results[0]['content'], '')
172−
173− json = """
174− {
175− "DefinitionSource": "definition source",
176− "Heading": "heading",
177− "ImageWidth": 0,
178− "RelatedTopics": [
179− {
180− "Result": "Top-level domains",
181− "Icon": {
182− "URL": "",
183− "Height": "",
184− "Width": ""
185− },
186− "FirstURL": "https://first.url",
187− "Text": "heading"
188− },
189− {
190− "Name": "name"
191− },
192− {
193− "Topics": [
194− {
195− "Result": "result topic",
196− "Icon": {
197− "URL": "",
198− "Height": "",
199− "Width": ""
200− },
201− "FirstURL": "https://duckduckgo.com/?q=2%2F2",
202− "Text": "heading"
203− }
204− ],
205− "Name": "name"
206− }
207− ],
208− "Entity": "Entity",
209− "Type": "A",
210− "Redirect": "",
211− "DefinitionURL": "http://definition.url",
212− "AbstractURL": "https://abstract.url",
213− "Definition": "this is the definition",
214− "AbstractSource": "abstract source",
215− "Infobox": {
216− "meta": [
217− {
218− "data_type": "string",
219− "value": ".test",
220− "label": "article_title"
221− }
222− ]
223− },
224− "Image": "image.png",
225− "ImageIsLogo": 0,
226− "Abstract": "abstract",
227− "AbstractText": "abstract text",
228− "AnswerType": "",
229− "ImageHeight": 0,
230− "Results": [{
231− "Result" : "result title",
232− "Icon" : {
233− "URL" : "result url",
234− "Height" : 16,
235− "Width" : 16
236− },
237− "Text" : "result text"
238− }
239− ],
240− "Answer": ""
241− }
242− """
243− response = mock.Mock(text=json)
244− results = duckduckgo_definitions.response(response)
245− self.assertEqual(type(results), list)
246− self.assertEqual(len(results), 1)
247− self.assertEqual(results[0]['infobox'], 'heading')
248− self.assertEqual(results[0]['id'], 'https://definition.url')
249− self.assertEqual(results[0]['entity'], 'Entity')
250− self.assertIn('abstract', results[0]['content'])
251− self.assertIn('this is the definition', results[0]['content'])
252− self.assertEqual(results[0]['img_src'], 'image.png')
253− self.assertIn({'url': 'https://abstract.url', 'title': 'abstract source'}, results[0]['urls'])
254− self.assertIn({'url': 'http://definition.url', 'title': 'definition source'}, results[0]['urls'])
255− self.assertIn({'name': 'name', 'suggestions': []}, results[0]['relatedTopics'])
tests/unit/engines/test_duckduckgo_images.pydeleted−75
@@ -1,75 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import duckduckgo_images
5−from searx.testing import SearxTestCase
6−
7−
8−class TestDuckduckgoImagesEngine(SearxTestCase):
9−
10− def test_request(self):
11− duckduckgo_images.supported_languages = ['de-CH', 'en-US']
12− query = 'test_query'
13− dicto = defaultdict(dict)
14− dicto['is_test'] = True
15− dicto['pageno'] = 1
16− dicto['safesearch'] = 0
17− dicto['language'] = 'all'
18− params = duckduckgo_images.request(query, dicto)
19− self.assertIn('url', params)
20− self.assertIn(query, params['url'])
21− self.assertIn('duckduckgo.com', params['url'])
22− self.assertIn('s=0', params['url'])
23− self.assertIn('p=-1', params['url'])
24− self.assertIn('vqd=12345', params['url'])
25−
26− # test paging, safe search and language
27− dicto['pageno'] = 2
28− dicto['safesearch'] = 2
29− dicto['language'] = 'de'
30− params = duckduckgo_images.request(query, dicto)
31− self.assertIn('url', params)
32− self.assertIn(query, params['url'])
33− self.assertIn('s=50', params['url'])
34− self.assertIn('p=1', params['url'])
35− self.assertIn('ch-de', params['url'])
36−
37− def test_response(self):
38− self.assertRaises(AttributeError, duckduckgo_images.response, None)
39− self.assertRaises(AttributeError, duckduckgo_images.response, [])
40− self.assertRaises(AttributeError, duckduckgo_images.response, '')
41− self.assertRaises(AttributeError, duckduckgo_images.response, '[]')
42−
43− response = mock.Mock(text='If this error persists, please let us know: ops@duckduckgo.com')
44− self.assertRaises(Exception, duckduckgo_images.response, response)
45−
46− json = u"""
47− {
48− "query": "test_query",
49− "results": [
50− {
51− "title": "Result 1",
52− "url": "https://site1.url",
53− "thumbnail": "https://thumb1.nail",
54− "image": "https://image1"
55− },
56− {
57− "title": "Result 2",
58− "url": "https://site2.url",
59− "thumbnail": "https://thumb2.nail",
60− "image": "https://image2"
61− }
62− ]
63− }
64− """
65− response = mock.Mock(text=json)
66− results = duckduckgo_images.response(response)
67− self.assertEqual(len(results), 2)
68− self.assertEqual(results[0]['title'], 'Result 1')
69− self.assertEqual(results[0]['url'], 'https://site1.url')
70− self.assertEqual(results[0]['thumbnail_src'], 'https://thumb1.nail')
71− self.assertEqual(results[0]['img_src'], 'https://image1')
72− self.assertEqual(results[1]['title'], 'Result 2')
73− self.assertEqual(results[1]['url'], 'https://site2.url')
74− self.assertEqual(results[1]['thumbnail_src'], 'https://thumb2.nail')
75− self.assertEqual(results[1]['img_src'], 'https://image2')
tests/unit/engines/test_duden.pydeleted−47
@@ -1,47 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import duden
4−from searx.testing import SearxTestCase
5−from datetime import datetime
6−
7−
8−class TestDudenEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'Haus'
12− dic = defaultdict(dict)
13− data = [
14− [1, 'https://www.duden.de/suchen/dudenonline/Haus'],
15− [2, 'https://www.duden.de/suchen/dudenonline/Haus?search_api_fulltext=&page=1']
16− ]
17− for page_no, exp_res in data:
18− dic['pageno'] = page_no
19− params = duden.request(query, dic)
20− self.assertTrue('url' in params)
21− self.assertTrue(query in params['url'])
22− self.assertTrue('duden.de' in params['url'])
23− self.assertEqual(params['url'], exp_res)
24−
25− def test_response(self):
26− resp = mock.Mock(text='<html></html>')
27− self.assertEqual(duden.response(resp), [])
28−
29− html = """
30− <section class="vignette">
31− <h2"> <a href="/rechtschreibung/Haus">
32− <strong>This is the title also here</strong>
33− </a> </h2>
34− <p>This is the content</p>
35− </section>
36− """
37− resp = mock.Mock(text=html)
38− results = duden.response(resp)
39−
40− self.assertEqual(len(results), 1)
41− self.assertEqual(type(results), list)
42−
43− # testing result (dictionary entry)
44− r = results[0]
45− self.assertEqual(r['url'], 'https://www.duden.de/rechtschreibung/Haus')
46− self.assertEqual(r['title'], 'This is the title also here')
47− self.assertEqual(r['content'], 'This is the content')
tests/unit/engines/test_dummy.pydeleted−26
@@ -1,26 +0,0 @@
1−from searx.engines import dummy
2−from searx.testing import SearxTestCase
3−
4−
5−class TestDummyEngine(SearxTestCase):
6−
7− def test_request(self):
8− test_params = [
9− [1, 2, 3],
10− ['a'],
11− [],
12− 1
13− ]
14− for params in test_params:
15− self.assertEqual(dummy.request(None, params), params)
16−
17− def test_response(self):
18− responses = [
19− None,
20− [],
21− True,
22− dict(),
23− tuple()
24− ]
25− for response in responses:
26− self.assertEqual(dummy.response(response), [])
tests/unit/engines/test_faroo.pydeleted−113
@@ -1,113 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import faroo
5−from searx.testing import SearxTestCase
6−
7−
8−class TestFarooEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dicto = defaultdict(dict)
13− dicto['pageno'] = 1
14− dicto['language'] = 'fr-FR'
15− dicto['category'] = 'general'
16− params = faroo.request(query, dicto)
17− self.assertIn('url', params)
18− self.assertIn(query, params['url'])
19− self.assertIn('faroo.com', params['url'])
20− self.assertIn('en', params['url'])
21− self.assertIn('web', params['url'])
22−
23− dicto['language'] = 'all'
24− params = faroo.request(query, dicto)
25− self.assertIn('en', params['url'])
26−
27− dicto['language'] = 'de-DE'
28− params = faroo.request(query, dicto)
29− self.assertIn('de', params['url'])
30−
31− def test_response(self):
32− self.assertRaises(AttributeError, faroo.response, None)
33− self.assertRaises(AttributeError, faroo.response, [])
34− self.assertRaises(AttributeError, faroo.response, '')
35− self.assertRaises(AttributeError, faroo.response, '[]')
36−
37− response = mock.Mock(text='{}')
38− self.assertEqual(faroo.response(response), [])
39−
40− response = mock.Mock(text='{"data": []}')
41− self.assertEqual(faroo.response(response), [])
42−
43− response = mock.Mock(text='{"data": []}', status_code=429)
44− self.assertRaises(Exception, faroo.response, response)
45−
46− json = """
47− {
48− "results": [
49− {
50− "title": "This is the title",
51− "kwic": "This is the content",
52− "content": "",
53− "url": "http://this.is.the.url/",
54− "iurl": "",
55− "domain": "css3test.com",
56− "author": "Jim Dalrymple",
57− "news": true,
58− "votes": "10",
59− "date": 1360622563000,
60− "related": []
61− },
62− {
63− "title": "This is the title2",
64− "kwic": "This is the content2",
65− "content": "",
66− "url": "http://this.is.the.url2/",
67− "iurl": "",
68− "domain": "css3test.com",
69− "author": "Jim Dalrymple",
70− "news": false,
71− "votes": "10",
72− "related": []
73− },
74− {
75− "title": "This is the title3",
76− "kwic": "This is the content3",
77− "content": "",
78− "url": "http://this.is.the.url3/",
79− "iurl": "http://upload.wikimedia.org/optimized.jpg",
80− "domain": "css3test.com",
81− "author": "Jim Dalrymple",
82− "news": false,
83− "votes": "10",
84− "related": []
85− }
86− ],
87− "query": "test",
88− "suggestions": [],
89− "count": 100,
90− "start": 1,
91− "length": 10,
92− "time": "15"
93− }
94− """
95− response = mock.Mock(text=json)
96− results = faroo.response(response)
97− self.assertEqual(type(results), list)
98− self.assertEqual(len(results), 3)
99− self.assertEqual(results[0]['title'], 'This is the title')
100− self.assertEqual(results[0]['url'], 'http://this.is.the.url/')
101− self.assertEqual(results[0]['content'], 'This is the content')
102− self.assertEqual(results[1]['title'], 'This is the title2')
103− self.assertEqual(results[1]['url'], 'http://this.is.the.url2/')
104− self.assertEqual(results[1]['content'], 'This is the content2')
105− self.assertEqual(results[2]['thumbnail'], 'http://upload.wikimedia.org/optimized.jpg')
106−
107− json = """
108− {}
109− """
110− response = mock.Mock(text=json)
111− results = faroo.response(response)
112− self.assertEqual(type(results), list)
113− self.assertEqual(len(results), 0)
tests/unit/engines/test_fdroid.pydeleted−49
@@ -1,49 +0,0 @@
1−import mock
2−from collections import defaultdict
3−from searx.engines import fdroid
4−from searx.testing import SearxTestCase
5−
6−
7−class TestFdroidEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dic = defaultdict(dict)
12− dic['pageno'] = 1
13− params = fdroid.request(query, dic)
14− self.assertTrue('url' in params)
15− self.assertTrue(query in params['url'])
16− self.assertTrue('f-droid.org' in params['url'])
17−
18− def test_response(self):
19− resp = mock.Mock(text='<html></html>')
20− self.assertEqual(fdroid.response(resp), [])
21−
22− html = """
23− <a href="https://google.com/qwerty">
24− <div id="appheader">
25− <div style="float:left;padding-right:10px;">
26− <img src="http://example.com/image.png"
27− style="width:48px;border:none;">
28− </div>
29− <div style="float:right;">
30− <p>Details...</p>
31− </div>
32− <p style="color:#000000;">
33− <span style="font-size:20px;">Sample title</span>
34− <br>
35− Sample content
36− </p>
37− </div>
38− </a>
39− """
40−
41− resp = mock.Mock(text=html)
42− results = fdroid.response(resp)
43−
44− self.assertEqual(type(results), list)
45− self.assertEqual(len(results), 1)
46− self.assertEqual(results[0]['url'], 'https://google.com/qwerty')
47− self.assertEqual(results[0]['title'], 'Sample title')
48− self.assertEqual(results[0]['content'], 'Sample content')
49− self.assertEqual(results[0]['img_src'], 'http://example.com/image.png')
tests/unit/engines/test_flickr.pydeleted−142
@@ -1,142 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import flickr
4−from searx.testing import SearxTestCase
5−
6−
7−class TestFlickrEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dicto = defaultdict(dict)
12− dicto['pageno'] = 0
13− params = flickr.request(query, dicto)
14− self.assertTrue('url' in params)
15− self.assertTrue(query in params['url'])
16− self.assertTrue('flickr.com' in params['url'])
17−
18− def test_response(self):
19− self.assertRaises(AttributeError, flickr.response, None)
20− self.assertRaises(AttributeError, flickr.response, [])
21− self.assertRaises(AttributeError, flickr.response, '')
22− self.assertRaises(AttributeError, flickr.response, '[]')
23−
24− response = mock.Mock(text='{}')
25− self.assertEqual(flickr.response(response), [])
26−
27− response = mock.Mock(text='{"data": []}')
28− self.assertEqual(flickr.response(response), [])
29−
30− json = r"""
31− { "photos": { "page": 1, "pages": "41001", "perpage": 100, "total": "4100032",
32− "photo": [
33− { "id": "15751017054", "owner": "66847915@N08",
34− "secret": "69c22afc40", "server": "7285", "farm": 8,
35− "title": "Photo title", "ispublic": 1,
36− "isfriend": 0, "isfamily": 0,
37− "description": { "_content": "Description" },
38− "ownername": "Owner",
39− "url_o": "https:\/\/farm8.staticflickr.com\/7285\/15751017054_9178e0f963_o.jpg",
40− "height_o": "2100", "width_o": "2653",
41− "url_n": "https:\/\/farm8.staticflickr.com\/7285\/15751017054_69c22afc40_n.jpg",
42− "height_n": "253", "width_n": "320",
43− "url_z": "https:\/\/farm8.staticflickr.com\/7285\/15751017054_69c22afc40_z.jpg",
44− "height_z": "507", "width_z": "640" }
45− ] }, "stat": "ok" }
46− """
47− response = mock.Mock(text=json)
48− results = flickr.response(response)
49− self.assertEqual(type(results), list)
50− self.assertEqual(len(results), 1)
51− self.assertEqual(results[0]['title'], 'Photo title')
52− self.assertEqual(results[0]['url'], 'https://www.flickr.com/photos/66847915@N08/15751017054')
53− self.assertTrue('o.jpg' in results[0]['img_src'])
54− self.assertTrue('n.jpg' in results[0]['thumbnail_src'])
55− self.assertTrue('Owner' in results[0]['author'])
56− self.assertTrue('Description' in results[0]['content'])
57−
58− json = r"""
59− { "photos": { "page": 1, "pages": "41001", "perpage": 100, "total": "4100032",
60− "photo": [
61− { "id": "15751017054", "owner": "66847915@N08",
62− "secret": "69c22afc40", "server": "7285", "farm": 8,
63− "title": "Photo title", "ispublic": 1,
64− "isfriend": 0, "isfamily": 0,
65− "description": { "_content": "Description" },
66− "ownername": "Owner",
67− "url_z": "https:\/\/farm8.staticflickr.com\/7285\/15751017054_69c22afc40_z.jpg",
68− "height_z": "507", "width_z": "640" }
69− ] }, "stat": "ok" }
70− """
71− response = mock.Mock(text=json)
72− results = flickr.response(response)
73− self.assertEqual(type(results), list)
74− self.assertEqual(len(results), 1)
75− self.assertEqual(results[0]['title'], 'Photo title')
76− self.assertEqual(results[0]['url'], 'https://www.flickr.com/photos/66847915@N08/15751017054')
77− self.assertTrue('z.jpg' in results[0]['img_src'])
78− self.assertTrue('z.jpg' in results[0]['thumbnail_src'])
79− self.assertTrue('Owner' in results[0]['author'])
80− self.assertTrue('Description' in results[0]['content'])
81−
82− json = r"""
83− { "photos": { "page": 1, "pages": "41001", "perpage": 100, "total": "4100032",
84− "photo": [
85− { "id": "15751017054", "owner": "66847915@N08",
86− "secret": "69c22afc40", "server": "7285", "farm": 8,
87− "title": "Photo title", "ispublic": 1,
88− "isfriend": 0, "isfamily": 0,
89− "description": { "_content": "Description" },
90− "ownername": "Owner",
91− "url_o": "https:\/\/farm8.staticflickr.com\/7285\/15751017054_9178e0f963_o.jpg",
92− "height_o": "2100", "width_o": "2653" }
93− ] }, "stat": "ok" }
94− """
95− response = mock.Mock(text=json)
96− results = flickr.response(response)
97− self.assertEqual(type(results), list)
98− self.assertEqual(len(results), 1)
99− self.assertEqual(results[0]['title'], 'Photo title')
100− self.assertEqual(results[0]['url'], 'https://www.flickr.com/photos/66847915@N08/15751017054')
101− self.assertTrue('o.jpg' in results[0]['img_src'])
102− self.assertTrue('o.jpg' in results[0]['thumbnail_src'])
103− self.assertTrue('Owner' in results[0]['author'])
104− self.assertTrue('Description' in results[0]['content'])
105−
106− json = r"""
107− { "photos": { "page": 1, "pages": "41001", "perpage": 100, "total": "4100032",
108− "photo": [
109− { "id": "15751017054", "owner": "66847915@N08",
110− "secret": "69c22afc40", "server": "7285", "farm": 8,
111− "title": "Photo title", "ispublic": 1,
112− "isfriend": 0, "isfamily": 0,
113− "description": { "_content": "Description" },
114− "ownername": "Owner",
115− "url_n": "https:\/\/farm8.staticflickr.com\/7285\/15751017054_69c22afc40_n.jpg",
116− "height_n": "253", "width_n": "320" }
117− ] }, "stat": "ok" }
118− """
119− response = mock.Mock(text=json)
120− results = flickr.response(response)
121− self.assertEqual(type(results), list)
122− self.assertEqual(len(results), 0)
123−
124− json = """
125− { "photos": { "page": 1, "pages": "41001", "perpage": 100, "total": "4100032",
126− "toto": [] }, "stat": "ok" }
127− """
128− response = mock.Mock(text=json)
129− results = flickr.response(response)
130− self.assertEqual(type(results), list)
131− self.assertEqual(len(results), 0)
132−
133− json = r"""
134− {"toto":[
135− {"id":200,"name":"Artist Name",
136− "link":"http:\/\/www.flickr.com\/artist\/1217","type":"artist"}
137− ]}
138− """
139− response = mock.Mock(text=json)
140− results = flickr.response(response)
141− self.assertEqual(type(results), list)
142− self.assertEqual(len(results), 0)
tests/unit/engines/test_flickr_noapi.pydeleted−357
@@ -1,357 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import flickr_noapi
4−from searx.testing import SearxTestCase
5−
6−
7−class TestFlickrNoapiEngine(SearxTestCase):
8−
9− def test_build_flickr_url(self):
10− url = flickr_noapi.build_flickr_url("uid", "pid")
11− self.assertIn("uid", url)
12− self.assertIn("pid", url)
13−
14− def test_request(self):
15− query = 'test_query'
16− dicto = defaultdict(dict)
17− dicto['pageno'] = 1
18− dicto['time_range'] = ''
19− params = flickr_noapi.request(query, dicto)
20− self.assertIn('url', params)
21− self.assertIn(query, params['url'])
22− self.assertIn('flickr.com', params['url'])
23−
24− def test_response(self):
25− self.assertRaises(AttributeError, flickr_noapi.response, None)
26− self.assertRaises(AttributeError, flickr_noapi.response, [])
27− self.assertRaises(AttributeError, flickr_noapi.response, '')
28− self.assertRaises(AttributeError, flickr_noapi.response, '[]')
29−
30− response = mock.Mock(text='"modelExport:{"legend":[],"main":{"search-photos-lite-models":[{"photos":{}}]}}')
31− self.assertEqual(flickr_noapi.response(response), [])
32−
33− response = \
34− mock.Mock(text='"modelExport:{"legend":[],"main":{"search-photos-lite-models":[{"photos":{"_data":[]}}]}}')
35− self.assertEqual(flickr_noapi.response(response), [])
36−
37− # everthing is ok test
38− json = """
39− modelExport: {
40− "legend": [
41− [
42− "search-photos-lite-models",
43− "0",
44− "photos",
45− "_data",
46− "0"
47− ]
48− ],
49− "main": {
50− "search-photos-lite-models": [
51− {
52− "photos": {
53− "_data": [
54− {
55− "_flickrModelRegistry": "photo-lite-models",
56− "title": "This%20is%20the%20title",
57− "username": "Owner",
58− "pathAlias": "klink692",
59− "realname": "Owner",
60− "license": 0,
61− "ownerNsid": "59729010@N00",
62− "canComment": false,
63− "commentCount": 14,
64− "faveCount": 21,
65− "id": "14001294434",
66− "sizes": {
67− "c": {
68− "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_c.jpg",
69− "width": 541,
70− "height": 800,
71− "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_c.jpg",
72− "key": "c"
73− },
74− "h": {
75− "displayUrl": "//farm8.staticflickr.com/7246/14001294434_761d32237a_h.jpg",
76− "width": 1081,
77− "height": 1600,
78− "url": "//c4.staticflickr.com/8/7246/14001294434_761d32237a_h.jpg",
79− "key": "h"
80− },
81− "k": {
82− "displayUrl": "//farm8.staticflickr.com/7246/14001294434_f145a2c11a_k.jpg",
83− "width": 1383,
84− "height": 2048,
85− "url": "//c4.staticflickr.com/8/7246/14001294434_f145a2c11a_k.jpg",
86− "key": "k"
87− },
88− "l": {
89− "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_b.jpg",
90− "width": 692,
91− "height": 1024,
92− "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_b.jpg",
93− "key": "l"
94− },
95− "m": {
96− "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777.jpg",
97− "width": 338,
98− "height": 500,
99− "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777.jpg",
100− "key": "m"
101− },
102− "n": {
103− "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_n.jpg",
104− "width": 216,
105− "height": 320,
106− "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_n.jpg",
107− "key": "n"
108− },
109− "q": {
110− "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_q.jpg",
111− "width": 150,
112− "height": 150,
113− "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_q.jpg",
114− "key": "q"
115− },
116− "s": {
117− "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_m.jpg",
118− "width": 162,
119− "height": 240,
120− "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_m.jpg",
121− "key": "s"
122− },
123− "sq": {
124− "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_s.jpg",
125− "width": 75,
126− "height": 75,
127− "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_s.jpg",
128− "key": "sq"
129− },
130− "t": {
131− "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_t.jpg",
132− "width": 68,
133− "height": 100,
134− "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_t.jpg",
135− "key": "t"
136− },
137− "z": {
138− "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_z.jpg",
139− "width": 433,
140− "height": 640,
141− "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_z.jpg",
142− "key": "z"
143− }
144− }
145− }
146− ]
147− }
148− }
149− ]
150− }
151− }
152− """
153− # Flickr serves search results in a json block named 'modelExport' buried inside a script tag,
154− # this json is served as a single line terminating with a comma.
155− json = ''.join(json.split()) + ',\n'
156− response = mock.Mock(text=json)
157− results = flickr_noapi.response(response)
158− self.assertEqual(type(results), list)
159− self.assertEqual(len(results), 1)
160− self.assertEqual(results[0]['title'], 'This is the title')
161− self.assertEqual(results[0]['url'], 'https://www.flickr.com/photos/59729010@N00/14001294434')
162− self.assertIn('k.jpg', results[0]['img_src'])
163− self.assertIn('n.jpg', results[0]['thumbnail_src'])
164− self.assertIn('Owner', results[0]['author'])
165−
166− # no n size, only the z size
167− json = """
168− modelExport: {
169− "legend": [
170− [
171− "search-photos-lite-models",
172− "0",
173− "photos",
174− "_data",
175− "0"
176− ]
177− ],
178− "main": {
179− "search-photos-lite-models": [
180− {
181− "photos": {
182− "_data": [
183− {
184− "_flickrModelRegistry": "photo-lite-models",
185− "title": "This%20is%20the%20title",
186− "username": "Owner",
187− "pathAlias": "klink692",
188− "realname": "Owner",
189− "license": 0,
190− "ownerNsid": "59729010@N00",
191− "canComment": false,
192− "commentCount": 14,
193− "faveCount": 21,
194− "id": "14001294434",
195− "sizes": {
196− "z": {
197− "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_z.jpg",
198− "width": 433,
199− "height": 640,
200− "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_z.jpg",
201− "key": "z"
202− }
203− }
204− }
205− ]
206− }
207− }
208− ]
209− }
210− }
211− """
212− json = ''.join(json.split()) + ',\n'
213− response = mock.Mock(text=json)
214− results = flickr_noapi.response(response)
215− self.assertEqual(type(results), list)
216− self.assertEqual(len(results), 1)
217− self.assertEqual(results[0]['title'], 'This is the title')
218− self.assertEqual(results[0]['url'], 'https://www.flickr.com/photos/59729010@N00/14001294434')
219− self.assertIn('z.jpg', results[0]['img_src'])
220− self.assertIn('z.jpg', results[0]['thumbnail_src'])
221− self.assertIn('Owner', results[0]['author'])
222−
223− # no z or n size
224− json = """
225− modelExport: {
226− "legend": [
227− [
228− "search-photos-lite-models",
229− "0",
230− "photos",
231− "_data",
232− "0"
233− ]
234− ],
235− "main": {
236− "search-photos-lite-models": [
237− {
238− "photos": {
239− "_data": [
240− {
241− "_flickrModelRegistry": "photo-lite-models",
242− "title": "This%20is%20the%20title",
243− "username": "Owner",
244− "pathAlias": "klink692",
245− "realname": "Owner",
246− "license": 0,
247− "ownerNsid": "59729010@N00",
248− "canComment": false,
249− "commentCount": 14,
250− "faveCount": 21,
251− "id": "14001294434",
252− "sizes": {
253− "o": {
254− "displayUrl": "//farm8.staticflickr.com/7246/14001294434_410f653777_o.jpg",
255− "width": 433,
256− "height": 640,
257− "url": "//c4.staticflickr.com/8/7246/14001294434_410f653777_o.jpg",
258− "key": "o"
259− }
260− }
261− }
262− ]
263− }
264− }
265− ]
266− }
267− }
268− """
269− json = ''.join(json.split()) + ',\n'
270− response = mock.Mock(text=json)
271− results = flickr_noapi.response(response)
272− self.assertEqual(type(results), list)
273− self.assertEqual(len(results), 1)
274− self.assertEqual(results[0]['title'], 'This is the title')
275− self.assertEqual(results[0]['url'], 'https://www.flickr.com/photos/59729010@N00/14001294434')
276− self.assertIn('o.jpg', results[0]['img_src'])
277− self.assertIn('o.jpg', results[0]['thumbnail_src'])
278− self.assertIn('Owner', results[0]['author'])
279−
280− # no image test
281− json = """
282− modelExport: {
283− "legend": [
284− [
285− "search-photos-lite-models",
286− "0",
287− "photos",
288− "_data",
289− "0"
290− ]
291− ],
292− "main": {
293− "search-photos-lite-models": [
294− {
295− "photos": {
296− "_data": [
297− {
298− "_flickrModelRegistry": "photo-lite-models",
299− "title": "This is the title",
300− "username": "Owner",
301− "pathAlias": "klink692",
302− "realname": "Owner",
303− "license": 0,
304− "ownerNsid": "59729010@N00",
305− "canComment": false,
306− "commentCount": 14,
307− "faveCount": 21,
308− "id": "14001294434",
309− "sizes": {
310− }
311− }
312− ]
313− }
314− }
315− ]
316− }
317− }
318− """
319− json = ''.join(json.split()) + ',\n'
320− response = mock.Mock(text=json)
321− results = flickr_noapi.response(response)
322− self.assertEqual(type(results), list)
323− self.assertEqual(len(results), 0)
324−
325− # null test
326− json = """
327− modelExport: {
328− "legend": [null],
329− "main": {
330− "search-photos-lite-models": [
331− {
332− "photos": {
333− "_data": [null]
334− }
335− }
336− ]
337− }
338− }
339− """
340− json = ''.join(json.split()) + ',\n'
341− response = mock.Mock(text=json)
342− results = flickr_noapi.response(response)
343− self.assertEqual(type(results), list)
344− self.assertEqual(len(results), 0)
345−
346− # garbage test
347− json = r"""
348− {"toto":[
349− {"id":200,"name":"Artist Name",
350− "link":"http:\/\/www.flickr.com\/artist\/1217","type":"artist"}
351− ]}
352− """
353− json = ''.join(json.split()) + ',\n'
354− response = mock.Mock(text=json)
355− results = flickr_noapi.response(response)
356− self.assertEqual(type(results), list)
357− self.assertEqual(len(results), 0)
tests/unit/engines/test_framalibre.pydeleted−103
@@ -1,103 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import framalibre
5−from searx.testing import SearxTestCase
6−
7−
8−class TestFramalibreEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dicto = defaultdict(dict)
13− dicto['pageno'] = 0
14− params = framalibre.request(query, dicto)
15− self.assertTrue('url' in params)
16− self.assertTrue(query in params['url'])
17− self.assertTrue('framalibre.org' in params['url'])
18−
19− def test_response(self):
20− self.assertRaises(AttributeError, framalibre.response, None)
21− self.assertRaises(AttributeError, framalibre.response, [])
22− self.assertRaises(AttributeError, framalibre.response, '')
23− self.assertRaises(AttributeError, framalibre.response, '[]')
24−
25− response = mock.Mock(text='{}')
26− self.assertEqual(framalibre.response(response), [])
27−
28− response = mock.Mock(text='{"data": []}')
29− self.assertEqual(framalibre.response(response), [])
30−
31− html = u"""
32− <div class="nodes-list-row">
33− <div id="node-431"
34− class="node node-logiciel-annuaires node-promoted node-teaser node-teaser node-sheet clearfix nodes-list"
35− about="/content/gogs" typeof="sioc:Item foaf:Document">
36− <header class="media">
37− <div class="media-left">
38− <div class="field field-name-field-logo field-type-image field-label-hidden">
39− <div class="field-items">
40− <div class="field-item even">
41− <a href="/content/gogs">
42− <img class="media-object img-responsive" typeof="foaf:Image"
43− src="https://framalibre.org/sites/default/files/styles/teaser_logo/public/leslogos/gogs-lg.png?itok=rrCxKKBy"
44− width="70" height="70" alt="" />
45− </a>
46− </div>
47− </div>
48− </div>
49− </div>
50− <div class="media-body">
51− <h3 class="node-title"><a href="/content/gogs">Gogs</a></h3>
52− <span property="dc:title" content="Gogs" class="rdf-meta element-hidden"></span>
53− <div class="field field-name-field-annuaires field-type-taxonomy-term-reference field-label-hidden">
54− <div class="field-items">
55− <div class="field-item even">
56− <a href="/annuaires/cloudwebapps"
57− typeof="skos:Concept" property="rdfs:label skos:prefLabel"
58− datatype="" class="label label-primary">Cloud/webApps</a>
59− </div>
60− </div>
61− </div>
62− </div>
63− </header>
64− <div class="content">
65− <div class="field field-name-field-votre-appr-ciation field-type-fivestar field-label-hidden">
66− <div class="field-items">
67− <div class="field-item even">
68− </div>
69− </div>
70− </div>
71− <div class="field field-name-body field-type-text-with-summary field-label-hidden">
72− <div class="field-items">
73− <div class="field-item even" property="content:encoded">
74− <p>Gogs est une interface web basée sur git et une bonne alternative à GitHub.</p>
75− </div>
76− </div>
77− </div>
78− </div>
79− <footer>
80− <a href="/content/gogs" class="read-more btn btn-default btn-sm">Voir la notice</a>
81− <div class="field field-name-field-lien-officiel field-type-link-field field-label-hidden">
82− <div class="field-items">
83− <div class="field-item even">
84− <a href="https://gogs.io/" target="_blank" title="Voir le site officiel">
85− <span class="glyphicon glyphicon-globe"></span>
86− <span class="sr-only">Lien officiel</span>
87− </a>
88− </div>
89− </div>
90− </div>
91− </footer>
92− </div>
93− </div>
94− """
95− response = mock.Mock(text=html)
96− results = framalibre.response(response)
97− self.assertEqual(type(results), list)
98− self.assertEqual(len(results), 1)
99− self.assertEqual(results[0]['title'], 'Gogs')
100− self.assertEqual(results[0]['url'],
101− 'https://framalibre.org/content/gogs')
102− self.assertEqual(results[0]['content'],
103− u"Gogs est une interface web basée sur git et une bonne alternative à GitHub.")
tests/unit/engines/test_frinkiac.pydeleted−50
@@ -1,50 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import frinkiac
5−from searx.testing import SearxTestCase
6−
7−
8−class TestFrinkiacEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− request_dict = defaultdict(dict)
13− params = frinkiac.request(query, request_dict)
14− self.assertTrue('url' in params)
15−
16− def test_response(self):
17− self.assertRaises(AttributeError, frinkiac.response, None)
18− self.assertRaises(AttributeError, frinkiac.response, [])
19− self.assertRaises(AttributeError, frinkiac.response, '')
20− self.assertRaises(AttributeError, frinkiac.response, '[]')
21−
22− text = """
23−[{"Id":770931,
24− "Episode":"S06E18",
25− "Timestamp":534616,
26− "Filename":""},
27− {"Id":1657080,
28− "Episode":"S12E14",
29− "Timestamp":910868,
30− "Filename":""},
31− {"Id":1943753,
32− "Episode":"S14E21",
33− "Timestamp":773439,
34− "Filename":""},
35− {"Id":107835,
36− "Episode":"S02E03",
37− "Timestamp":531709,
38− "Filename":""}]
39− """
40−
41− response = mock.Mock(text=text)
42− results = frinkiac.response(response)
43− self.assertEqual(type(results), list)
44− self.assertEqual(len(results), 4)
45− self.assertEqual(results[0]['title'], u'S06E18')
46− self.assertIn('p=caption', results[0]['url'])
47− self.assertIn('e=S06E18', results[0]['url'])
48− self.assertIn('t=534616', results[0]['url'])
49− self.assertEqual(results[0]['thumbnail_src'], 'https://frinkiac.com/img/S06E18/534616/medium.jpg')
50− self.assertEqual(results[0]['img_src'], 'https://frinkiac.com/img/S06E18/534616.jpg')
tests/unit/engines/test_genius.pydeleted−231
@@ -1,231 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from datetime import datetime
4−from searx.engines import genius
5−from searx.testing import SearxTestCase
6−
7−
8−class TestGeniusEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dicto = defaultdict(dict)
13− dicto['pageno'] = 1
14− params = genius.request(query, dicto)
15− self.assertTrue('url' in params)
16− self.assertTrue(query in params['url'])
17− self.assertTrue('genius.com' in params['url'])
18−
19− def test_response(self):
20−
21− json_empty = """
22− {
23− "meta": {
24− "status": 200
25− },
26− "response": {
27− "sections": [
28− {
29− "type": "top_hit",
30− "hits": []
31− },
32− {
33− "type": "song",
34− "hits": []
35− },
36− {
37− "type": "lyric",
38− "hits": []
39− },
40− {
41− "type": "artist",
42− "hits": []
43− },
44− {
45− "type": "album",
46− "hits": []
47− },
48− {
49− "type": "tag",
50− "hits": []
51− },
52− {
53− "type": "video",
54− "hits": []
55− },
56− {
57− "type": "article",
58− "hits": []
59− },
60− {
61− "type": "user",
62− "hits": []
63− }
64− ]
65− }
66− }
67− """
68−
69− resp = mock.Mock(text=json_empty)
70− self.assertEqual(genius.response(resp), [])
71−
72− json = """
73− {
74− "meta": {
75− "status": 200
76− },
77− "response": {
78− "sections": [
79− {
80− "type": "lyric",
81− "hits": [
82− {
83− "highlights": [
84− {
85− "property": "lyrics",
86− "value": "Sample lyrics",
87− "snippet": true,
88− "ranges": []
89− }
90− ],
91− "index": "lyric",
92− "type": "song",
93− "result": {
94− "_type": "song",
95− "annotation_count": 45,
96− "api_path": "/songs/52916",
97− "full_title": "J't'emmerde by MC Jean Gab'1",
98− "header_image_thumbnail_url": "https://images.genius.com/xxx.300x300x1.jpg",
99− "header_image_url": "https://images.genius.com/ef9f736a86df3c3b1772f3fb7fbdb21c.1000x1000x1.jpg",
100− "id": 52916,
101− "instrumental": false,
102− "lyrics_owner_id": 15586,
103− "lyrics_state": "complete",
104− "lyrics_updated_at": 1498744545,
105− "path": "/Mc-jean-gab1-jtemmerde-lyrics",
106− "pyongs_count": 4,
107− "song_art_image_thumbnail_url": "https://images.genius.com/xxx.300x300x1.jpg",
108− "stats": {
109− "hot": false,
110− "unreviewed_annotations": 0,
111− "pageviews": 62490
112− },
113− "title": "J't'emmerde",
114− "title_with_featured": "J't'emmerde",
115− "updated_by_human_at": 1498744546,
116− "url": "https://genius.com/Mc-jean-gab1-jtemmerde-lyrics",
117− "primary_artist": {
118− "_type": "artist",
119− "api_path": "/artists/12691",
120− "header_image_url": "https://images.genius.com/c7847662a58f8c2b0f02a6e217d60907.960x657x1.jpg",
121− "id": 12691,
122− "image_url": "https://s3.amazonaws.com/rapgenius/Mc-jean-gab1.jpg",
123− "index_character": "m",
124− "is_meme_verified": false,
125− "is_verified": false,
126− "name": "MC Jean Gab'1",
127− "slug": "Mc-jean-gab1",
128− "url": "https://genius.com/artists/Mc-jean-gab1"
129− }
130− }
131− }
132− ]
133− },
134− {
135− "type": "artist",
136− "hits": [
137− {
138− "highlights": [],
139− "index": "artist",
140− "type": "artist",
141− "result": {
142− "_type": "artist",
143− "api_path": "/artists/191580",
144− "header_image_url": "https://assets.genius.com/images/default_avatar_300.png?1503090542",
145− "id": 191580,
146− "image_url": "https://assets.genius.com/images/default_avatar_300.png?1503090542",
147− "index_character": "a",
148− "is_meme_verified": false,
149− "is_verified": false,
150− "name": "ASDF Guy",
151− "slug": "Asdf-guy",
152− "url": "https://genius.com/artists/Asdf-guy"
153− }
154− }
155− ]
156− },
157− {
158− "type": "album",
159− "hits": [
160− {
161− "highlights": [],
162− "index": "album",
163− "type": "album",
164− "result": {
165− "_type": "album",
166− "api_path": "/albums/132332",
167− "cover_art_thumbnail_url": "https://images.genius.com/xxx.300x300x1.jpg",
168− "cover_art_url": "https://images.genius.com/xxx.600x600x1.jpg",
169− "full_title": "ASD by A Skylit Drive",
170− "id": 132332,
171− "name": "ASD",
172− "name_with_artist": "ASD (artist: A Skylit Drive)",
173− "release_date_components": {
174− "year": 2015,
175− "month": null,
176− "day": null
177− },
178− "url": "https://genius.com/albums/A-skylit-drive/Asd",
179− "artist": {
180− "_type": "artist",
181− "api_path": "/artists/48712",
182− "header_image_url": "https://images.genius.com/814c1551293172c56306d0e310c6aa89.620x400x1.jpg",
183− "id": 48712,
184− "image_url": "https://images.genius.com/814c1551293172c56306d0e310c6aa89.620x400x1.jpg",
185− "index_character": "s",
186− "is_meme_verified": false,
187− "is_verified": false,
188− "name": "A Skylit Drive",
189− "slug": "A-skylit-drive",
190− "url": "https://genius.com/artists/A-skylit-drive"
191− }
192− }
193− }
194− ]
195− }
196− ]
197− }
198− }
199− """
200−
201− resp = mock.Mock(text=json)
202− results = genius.response(resp)
203−
204− self.assertEqual(len(results), 3)
205− self.assertEqual(type(results), list)
206−
207− # check lyric parsing
208− r = results[0]
209− self.assertEqual(r['url'], 'https://genius.com/Mc-jean-gab1-jtemmerde-lyrics')
210− self.assertEqual(r['title'], "J't'emmerde by MC Jean Gab'1")
211− self.assertEqual(r['content'], "Sample lyrics")
212− self.assertEqual(r['template'], 'videos.html')
213− self.assertEqual(r['thumbnail'], 'https://images.genius.com/xxx.300x300x1.jpg')
214− created = datetime.fromtimestamp(1498744545)
215− self.assertEqual(r['publishedDate'], created)
216−
217− # check artist parsing
218− r = results[1]
219− self.assertEqual(r['url'], 'https://genius.com/artists/Asdf-guy')
220− self.assertEqual(r['title'], "ASDF Guy")
221− self.assertEqual(r['content'], None)
222− self.assertEqual(r['template'], 'videos.html')
223− self.assertEqual(r['thumbnail'], 'https://assets.genius.com/images/default_avatar_300.png?1503090542')
224−
225− # check album parsing
226− r = results[2]
227− self.assertEqual(r['url'], 'https://genius.com/albums/A-skylit-drive/Asd')
228− self.assertEqual(r['title'], "ASD by A Skylit Drive")
229− self.assertEqual(r['content'], "Released: 2015")
230− self.assertEqual(r['template'], 'videos.html')
231− self.assertEqual(r['thumbnail'], 'https://images.genius.com/xxx.600x600x1.jpg')
tests/unit/engines/test_gigablast.pydeleted−119
@@ -1,119 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import gigablast
4−from searx.testing import SearxTestCase
5−
6−
7−class TestGigablastEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dicto = defaultdict(dict)
12− dicto['pageno'] = 0
13− dicto['safesearch'] = 0
14− dicto['language'] = 'all'
15− params = gigablast.request(query, dicto)
16− self.assertTrue('url' in params)
17− self.assertTrue(query in params['url'])
18− self.assertTrue('gigablast.com' in params['url'])
19− self.assertTrue('xx' in params['url'])
20−
21− dicto['language'] = 'en-US'
22− params = gigablast.request(query, dicto)
23− self.assertTrue('en' in params['url'])
24− self.assertFalse('en-US' in params['url'])
25−
26− def test_response(self):
27− self.assertRaises(AttributeError, gigablast.response, None)
28− self.assertRaises(AttributeError, gigablast.response, [])
29− self.assertRaises(AttributeError, gigablast.response, '')
30− self.assertRaises(AttributeError, gigablast.response, '[]')
31−
32− response = mock.Mock(text='{"results": []}')
33− self.assertEqual(gigablast.response(response), [])
34−
35− json = """{"results": [
36− {
37− "title":"South by Southwest 2016",
38− "dmozEntry":{
39− "dmozCatId":1041152,
40− "directCatId":1,
41− "dmozCatStr":"Top: Regional: North America: United States",
42− "dmozTitle":"South by Southwest (SXSW)",
43− "dmozSum":"Annual music, film, and interactive conference.",
44− "dmozAnchor":""
45− },
46− "dmozEntry":{
47− "dmozCatId":763945,
48− "directCatId":1,
49− "dmozCatStr":"Top: Regional: North America: United States",
50− "dmozTitle":"South by Southwest (SXSW)",
51− "dmozSum":"",
52− "dmozAnchor":"www.sxsw.com"
53− },
54− "dmozEntry":{
55− "dmozCatId":761446,
56− "directCatId":1,
57− "dmozCatStr":"Top: Regional: North America: United States",
58− "dmozTitle":"South by Southwest (SXSW)",
59− "dmozSum":"Music, film, and interactive conference and festival.",
60− "dmozAnchor":""
61− },
62− "indirectDmozCatId":1041152,
63− "indirectDmozCatId":763945,
64− "indirectDmozCatId":761446,
65− "contentType":"html",
66− "sum":"This should be the content.",
67− "url":"www.sxsw.com",
68− "hopCount":0,
69− "size":" 102k",
70− "sizeInBytes":104306,
71− "bytesUsedToComputeSummary":70000,
72− "docId":269411794364,
73− "docScore":586571136.000000,
74− "summaryGenTimeMS":12,
75− "summaryTagdbLookupTimeMS":0,
76− "summaryTitleRecLoadTimeMS":1,
77− "site":"www.sxsw.com",
78− "spidered":1452203608,
79− "firstIndexedDateUTC":1444167123,
80− "contentHash32":2170650347,
81− "language":"English",
82− "langAbbr":"en"
83− }
84−]}
85− """
86− response = mock.Mock(text=json)
87− results = gigablast.response(response)
88− self.assertEqual(type(results), list)
89− self.assertEqual(len(results), 1)
90− self.assertEqual(results[0]['title'], 'South by Southwest 2016')
91− self.assertEqual(results[0]['url'], 'www.sxsw.com')
92− self.assertEqual(results[0]['content'], 'This should be the content.')
93−
94− def test_fetch_supported_languages(self):
95− html = """<html></html>"""
96− response = mock.Mock(text=html)
97− results = gigablast._fetch_supported_languages(response)
98− self.assertEqual(type(results), list)
99− self.assertEqual(len(results), 0)
100−
101− html = """
102− <html>
103− <body>
104− <span id="menu2">
105− <a href="/search?&rxikd=1&qlang=xx"></a>
106− <a href="/search?&rxikd=1&qlang=en"></a>
107− <a href="/search?&rxikd=1&prepend=gblang%3Aen"></a>
108− <a href="/search?&rxikd=1&qlang=zh_"></a>
109− <a href="/search?&rxikd=1&prepend=gblang%3Azh_tw"></a>
110− </span>
111− </body>
112− </html>
113− """
114− response = mock.Mock(text=html)
115− languages = gigablast._fetch_supported_languages(response)
116− self.assertEqual(type(languages), list)
117− self.assertEqual(len(languages), 2)
118− self.assertIn('en', languages)
119− self.assertIn('zh-TW', languages)
tests/unit/engines/test_github.pydeleted−61
@@ -1,61 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import github
4−from searx.testing import SearxTestCase
5−
6−
7−class TestGitHubEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− params = github.request(query, defaultdict(dict))
12− self.assertTrue('url' in params)
13− self.assertTrue(query in params['url'])
14− self.assertTrue('github.com' in params['url'])
15− self.assertEqual(params['headers']['Accept'], github.accept_header)
16−
17− def test_response(self):
18− self.assertRaises(AttributeError, github.response, None)
19− self.assertRaises(AttributeError, github.response, [])
20− self.assertRaises(AttributeError, github.response, '')
21− self.assertRaises(AttributeError, github.response, '[]')
22−
23− response = mock.Mock(text='{}')
24− self.assertEqual(github.response(response), [])
25−
26− response = mock.Mock(text='{"items": []}')
27− self.assertEqual(github.response(response), [])
28−
29− json = """
30− {
31− "items": [
32− {
33− "name": "title",
34− "html_url": "url",
35− "description": ""
36− }
37− ]
38− }
39− """
40− response = mock.Mock(text=json)
41− results = github.response(response)
42− self.assertEqual(type(results), list)
43− self.assertEqual(len(results), 1)
44− self.assertEqual(results[0]['title'], 'title')
45− self.assertEqual(results[0]['url'], 'url')
46− self.assertEqual(results[0]['content'], '')
47−
48− json = """
49− {
50− "items": [
51− {
52− "name": "title",
53− "html_url": "url",
54− "description": "desc"
55− }
56− ]
57− }
58− """
59− response = mock.Mock(text=json)
60− results = github.response(response)
61− self.assertEqual(results[0]['content'], "desc")
tests/unit/engines/test_google.pydeleted−237
@@ -1,237 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−import lxml
5−from searx.engines import google
6−from searx.testing import SearxTestCase
7−
8−
9−class TestGoogleEngine(SearxTestCase):
10−
11− def mock_response(self, text):
12− response = mock.Mock(text=text, url='https://www.google.com/search?q=test&start=0&gbv=1&gws_rd=cr')
13− response.search_params = mock.Mock()
14− response.search_params.get = mock.Mock(return_value='www.google.com')
15− return response
16−
17− def test_request(self):
18− google.supported_languages = ['en', 'fr', 'zh-CN', 'iw']
19− google.language_aliases = {'he': 'iw'}
20−
21− query = 'test_query'
22− dicto = defaultdict(dict)
23− dicto['pageno'] = 1
24− dicto['language'] = 'fr-FR'
25− dicto['time_range'] = ''
26− params = google.request(query, dicto)
27− self.assertIn('url', params)
28− self.assertIn(query, params['url'])
29− self.assertIn('google.fr', params['url'])
30− self.assertIn('fr', params['url'])
31− self.assertIn('fr', params['headers']['Accept-Language'])
32−
33− dicto['language'] = 'en-US'
34− params = google.request(query, dicto)
35− self.assertIn('google.com', params['url'])
36− self.assertIn('en', params['url'])
37− self.assertIn('en', params['headers']['Accept-Language'])
38−
39− dicto['language'] = 'zh'
40− params = google.request(query, dicto)
41− self.assertIn('google.com', params['url'])
42− self.assertIn('zh-CN', params['url'])
43− self.assertIn('zh-CN', params['headers']['Accept-Language'])
44−
45− dicto['language'] = 'he'
46− params = google.request(query, dicto)
47− self.assertIn('google.com', params['url'])
48− self.assertIn('iw', params['url'])
49− self.assertIn('iw', params['headers']['Accept-Language'])
50−
51− def test_response(self):
52− self.assertRaises(AttributeError, google.response, None)
53− self.assertRaises(AttributeError, google.response, [])
54− self.assertRaises(AttributeError, google.response, '')
55− self.assertRaises(AttributeError, google.response, '[]')
56−
57− response = self.mock_response('<html></html>')
58− self.assertEqual(google.response(response), [])
59−
60− html = """
61− <div class="g">
62− <h3 class="r">
63− <a href="http://this.should.be.the.link/">
64− <b>This</b> is <b>the</b> title
65− </a>
66− </h3>
67− <div class="s">
68− <div class="kv" style="margin-bottom:2px">
69− <cite>
70− <b>test</b>.psychologies.com/
71− </cite>
72− <div class="_nBb"><U+200E>
73− <div style="display:inline" onclick="google.sham(this);" aria-expanded="false"
74− aria-haspopup="true" tabindex="0" data-ved="0CBUQ7B0wAA">
75− <span class="_O0">
76− </span>
77− </div>
78− <div style="display:none" class="am-dropdown-menu" role="menu" tabindex="-1">
79− <ul>
80− <li class="_Ykb">
81− <a class="_Zkb" href="http://www.google.fr/url?url=http://webcache.googleusercontent
82− .com/search%3Fcache:R1Z_4pGXjuIJ:http://test.psychologies.com/">
83− En cache
84− </a>
85− </li>
86− <li class="_Ykb">
87− <a class="_Zkb" href="/search?safe=off&amp;q=related:test.psy.com/">
88− Pages similaires
89− </a>
90− </li>
91− </ul>
92− </div>
93− </div>
94− </div>
95− <span class="st">
96− This should be the content.
97− </span>
98− <br>
99− <div class="osl"><U+200E>
100− <a href="http://www.google.fr/url?url=http://test.psychologies.com/tests/">
101− Test Personnalité
102− </a> - <U+200E>
103− <a href="http://www.google.fr/url?url=http://test.psychologies.com/test/">
104− Tests - Moi
105− </a> - <U+200E>
106− <a href="http://www.google.fr/url?url=http://test.psychologies.com/test/tests-couple">
107− Test Couple
108− </a>
109− - <U+200E>
110− <a href="http://www.google.fr/url?url=http://test.psychologies.com/tests/tests-amour">
111− Test Amour
112− </a>
113− </div>
114− </div>
115− </div>
116− <div class="g">
117− <h3 class="r">
118− <a href="http://www.google.com/images?q=toto">
119− <b>This</b>
120− </a>
121− </h3>
122− </div>
123− <div class="g">
124− <h3 class="r">
125− <a href="http://www.google.com/search?q=toto">
126− <b>This</b> is
127− </a>
128− </h3>
129− </div>
130− <div class="g">
131− <h3 class="r">
132− <a href="€">
133− <b>This</b> is <b>the</b>
134− </a>
135− </h3>
136− </div>
137− <div class="g">
138− <h3 class="r">
139− <a href="/url?q=url">
140− <b>This</b> is <b>the</b>
141− </a>
142− </h3>
143− </div>
144− <p class="_Bmc" style="margin:3px 8px">
145− <a href="/search?num=20&amp;safe=off&amp;q=t&amp;revid=1754833769&amp;sa=X&amp;ei=-&amp;ved=">
146− suggestion <b>title</b>
147− </a>
148− </p>
149− """
150− response = self.mock_response(html)
151− results = google.response(response)
152− self.assertEqual(type(results), list)
153− self.assertEqual(len(results), 2)
154− self.assertEqual(results[0]['title'], 'This is the title')
155− self.assertEqual(results[0]['url'], 'http://this.should.be.the.link/')
156− self.assertEqual(results[0]['content'], 'This should be the content.')
157− self.assertEqual(results[1]['suggestion'], 'suggestion title')
158−
159− html = """
160− <li class="b_algo" u="0|5109|4755453613245655|UAGjXgIrPH5yh-o5oNHRx_3Zta87f_QO">
161− </li>
162− """
163− response = self.mock_response(html)
164− results = google.response(response)
165− self.assertEqual(type(results), list)
166− self.assertEqual(len(results), 0)
167−
168− response = mock.Mock(text='<html></html>', url='https://sorry.google.com')
169− response.search_params = mock.Mock()
170− response.search_params.get = mock.Mock(return_value='www.google.com')
171− self.assertRaises(RuntimeWarning, google.response, response)
172−
173− response = mock.Mock(text='<html></html>', url='https://www.google.com/sorry/IndexRedirect')
174− response.search_params = mock.Mock()
175− response.search_params.get = mock.Mock(return_value='www.google.com')
176− self.assertRaises(RuntimeWarning, google.response, response)
177−
178− def test_parse_images(self):
179− html = """
180− <li>
181− <div>
182− <a href="http://www.google.com/url?q=http://this.is.the.url/">
183− <img style="margin:3px 0;margin-right:6px;padding:0" height="90"
184− src="https://this.is.the.image/image.jpg" width="60" align="middle" alt="" border="0">
185− </a>
186− </div>
187− </li>
188− """
189− dom = lxml.html.fromstring(html)
190− results = google.parse_images(dom, 'www.google.com')
191− self.assertEqual(type(results), list)
192− self.assertEqual(len(results), 1)
193− self.assertEqual(results[0]['url'], 'http://this.is.the.url/')
194− self.assertEqual(results[0]['title'], '')
195− self.assertEqual(results[0]['content'], '')
196− self.assertEqual(results[0]['img_src'], 'https://this.is.the.image/image.jpg')
197−
198− def test_fetch_supported_languages(self):
199− html = """<html></html>"""
200− response = mock.Mock(text=html)
201− languages = google._fetch_supported_languages(response)
202− self.assertEqual(type(languages), dict)
203− self.assertEqual(len(languages), 0)
204−
205− html = u"""
206− <html>
207− <body>
208− <div id="langSec">
209− <div>
210− <input name="lr" data-name="english" value="lang_en" />
211− <input name="lr" data-name="中文 (简体)" value="lang_zh-CN" />
212− <input name="lr" data-name="中文 (繁體)" value="lang_zh-TW" />
213− </div>
214− </div>
215− </body>
216− </html>
217− """
218− response = mock.Mock(text=html)
219− languages = google._fetch_supported_languages(response)
220− self.assertEqual(type(languages), dict)
221− self.assertEqual(len(languages), 3)
222−
223− self.assertIn('en', languages)
224− self.assertIn('zh-CN', languages)
225− self.assertIn('zh-TW', languages)
226−
227− self.assertEquals(type(languages['en']), dict)
228− self.assertEquals(type(languages['zh-CN']), dict)
229− self.assertEquals(type(languages['zh-TW']), dict)
230−
231− self.assertIn('name', languages['en'])
232− self.assertIn('name', languages['zh-CN'])
233− self.assertIn('name', languages['zh-TW'])
234−
235− self.assertEquals(languages['en']['name'], 'English')
236− self.assertEquals(languages['zh-CN']['name'], u'中文 (简体)')
237− self.assertEquals(languages['zh-TW']['name'], u'中文 (繁體)')
tests/unit/engines/test_google_images.pydeleted−27
@@ -1,27 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import google_images
4−from searx.testing import SearxTestCase
5−
6−
7−class TestGoogleImagesEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dicto = defaultdict(dict)
12− dicto['pageno'] = 1
13− dicto['safesearch'] = 1
14− dicto['time_range'] = ''
15− params = google_images.request(query, dicto)
16− self.assertIn('url', params)
17− self.assertIn(query, params['url'])
18−
19− dicto['safesearch'] = 0
20− params = google_images.request(query, dicto)
21− self.assertNotIn('safe', params['url'])
22−
23− def test_response(self):
24− self.assertRaises(AttributeError, google_images.response, None)
25− self.assertRaises(AttributeError, google_images.response, [])
26− self.assertRaises(AttributeError, google_images.response, '')
27− self.assertRaises(AttributeError, google_images.response, '[]')
tests/unit/engines/test_google_news.pydeleted−102
@@ -1,102 +0,0 @@
1−# -*- coding: utf-8 -*-
2−
3−from collections import defaultdict
4−import mock
5−from searx.engines import google_news
6−from searx.testing import SearxTestCase
7−
8−
9−class TestGoogleNewsEngine(SearxTestCase):
10−
11− def test_request(self):
12− google_news.supported_languages = ['en-US', 'fr-FR']
13− google_news.language_aliases = {}
14− query = 'test_query'
15− dicto = defaultdict(dict)
16− dicto['pageno'] = 1
17− dicto['language'] = 'fr-FR'
18− dicto['time_range'] = 'w'
19− params = google_news.request(query, dicto)
20− self.assertIn('url', params)
21− self.assertIn(query, params['url'])
22− self.assertIn('fr', params['url'])
23−
24− dicto['language'] = 'all'
25− params = google_news.request(query, dicto)
26− self.assertIn('url', params)
27− self.assertNotIn('fr', params['url'])
28−
29− def test_response(self):
30− self.assertRaises(AttributeError, google_news.response, None)
31− self.assertRaises(AttributeError, google_news.response, [])
32− self.assertRaises(AttributeError, google_news.response, '')
33− self.assertRaises(AttributeError, google_news.response, '[]')
34−
35− response = mock.Mock(text='{}')
36− self.assertEqual(google_news.response(response), [])
37−
38− response = mock.Mock(text='{"data": []}')
39− self.assertEqual(google_news.response(response), [])
40−
41− html = u"""
42−<h2 class="hd">Search Results</h2>
43−<div data-async-context="query:searx" id="ires">
44− <div eid="oC2oWcGXCafR6ASkwoCwDA" id="rso">
45− <div class="_NId">
46− <!--m-->
47− <div class="g _cy">
48− <div class="ts _JGs _JHs _tJs _KGs _jHs">
49− <div class="_hJs">
50− <h3 class="r _gJs">
51− <a class="l lLrAF" href="https://example.com/" onmousedown="return rwt(this,'','','','11','AFQjCNEyehpzD5cJK1KUfXBx9RmsbqqG9g','','0ahUKEwjB58OR54HWAhWnKJoKHSQhAMY4ChCpAggiKAAwAA','','',event)">Example title</a>
52− </h3>
53− <div class="slp">
54− <span class="_OHs _PHs">
55− Mac &amp; i</span>
56− <span class="_QGs">
57− -</span>
58− <span class="f nsa _QHs">
59− Mar 21, 2016</span>
60− </div>
61− <div class="st">Example description</div>
62− </div>
63− </div>
64− </div>
65− <div class="g _cy">
66− <div class="ts _JGs _JHs _oGs _KGs _jHs">
67− <a class="top _xGs _SHs" href="https://example2.com/" onmousedown="return rwt(this,'','','','12','AFQjCNHObfH7sYmLWI1SC-YhWXKZFRzRjw','','0ahUKEwjB58OR54HWAhWnKJoKHSQhAMY4ChC8iAEIJDAB','','',event)">
68− <img class="th _RGs" src="https://example2.com/image.jpg" alt="Story image for searx from Golem.de" onload="typeof google==='object'&&google.aft&&google.aft(this)">
69− </a>
70− <div class="_hJs">
71− <h3 class="r _gJs">
72− <a class="l lLrAF" href="https://example2.com/" onmousedown="return rwt(this,'','','','12','AFQjCNHObfH7sYmLWI1SC-YhWXKZFRzRjw','','0ahUKEwjB58OR54HWAhWnKJoKHSQhAMY4ChCpAgglKAAwAQ','','',event)">Example title 2</a>
73− </h3>
74− <div class="slp">
75− <span class="_OHs _PHs">
76− Golem.de</span>
77− <span class="_QGs">
78− -</span>
79− <span class="f nsa _QHs">
80− Oct 4, 2016</span>
81− </div>
82− <div class="st">Example description 2</div>
83− </div>
84− </div>
85− </div>
86− </div>
87− </div>
88−</div>
89−
90−
91− """ # noqa
92− response = mock.Mock(text=html)
93− results = google_news.response(response)
94− self.assertEqual(type(results), list)
95− self.assertEqual(len(results), 2)
96− self.assertEqual(results[0]['title'], u'Example title')
97− self.assertEqual(results[0]['url'], 'https://example.com/')
98− self.assertEqual(results[0]['content'], 'Example description')
99− self.assertEqual(results[1]['title'], u'Example title 2')
100− self.assertEqual(results[1]['url'], 'https://example2.com/')
101− self.assertEqual(results[1]['content'], 'Example description 2')
102− self.assertEqual(results[1]['img_src'], 'https://example2.com/image.jpg')
tests/unit/engines/test_google_videos.pydeleted−79
@@ -1,79 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import google_videos
4−from searx.testing import SearxTestCase
5−
6−
7−class TestGoogleVideosEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dicto = defaultdict(dict)
12− dicto['pageno'] = 1
13− dicto['safesearch'] = 1
14− dicto['time_range'] = ''
15− params = google_videos.request(query, dicto)
16− self.assertIn('url', params)
17− self.assertIn(query, params['url'])
18−
19− dicto['safesearch'] = 0
20− params = google_videos.request(query, dicto)
21− self.assertNotIn('safe', params['url'])
22−
23− def test_response(self):
24− self.assertRaises(AttributeError, google_videos.response, None)
25− self.assertRaises(AttributeError, google_videos.response, [])
26− self.assertRaises(AttributeError, google_videos.response, '')
27− self.assertRaises(AttributeError, google_videos.response, '[]')
28−
29− html = r"""
30− <div>
31− <div>
32− <div class="g">
33− <div class="r">
34− <a href="url_1"><h3>Title 1</h3></a>
35− </div>
36− <div class="s">
37− <div>
38− <a>
39− <g-img>
40− <img id="vidthumb1">
41− </g-img>
42− </a>
43− </div>
44− </div>
45− <div>
46− <span class="st">Content 1</span>
47− </div>
48− </div>
49− <div class="g">
50− <div class="r">
51− <a href="url_2"><h3>Title 2</h3></a>
52− </div>
53− <div class="s">
54− <div>
55− <a>
56− <g-img>
57− <img id="vidthumb2">
58− </g-img>
59− </a>
60− </div>
61− </div>
62− <div>
63− <span class="st">Content 2</span>
64− </div>
65− </div>
66− </div>
67− </div>
68− <script>function _setImagesSrc(c,d,e){}</script>
69− """
70− response = mock.Mock(text=html)
71− results = google_videos.response(response)
72− self.assertEqual(type(results), list)
73− self.assertEqual(len(results), 2)
74− self.assertEqual(results[0]['url'], u'url_1')
75− self.assertEqual(results[0]['title'], u'Title 1')
76− self.assertEqual(results[0]['content'], u'Content 1')
77− self.assertEqual(results[1]['url'], u'url_2')
78− self.assertEqual(results[1]['title'], u'Title 2')
79− self.assertEqual(results[1]['content'], u'Content 2')
tests/unit/engines/test_ina.pydeleted−64
@@ -1,64 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import ina
4−from searx.testing import SearxTestCase
5−
6−
7−class TestInaEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dicto = defaultdict(dict)
12− dicto['pageno'] = 0
13− params = ina.request(query, dicto)
14− self.assertTrue('url' in params)
15− self.assertTrue(query in params['url'])
16− self.assertTrue('ina.fr' in params['url'])
17−
18− def test_response(self):
19− self.assertRaises(AttributeError, ina.response, None)
20− self.assertRaises(AttributeError, ina.response, [])
21− self.assertRaises(AttributeError, ina.response, '')
22− self.assertRaises(AttributeError, ina.response, '[]')
23−
24− response = mock.Mock(text='{}')
25− self.assertEqual(ina.response(response), [])
26−
27− response = mock.Mock(text='{"data": []}')
28− self.assertEqual(ina.response(response), [])
29−
30− json = """
31− {"content":"\\t<div class=\\"container\\">\\n\\t\\n\
32− <!-- DEBUT CONTENU PRINCIPAL -->\\n<div class=\\"row\\">\\n\
33− <div class=\\"search-results--list\\"><div class=\\"media\\">\\n\
34− \\t\\t\\t\\t<a class=\\"media-left media-video premium xiti_click_action\\" \
35− data-xiti-params=\\"recherche_v4::resultats_conference_de_presse_du_general_de_gaulle::N\\" \
36− href=\\"\\/video\\/CAF89035682\\/conference-de-presse-du-general-de-gaulle-video.html\\">\\n\
37− <img src=\\"https:\\/\\/www.ina.fr\\/images_v2\\/140x105\\/CAF89035682.jpeg\\" \
38− alt=\\"Conf\\u00e9rence de presse du G\\u00e9n\\u00e9ral de Gaulle \\">\\n\
39− \\t\\t\\t\\t\\t<\\/a>\\n\
40− \\t\\t\\t\\t\\t<div class=\\"media-body\\">\\n\\t\\t\\t\\t\\t\\t<h3 class=\\"h3--title media-heading\\">\\n\
41− \\t\\t\\t\\t\\t\\t\\t<a class=\\"xiti_click_action\\" \
42− data-xiti-params=\\"recherche_v4::resultats_conference_de_presse_du_general_de_gaulle::N\\" \
43− href=\\"\\/video\\/CAF89035682\\/conference-de-presse-du-general-de-gaulle-video.html\\">\
44− Conf\\u00e9rence de presse du G\\u00e9n\\u00e9ral de Gaulle <\\/a>\\n\
45− <\\/h3>\\n\
46− <div class=\\"media-body__info\\">\\n<span class=\\"broadcast\\">27\\/11\\/1967<\\/span>\\n\
47− <span class=\\"views\\">29321 vues<\\/span>\\n\
48− <span class=\\"duration\\">01h 33m 07s<\\/span>\\n\
49− <\\/div>\\n\
50− <p class=\\"media-body__summary\\">VERSION INTEGRALE DE LA CONFERENCE DE PRESSE DU GENERAL DE GAULLE . \
51− - PA le Pr\\u00e9sident DE GAULLE : il ouvre les bras et s'assied. DP journalis...<\\/p>\\n\
52− <\\/div>\\n<\\/div><!-- \\/.media -->\\n"
53− }
54− """
55− response = mock.Mock(text=json)
56− results = ina.response(response)
57− self.assertEqual(type(results), list)
58− self.assertEqual(len(results), 1)
59− self.assertEqual(results[0]['title'], u'Conf\xe9rence de presse du G\xe9n\xe9ral de Gaulle')
60− self.assertEqual(results[0]['url'],
61− 'https://www.ina.fr/video/CAF89035682/conference-de-presse-du-general-de-gaulle-video.html')
62− self.assertEqual(results[0]['content'],
63− u"VERSION INTEGRALE DE LA CONFERENCE DE PRESSE DU GENERAL DE GAULLE ."
64− u" - PA le Pr\u00e9sident DE GAULLE : il ouvre les bras et s'assied. DP journalis...")
tests/unit/engines/test_kickass.pydeleted−397
@@ -1,397 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import kickass
5−from searx.testing import SearxTestCase
6−
7−
8−class TestKickassEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dicto = defaultdict(dict)
13− dicto['pageno'] = 1
14− params = kickass.request(query, dicto)
15− self.assertIn('url', params)
16− self.assertIn(query, params['url'])
17− self.assertIn('kickass.cd', params['url'])
18− self.assertFalse(params['verify'])
19−
20− def test_response(self):
21− self.assertRaises(AttributeError, kickass.response, None)
22− self.assertRaises(AttributeError, kickass.response, [])
23− self.assertRaises(AttributeError, kickass.response, '')
24− self.assertRaises(AttributeError, kickass.response, '[]')
25−
26− response = mock.Mock(text='<html></html>')
27− self.assertEqual(kickass.response(response), [])
28−
29− html = """
30− <table cellpadding="0" cellspacing="0" class="data" style="width: 100%">
31− <tr class="firstr">
32− <th class="width100perc nopad">torrent name</th>
33− <th class="center">
34− <a href="/search/test/?field=size&sorder=desc" rel="nofollow">size</a>
35− </th>
36− <th class="center"><span class="files">
37− <a href="/search/test/?field=files_count&sorder=desc" rel="nofollow">files</a></span>
38− </th>
39− <th class="center"><span>
40− <a href="/search/test/?field=time_add&sorder=desc" rel="nofollow">age</a></span>
41− </th>
42− <th class="center"><span class="seed">
43− <a href="/search/test/?field=seeders&sorder=desc" rel="nofollow">seed</a></span>
44− </th>
45− <th class="lasttd nobr center">
46− <a href="/search/test/?field=leechers&sorder=desc" rel="nofollow">leech</a>
47− </th>
48− </tr>
49− <tr class="even" id="torrent_test6478745">
50− <td>
51− <div class="iaconbox center floatright">
52− <a rel="6478745,0" class="icommentjs icon16" href="/test-t6478745.html#comment">
53− <em style="font-size: 12px; margin: 0 4px 0 4px;" class="iconvalue">3</em>
54− <i class="ka ka-comment"></i>
55− </a>
56− <a class="iverify icon16" href="/test-t6478745.html" title="Verified Torrent">
57− <i class="ka ka16 ka-verify ka-green"></i>
58− </a>
59− <a href="#" onclick="_scq.push([]); return false;" class="partner1Button idownload icon16">
60− <i class="ka ka16 ka-arrow-down partner1Button"></i>
61− </a>
62− <a title="Torrent magnet link"
63− href="magnet:?xt=urn:btih:MAGNETURL&dn=test" class="imagnet icon16">
64− <i class="ka ka16 ka-magnet"></i>
65− </a>
66− <a title="Download torrent file"
67− href="http://torcache.net/torrent/53917.torrent?title=test" class="idownload icon16">
68− <i class="ka ka16 ka-arrow-down"></i>
69− </a>
70− </div>
71− <div class="torrentname">
72− <a href="/test-t6478745.html" class="torType txtType"></a>
73− <a href="/test-t6478745.html" class="normalgrey font12px plain bold"></a>
74− <div class="markeredBlock torType txtType">
75− <a href="/url.html" class="cellMainLink">
76− <strong class="red">This should be the title</strong>
77− </a>
78− <span class="font11px lightgrey block">
79− Posted by <i class="ka ka-verify" style="font-size: 16px;color:orange;"></i>
80− <a class="plain" href="/user/riri/">riri</a> in
81− <span id="cat_6478745">
82− <strong><a href="/other/">Other</a> > <a href="/unsorted/">Unsorted</a></strong>
83− </span>
84− </span>
85− </div>
86− </td>
87− <td class="nobr center">449 bytes</td>
88− <td class="center">4</td>
89− <td class="center">2&nbsp;years</td>
90− <td class="green center">10</td>
91− <td class="red lasttd center">1</td>
92− </tr>
93− </table>
94− """
95− response = mock.Mock(text=html)
96− results = kickass.response(response)
97− self.assertEqual(type(results), list)
98− self.assertEqual(len(results), 1)
99− self.assertEqual(results[0]['title'], 'This should be the title')
100− self.assertEqual(results[0]['url'], 'https://kickass.cd/url.html')
101− self.assertEqual(results[0]['content'], 'Posted by riri in Other > Unsorted')
102− self.assertEqual(results[0]['seed'], 10)
103− self.assertEqual(results[0]['leech'], 1)
104− self.assertEqual(results[0]['filesize'], 449)
105− self.assertEqual(results[0]['files'], 4)
106− self.assertEqual(results[0]['magnetlink'], 'magnet:?xt=urn:btih:MAGNETURL&dn=test')
107− self.assertEqual(results[0]['torrentfile'], 'http://torcache.net/torrent/53917.torrent?title=test')
108−
109− html = """
110− <table cellpadding="0" cellspacing="0" class="data" style="width: 100%">
111− <tr class="firstr">
112− <th class="width100perc nopad">torrent name</th>
113− <th class="center">
114− <a href="/search/test/?field=size&sorder=desc" rel="nofollow">size</a>
115− </th>
116− <th class="center"><span class="files">
117− <a href="/search/test/?field=files_count&sorder=desc" rel="nofollow">files</a></span>
118− </th>
119− <th class="center"><span>
120− <a href="/search/test/?field=time_add&sorder=desc" rel="nofollow">age</a></span>
121− </th>
122− <th class="center"><span class="seed">
123− <a href="/search/test/?field=seeders&sorder=desc" rel="nofollow">seed</a></span>
124− </th>
125− <th class="lasttd nobr center">
126− <a href="/search/test/?field=leechers&sorder=desc" rel="nofollow">leech</a>
127− </th>
128− </tr>
129− </table>
130− """
131− response = mock.Mock(text=html)
132− results = kickass.response(response)
133− self.assertEqual(type(results), list)
134− self.assertEqual(len(results), 0)
135−
136− html = """
137− <table cellpadding="0" cellspacing="0" class="data" style="width: 100%">
138− <tr class="firstr">
139− <th class="width100perc nopad">torrent name</th>
140− <th class="center">
141− <a href="/search/test/?field=size&sorder=desc" rel="nofollow">size</a>
142− </th>
143− <th class="center"><span class="files">
144− <a href="/search/test/?field=files_count&sorder=desc" rel="nofollow">files</a></span>
145− </th>
146− <th class="center"><span>
147− <a href="/search/test/?field=time_add&sorder=desc" rel="nofollow">age</a></span>
148− </th>
149− <th class="center"><span class="seed">
150− <a href="/search/test/?field=seeders&sorder=desc" rel="nofollow">seed</a></span>
151− </th>
152− <th class="lasttd nobr center">
153− <a href="/search/test/?field=leechers&sorder=desc" rel="nofollow">leech</a>
154− </th>
155− </tr>
156− <tr class="even" id="torrent_test6478745">
157− <td>
158− <div class="iaconbox center floatright">
159− <a rel="6478745,0" class="icommentjs icon16" href="/test-t6478745.html#comment">
160− <em style="font-size: 12px; margin: 0 4px 0 4px;" class="iconvalue">3</em>
161− <i class="ka ka-comment"></i>
162− </a>
163− <a class="iverify icon16" href="/test-t6478745.html" title="Verified Torrent">
164− <i class="ka ka16 ka-verify ka-green"></i>
165− </a>
166− <a href="#" onclick="_scq.push([]); return false;" class="partner1Button idownload icon16">
167− <i class="ka ka16 ka-arrow-down partner1Button"></i>
168− </a>
169− <a title="Torrent magnet link"
170− href="magnet:?xt=urn:btih:MAGNETURL&dn=test" class="imagnet icon16">
171− <i class="ka ka16 ka-magnet"></i>
172− </a>
173− <a title="Download torrent file"
174− href="http://torcache.net/torrent/53917.torrent?title=test" class="idownload icon16">
175− <i class="ka ka16 ka-arrow-down"></i>
176− </a>
177− </div>
178− <div class="torrentname">
179− <a href="/test-t6478745.html" class="torType txtType"></a>
180− <a href="/test-t6478745.html" class="normalgrey font12px plain bold"></a>
181− <div class="markeredBlock torType txtType">
182− <a href="/url.html" class="cellMainLink">
183− <strong class="red">This should be the title</strong>
184− </a>
185− <span class="font11px lightgrey block">
186− Posted by <i class="ka ka-verify" style="font-size: 16px;color:orange;"></i>
187− <a class="plain" href="/user/riri/">riri</a> in
188− <span id="cat_6478745">
189− <strong><a href="/other/">Other</a> > <a href="/unsorted/">Unsorted</a></strong>
190− </span>
191− </span>
192− </div>
193− </td>
194− <td class="nobr center">1 KiB</td>
195− <td class="center">4</td>
196− <td class="center">2&nbsp;years</td>
197− <td class="green center">10</td>
198− <td class="red lasttd center">1</td>
199− </tr>
200− <tr class="even" id="torrent_test6478745">
201− <td>
202− <div class="iaconbox center floatright">
203− <a rel="6478745,0" class="icommentjs icon16" href="/test-t6478745.html#comment">
204− <em style="font-size: 12px; margin: 0 4px 0 4px;" class="iconvalue">3</em>
205− <i class="ka ka-comment"></i>
206− </a>
207− <a class="iverify icon16" href="/test-t6478745.html" title="Verified Torrent">
208− <i class="ka ka16 ka-verify ka-green"></i>
209− </a>
210− <a href="#" onclick="_scq.push([]); return false;" class="partner1Button idownload icon16">
211− <i class="ka ka16 ka-arrow-down partner1Button"></i>
212− </a>
213− <a title="Torrent magnet link"
214− href="magnet:?xt=urn:btih:MAGNETURL&dn=test" class="imagnet icon16">
215− <i class="ka ka16 ka-magnet"></i>
216− </a>
217− <a title="Download torrent file"
218− href="http://torcache.net/torrent/53917.torrent?title=test" class="idownload icon16">
219− <i class="ka ka16 ka-arrow-down"></i>
220− </a>
221− </div>
222− <div class="torrentname">
223− <a href="/test-t6478745.html" class="torType txtType"></a>
224− <a href="/test-t6478745.html" class="normalgrey font12px plain bold"></a>
225− <div class="markeredBlock torType txtType">
226− <a href="/url.html" class="cellMainLink">
227− <strong class="red">This should be the title</strong>
228− </a>
229− <span class="font11px lightgrey block">
230− Posted by <i class="ka ka-verify" style="font-size: 16px;color:orange;"></i>
231− <a class="plain" href="/user/riri/">riri</a> in
232− <span id="cat_6478745">
233− <strong><a href="/other/">Other</a> > <a href="/unsorted/">Unsorted</a></strong>
234− </span>
235− </span>
236− </div>
237− </td>
238− <td class="nobr center">1 MiB</td>
239− <td class="center">4</td>
240− <td class="center">2&nbsp;years</td>
241− <td class="green center">9</td>
242− <td class="red lasttd center">1</td>
243− </tr>
244− <tr class="even" id="torrent_test6478745">
245− <td>
246− <div class="iaconbox center floatright">
247− <a rel="6478745,0" class="icommentjs icon16" href="/test-t6478745.html#comment">
248− <em style="font-size: 12px; margin: 0 4px 0 4px;" class="iconvalue">3</em>
249− <i class="ka ka-comment"></i>
250− </a>
251− <a class="iverify icon16" href="/test-t6478745.html" title="Verified Torrent">
252− <i class="ka ka16 ka-verify ka-green"></i>
253− </a>
254− <a href="#" onclick="_scq.push([]); return false;" class="partner1Button idownload icon16">
255− <i class="ka ka16 ka-arrow-down partner1Button"></i>
256− </a>
257− <a title="Torrent magnet link"
258− href="magnet:?xt=urn:btih:MAGNETURL&dn=test" class="imagnet icon16">
259− <i class="ka ka16 ka-magnet"></i>
260− </a>
261− <a title="Download torrent file"
262− href="http://torcache.net/torrent/53917.torrent?title=test" class="idownload icon16">
263− <i class="ka ka16 ka-arrow-down"></i>
264− </a>
265− </div>
266− <div class="torrentname">
267− <a href="/test-t6478745.html" class="torType txtType"></a>
268− <a href="/test-t6478745.html" class="normalgrey font12px plain bold"></a>
269− <div class="markeredBlock torType txtType">
270− <a href="/url.html" class="cellMainLink">
271− <strong class="red">This should be the title</strong>
272− </a>
273− <span class="font11px lightgrey block">
274− Posted by <i class="ka ka-verify" style="font-size: 16px;color:orange;"></i>
275− <a class="plain" href="/user/riri/">riri</a> in
276− <span id="cat_6478745">
277− <strong><a href="/other/">Other</a> > <a href="/unsorted/">Unsorted</a></strong>
278− </span>
279− </span>
280− </div>
281− </td>
282− <td class="nobr center">1 GiB</td>
283− <td class="center">4</td>
284− <td class="center">2&nbsp;years</td>
285− <td class="green center">8</td>
286− <td class="red lasttd center">1</td>
287− </tr>
288− <tr class="even" id="torrent_test6478745">
289− <td>
290− <div class="iaconbox center floatright">
291− <a rel="6478745,0" class="icommentjs icon16" href="/test-t6478745.html#comment">
292− <em style="font-size: 12px; margin: 0 4px 0 4px;" class="iconvalue">3</em>
293− <i class="ka ka-comment"></i>
294− </a>
295− <a class="iverify icon16" href="/test-t6478745.html" title="Verified Torrent">
296− <i class="ka ka16 ka-verify ka-green"></i>
297− </a>
298− <a href="#" onclick="_scq.push([]); return false;" class="partner1Button idownload icon16">
299− <i class="ka ka16 ka-arrow-down partner1Button"></i>
300− </a>
301− <a title="Torrent magnet link"
302− href="magnet:?xt=urn:btih:MAGNETURL&dn=test" class="imagnet icon16">
303− <i class="ka ka16 ka-magnet"></i>
304− </a>
305− <a title="Download torrent file"
306− href="http://torcache.net/torrent/53917.torrent?title=test" class="idownload icon16">
307− <i class="ka ka16 ka-arrow-down"></i>
308− </a>
309− </div>
310− <div class="torrentname">
311− <a href="/test-t6478745.html" class="torType txtType"></a>
312− <a href="/test-t6478745.html" class="normalgrey font12px plain bold"></a>
313− <div class="markeredBlock torType txtType">
314− <a href="/url.html" class="cellMainLink">
315− <strong class="red">This should be the title</strong>
316− </a>
317− <span class="font11px lightgrey block">
318− Posted by <i class="ka ka-verify" style="font-size: 16px;color:orange;"></i>
319− <a class="plain" href="/user/riri/">riri</a> in
320− <span id="cat_6478745">
321− <strong><a href="/other/">Other</a> > <a href="/unsorted/">Unsorted</a></strong>
322− </span>
323− </span>
324− </div>
325− </td>
326− <td class="nobr center">1 TiB</td>
327− <td class="center">4</td>
328− <td class="center">2&nbsp;years</td>
329− <td class="green center">7</td>
330− <td class="red lasttd center">1</td>
331− </tr>
332− <tr class="even" id="torrent_test6478745">
333− <td>
334− <div class="iaconbox center floatright">
335− <a rel="6478745,0" class="icommentjs icon16" href="/test-t6478745.html#comment">
336− <em style="font-size: 12px; margin: 0 4px 0 4px;" class="iconvalue">3</em>
337− <i class="ka ka-comment"></i>
338− </a>
339− <a class="iverify icon16" href="/test-t6478745.html" title="Verified Torrent">
340− <i class="ka ka16 ka-verify ka-green"></i>
341− </a>
342− <a href="#" onclick="_scq.push([]); return false;" class="partner1Button idownload icon16">
343− <i class="ka ka16 ka-arrow-down partner1Button"></i>
344− </a>
345− <a title="Torrent magnet link"
346− href="magnet:?xt=urn:btih:MAGNETURL&dn=test" class="imagnet icon16">
347− <i class="ka ka16 ka-magnet"></i>
348− </a>
349− <a title="Download torrent file"
350− href="http://torcache.net/torrent/53917.torrent?title=test" class="idownload icon16">
351− <i class="ka ka16 ka-arrow-down"></i>
352− </a>
353− </div>
354− <div class="torrentname">
355− <a href="/test-t6478745.html" class="torType txtType"></a>
356− <a href="/test-t6478745.html" class="normalgrey font12px plain bold"></a>
357− <div class="markeredBlock torType txtType">
358− <a href="/url.html" class="cellMainLink">
359− <strong class="red">This should be the title</strong>
360− </a>
361− <span class="font11px lightgrey block">
362− Posted by <i class="ka ka-verify" style="font-size: 16px;color:orange;"></i>
363− <a class="plain" href="/user/riri/">riri</a> in
364− <span id="cat_6478745">
365− <strong><a href="/other/">Other</a> > <a href="/unsorted/">Unsorted</a></strong>
366− </span>
367− </span>
368− </div>
369− </td>
370− <td class="nobr center">z bytes</td>
371− <td class="center">r</td>
372− <td class="center">2&nbsp;years</td>
373− <td class="green center">a</td>
374− <td class="red lasttd center">t</td>
375− </tr>
376− </table>
377− """
378− response = mock.Mock(text=html)
379− results = kickass.response(response)
380− self.assertEqual(type(results), list)
381− self.assertEqual(len(results), 5)
382− self.assertEqual(results[0]['title'], 'This should be the title')
383− self.assertEqual(results[0]['url'], 'https://kickass.cd/url.html')
384− self.assertEqual(results[0]['content'], 'Posted by riri in Other > Unsorted')
385− self.assertEqual(results[0]['seed'], 10)
386− self.assertEqual(results[0]['leech'], 1)
387− self.assertEqual(results[0]['files'], 4)
388− self.assertEqual(results[0]['magnetlink'], 'magnet:?xt=urn:btih:MAGNETURL&dn=test')
389− self.assertEqual(results[0]['torrentfile'], 'http://torcache.net/torrent/53917.torrent?title=test')
390− self.assertEqual(results[0]['filesize'], 1000)
391− self.assertEqual(results[1]['filesize'], 1000000)
392− self.assertEqual(results[2]['filesize'], 1000000000)
393− self.assertEqual(results[3]['filesize'], 1000000000000)
394− self.assertEqual(results[4]['seed'], 0)
395− self.assertEqual(results[4]['leech'], 0)
396− self.assertEqual(results[4]['files'], None)
397− self.assertEqual(results[4]['filesize'], None)
tests/unit/engines/test_mediawiki.pydeleted−130
@@ -1,130 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import mediawiki
5−from searx.testing import SearxTestCase
6−
7−
8−class TestMediawikiEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dicto = defaultdict(dict)
13− dicto['pageno'] = 1
14− dicto['language'] = 'fr_FR'
15− params = mediawiki.request(query, dicto)
16− self.assertIn('url', params)
17− self.assertIn(query, params['url'])
18− self.assertIn('wikipedia.org', params['url'])
19− self.assertIn('fr', params['url'])
20−
21− dicto['language'] = 'all'
22− params = mediawiki.request(query, dicto)
23− self.assertIn('en', params['url'])
24−
25− mediawiki.base_url = "http://test.url/"
26− mediawiki.search_url = mediawiki.base_url +\
27− 'w/api.php?action=query'\
28− '&list=search'\
29− '&{query}'\
30− '&srprop=timestamp'\
31− '&format=json'\
32− '&sroffset={offset}'\
33− '&srlimit={limit}' # noqa
34− params = mediawiki.request(query, dicto)
35− self.assertIn('test.url', params['url'])
36−
37− def test_response(self):
38− dicto = defaultdict(dict)
39− dicto['language'] = 'fr'
40− mediawiki.base_url = "https://{language}.wikipedia.org/"
41−
42− self.assertRaises(AttributeError, mediawiki.response, None)
43− self.assertRaises(AttributeError, mediawiki.response, [])
44− self.assertRaises(AttributeError, mediawiki.response, '')
45− self.assertRaises(AttributeError, mediawiki.response, '[]')
46−
47− response = mock.Mock(text='{}', search_params=dicto)
48− self.assertEqual(mediawiki.response(response), [])
49−
50− response = mock.Mock(text='{"data": []}', search_params=dicto)
51− self.assertEqual(mediawiki.response(response), [])
52−
53− json = """
54− {
55− "query-continue": {
56− "search": {
57− "sroffset": 1
58− }
59− },
60− "query": {
61− "searchinfo": {
62− "totalhits": 29721
63− },
64− "search": [
65− {
66− "ns": 0,
67− "title": "This is the title étude",
68− "timestamp": "2014-12-19T17:42:52Z"
69− }
70− ]
71− }
72− }
73− """
74− response = mock.Mock(text=json, search_params=dicto)
75− results = mediawiki.response(response)
76− self.assertEqual(type(results), list)
77− self.assertEqual(len(results), 1)
78− self.assertEqual(results[0]['title'], u'This is the title étude')
79− self.assertIn('fr.wikipedia.org', results[0]['url'])
80− self.assertIn('This_is_the_title', results[0]['url'])
81− self.assertIn('%C3%A9tude', results[0]['url'])
82− self.assertEqual(results[0]['content'], '')
83−
84− json = """
85− {
86− "query-continue": {
87− "search": {
88− "sroffset": 1
89− }
90− },
91− "query": {
92− "searchinfo": {
93− "totalhits": 29721
94− },
95− "search": [
96− ]
97− }
98− }
99− """
100− response = mock.Mock(text=json, search_params=dicto)
101− results = mediawiki.response(response)
102− self.assertEqual(type(results), list)
103− self.assertEqual(len(results), 0)
104−
105− json = """
106− {
107− "query-continue": {
108− "search": {
109− "sroffset": 1
110− }
111− },
112− "query": {
113− }
114− }
115− """
116− response = mock.Mock(text=json, search_params=dicto)
117− results = mediawiki.response(response)
118− self.assertEqual(type(results), list)
119− self.assertEqual(len(results), 0)
120−
121− json = r"""
122− {"toto":[
123− {"id":200,"name":"Artist Name",
124− "link":"http:\/\/www.mediawiki.com\/artist\/1217","type":"artist"}
125− ]}
126− """
127− response = mock.Mock(text=json, search_params=dicto)
128− results = mediawiki.response(response)
129− self.assertEqual(type(results), list)
130− self.assertEqual(len(results), 0)
tests/unit/engines/test_mixcloud.pydeleted−67
@@ -1,67 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import mixcloud
4−from searx.testing import SearxTestCase
5−
6−
7−class TestMixcloudEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dicto = defaultdict(dict)
12− dicto['pageno'] = 0
13− params = mixcloud.request(query, dicto)
14− self.assertTrue('url' in params)
15− self.assertTrue(query in params['url'])
16− self.assertTrue('mixcloud.com' in params['url'])
17−
18− def test_response(self):
19− self.assertRaises(AttributeError, mixcloud.response, None)
20− self.assertRaises(AttributeError, mixcloud.response, [])
21− self.assertRaises(AttributeError, mixcloud.response, '')
22− self.assertRaises(AttributeError, mixcloud.response, '[]')
23−
24− response = mock.Mock(text='{}')
25− self.assertEqual(mixcloud.response(response), [])
26−
27− response = mock.Mock(text='{"data": []}')
28− self.assertEqual(mixcloud.response(response), [])
29−
30− json = """
31− {"data":[
32− {
33− "user": {
34− "url": "http://www.mixcloud.com/user/",
35− "username": "user",
36− "name": "User",
37− "key": "/user/"
38− },
39− "key": "/user/this-is-the-url/",
40− "created_time": "2014-11-14T13:30:02Z",
41− "audio_length": 3728,
42− "slug": "this-is-the-url",
43− "name": "Title of track",
44− "url": "http://www.mixcloud.com/user/this-is-the-url/",
45− "updated_time": "2014-11-14T13:14:10Z"
46− }
47− ]}
48− """
49− response = mock.Mock(text=json)
50− results = mixcloud.response(response)
51− self.assertEqual(type(results), list)
52− self.assertEqual(len(results), 1)
53− self.assertEqual(results[0]['title'], 'Title of track')
54− self.assertEqual(results[0]['url'], 'http://www.mixcloud.com/user/this-is-the-url/')
55− self.assertEqual(results[0]['content'], 'User')
56− self.assertTrue('http://www.mixcloud.com/user/this-is-the-url/' in results[0]['embedded'])
57−
58− json = r"""
59− {"toto":[
60− {"id":200,"name":"Artist Name",
61− "link":"http:\/\/www.mixcloud.com\/artist\/1217","type":"artist"}
62− ]}
63− """
64− response = mock.Mock(text=json)
65− results = mixcloud.response(response)
66− self.assertEqual(type(results), list)
67− self.assertEqual(len(results), 0)
tests/unit/engines/test_nyaa.pydeleted−124
@@ -1,124 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import nyaa
4−from searx.testing import SearxTestCase
5−
6−
7−class TestNyaaEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dic = defaultdict(dict)
12− dic['pageno'] = 1
13− params = nyaa.request(query, dic)
14− self.assertTrue('url' in params)
15− self.assertTrue(query in params['url'])
16− self.assertTrue('nyaa.si' in params['url'])
17−
18− def test_response(self):
19− resp = mock.Mock(text='<html></html>')
20− self.assertEqual(nyaa.response(resp), [])
21−
22− html = """
23− <table class="table table-bordered table-hover table-striped torrent-list">
24− <thead>
25− <tr>
26− <th class="hdr-category text-center" style="width:80px;">
27− <div>Category</div>
28− </th>
29− <th class="hdr-name" style="width:auto;">
30− <div>Name</div>
31− </th>
32− <th class="hdr-comments sorting text-center" title="Comments" style="width:50px;">
33− <a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=comments&amp;o=desc"></a>
34− <i class="fa fa-comments-o"></i>
35− </th>
36− <th class="hdr-link text-center" style="width:70px;">
37− <div>Link</div>
38− </th>
39− <th class="hdr-size sorting text-center" style="width:100px;">
40− <a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=size&amp;o=desc"></a>
41− <div>Size</div>
42− </th>
43− <th class="hdr-date sorting_desc text-center" title="In local time" style="width:140px;">
44− <a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=id&amp;o=asc"></a>
45− <div>Date</div>
46− </th>
47− <th class="hdr-seeders sorting text-center" title="Seeders" style="width:50px;">
48− <a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=seeders&amp;o=desc"></a>
49− <i class="fa fa-arrow-up" aria-hidden="true"></i>
50− </th>
51− <th class="hdr-leechers sorting text-center" title="Leechers" style="width:50px;">
52− <a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=leechers&amp;o=desc"></a>
53− <i class="fa fa-arrow-down" aria-hidden="true"></i>
54− </th>
55− <th class="hdr-downloads sorting text-center" title="Completed downloads" style="width:50px;">
56− <a href="/?f=0&amp;c=0_0&amp;q=Death+Parade&amp;s=downloads&amp;o=desc"></a>
57− <i class="fa fa-check" aria-hidden="true"></i>
58− </th>
59− </tr>
60− </thead>
61− <tbody>
62− <tr class="default">
63− <td style="padding:0 4px;">
64− <a href="/?c=1_2" title="Anime - English-translated">
65− <img src="/static/img/icons/nyaa/1_2.png" alt="Anime - English-translated">
66− </a>
67− </td>
68− <td colspan="2">
69− <a href="/view/1" title="Sample title 1">Sample title 1</a>
70− </td>
71− <td class="text-center" style="white-space: nowrap;">
72− <a href="/download/1.torrent"><i class="fa fa-fw fa-download"></i></a>
73− <a href="magnet:?xt=urn:btih:2"><i class="fa fa-fw fa-magnet"></i></a>
74− </td>
75− <td class="text-center">723.7 MiB</td>
76− <td class="text-center" data-timestamp="1503307456" title="1 week 3
77− days 9 hours 44 minutes 39 seconds ago">2017-08-21 11:24</td>
78− <td class="text-center" style="color: green;">1</td>
79− <td class="text-center" style="color: red;">3</td>
80− <td class="text-center">12</td>
81− </tr>
82− <tr class="default">
83− <td style="padding:0 4px;">
84− <a href="/?c=1_2" title="Anime - English-translated">
85− <img src="/static/img/icons/nyaa/1_2.png" alt="Anime - English-translated">
86− </a>
87− </td>
88− <td colspan="2">
89− <a href="/view/2" title="Sample title 2">Sample title 2</a>
90− </td>
91− <td class="text-center" style="white-space: nowrap;">
92− <a href="magnet:?xt=urn:btih:2"><i class="fa fa-fw fa-magnet"></i></a>
93− </td>
94− <td class="text-center">8.2 GiB</td>
95− <td class="text-center" data-timestamp="1491608400" title="4 months 3
96− weeks 4 days 19 hours 28 minutes 55 seconds ago">2017-04-08 01:40</td>
97− <td class="text-center" style="color: green;">10</td>
98− <td class="text-center" style="color: red;">1</td>
99− <td class="text-center">206</td>
100− </tr>
101− </tbody>
102− </table>
103− """
104−
105− resp = mock.Mock(text=html)
106− results = nyaa.response(resp)
107−
108− self.assertEqual(type(results), list)
109− self.assertEqual(len(results), 2)
110−
111− r = results[0]
112− self.assertTrue(r['url'].find('1') >= 0)
113− self.assertTrue(r['torrentfile'].find('1.torrent') >= 0)
114− self.assertTrue(r['content'].find('Anime - English-translated') >= 0)
115− self.assertTrue(r['content'].find('Downloaded 12 times.') >= 0)
116−
117− self.assertEqual(r['title'], 'Sample title 1')
118− self.assertEqual(r['seed'], 1)
119− self.assertEqual(r['leech'], 3)
120− self.assertEqual(r['filesize'], 723700000)
121−
122− r = results[1]
123− self.assertTrue(r['url'].find('2') >= 0)
124− self.assertTrue(r['magnetlink'].find('magnet:') >= 0)
tests/unit/engines/test_openstreetmap.pydeleted−199
@@ -1,199 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import openstreetmap
5−from searx.testing import SearxTestCase
6−
7−
8−class TestOpenstreetmapEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dicto = defaultdict(dict)
13− dicto['pageno'] = 1
14− params = openstreetmap.request(query, dicto)
15− self.assertIn('url', params)
16− self.assertIn(query, params['url'])
17− self.assertIn('openstreetmap.org', params['url'])
18−
19− def test_response(self):
20− self.assertRaises(AttributeError, openstreetmap.response, None)
21− self.assertRaises(AttributeError, openstreetmap.response, [])
22− self.assertRaises(AttributeError, openstreetmap.response, '')
23− self.assertRaises(AttributeError, openstreetmap.response, '[]')
24−
25− response = mock.Mock(text='{}')
26− self.assertEqual(openstreetmap.response(response), [])
27−
28− response = mock.Mock(text='{"data": []}')
29− self.assertEqual(openstreetmap.response(response), [])
30−
31− json = """
32− [
33− {
34− "place_id": "127732055",
35− "licence": "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright",
36− "osm_type": "relation",
37− "osm_id": "7444",
38− "boundingbox": [
39− "48.8155755",
40− "48.902156",
41− "2.224122",
42− "2.4697602"
43− ],
44− "lat": "48.8565056",
45− "lon": "2.3521334",
46− "display_name": "This is the title",
47− "class": "place",
48− "type": "city",
49− "importance": 0.96893459932191,
50− "icon": "https://nominatim.openstreetmap.org/images/mapicons/poi_place_city.p.20.png",
51− "address": {
52− "city": "Paris",
53− "county": "Paris",
54− "state": "Île-de-France",
55− "country": "France",
56− "country_code": "fr"
57− },
58− "geojson": {
59− "type": "Polygon",
60− "coordinates": [
61− [
62− [
63− 2.224122,
64− 48.854199
65− ]
66− ]
67− ]
68− }
69− }
70− ]
71− """
72− response = mock.Mock(text=json)
73− results = openstreetmap.response(response)
74− self.assertEqual(type(results), list)
75− self.assertEqual(len(results), 1)
76− self.assertEqual(results[0]['title'], 'This is the title')
77− self.assertEqual(results[0]['url'], 'https://openstreetmap.org/relation/7444')
78− self.assertIn('coordinates', results[0]['geojson'])
79− self.assertEqual(results[0]['geojson']['coordinates'][0][0][0], 2.224122)
80− self.assertEqual(results[0]['geojson']['coordinates'][0][0][1], 48.854199)
81− self.assertEqual(results[0]['address'], None)
82− self.assertIn('48.8155755', results[0]['boundingbox'])
83− self.assertIn('48.902156', results[0]['boundingbox'])
84− self.assertIn('2.224122', results[0]['boundingbox'])
85− self.assertIn('2.4697602', results[0]['boundingbox'])
86−
87− json = """
88− [
89− {
90− "place_id": "127732055",
91− "licence": "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright",
92− "osm_type": "relation",
93− "osm_id": "7444",
94− "boundingbox": [
95− "48.8155755",
96− "48.902156",
97− "2.224122",
98− "2.4697602"
99− ],
100− "lat": "48.8565056",
101− "lon": "2.3521334",
102− "display_name": "This is the title",
103− "class": "tourism",
104− "type": "city",
105− "importance": 0.96893459932191,
106− "icon": "https://nominatim.openstreetmap.org/images/mapicons/poi_place_city.p.20.png",
107− "address": {
108− "city": "Paris",
109− "county": "Paris",
110− "state": "Île-de-France",
111− "country": "France",
112− "country_code": "fr",
113− "address29": "Address"
114− },
115− "geojson": {
116− "type": "Polygon",
117− "coordinates": [
118− [
119− [
120− 2.224122,
121− 48.854199
122− ]
123− ]
124− ]
125− }
126− },
127− {
128− "place_id": "127732055",
129− "licence": "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright",
130− "osm_type": "relation",
131− "osm_id": "7444",
132− "boundingbox": [
133− "48.8155755",
134− "48.902156",
135− "2.224122",
136− "2.4697602"
137− ],
138− "lat": "48.8565056",
139− "lon": "2.3521334",
140− "display_name": "This is the title",
141− "class": "tourism",
142− "type": "city",
143− "importance": 0.96893459932191,
144− "icon": "https://nominatim.openstreetmap.org/images/mapicons/poi_place_city.p.20.png",
145− "address": {
146− "city": "Paris",
147− "county": "Paris",
148− "state": "Île-de-France",
149− "country": "France",
150− "postcode": 75000,
151− "country_code": "fr"
152− },
153− "geojson": {
154− "type": "Polygon",
155− "coordinates": [
156− [
157− [
158− 2.224122,
159− 48.854199
160− ]
161− ]
162− ]
163− }
164− },
165− {
166− "place_id": "127732055",
167− "licence": "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright",
168− "osm_type": "node",
169− "osm_id": "7444",
170− "boundingbox": [
171− "48.8155755",
172− "48.902156",
173− "2.224122",
174− "2.4697602"
175− ],
176− "lat": "48.8565056",
177− "lon": "2.3521334",
178− "display_name": "This is the title",
179− "class": "tourism",
180− "type": "city",
181− "importance": 0.96893459932191,
182− "icon": "https://nominatim.openstreetmap.org/images/mapicons/poi_place_city.p.20.png",
183− "address": {
184− "city": "Paris",
185− "county": "Paris",
186− "state": "Île-de-France",
187− "country": "France",
188− "country_code": "fr",
189− "address29": "Address"
190− }
191− }
192− ]
193− """
194− response = mock.Mock(text=json)
195− results = openstreetmap.response(response)
196− self.assertEqual(type(results), list)
197− self.assertEqual(len(results), 3)
198− self.assertIn('48.8565056', results[2]['geojson']['coordinates'])
199− self.assertIn('2.3521334', results[2]['geojson']['coordinates'])
tests/unit/engines/test_pdbe.pydeleted−109
@@ -1,109 +0,0 @@
1−import mock
2−from collections import defaultdict
3−from searx.engines import pdbe
4−from searx.testing import SearxTestCase
5−
6−
7−class TestPdbeEngine(SearxTestCase):
8− def test_request(self):
9− query = 'test_query'
10− dicto = defaultdict(dict)
11− params = pdbe.request(query, dicto)
12− self.assertTrue('url' in params)
13− self.assertTrue('ebi.ac.uk' in params['url'])
14− self.assertTrue('data' in params)
15− self.assertTrue('q' in params['data'])
16− self.assertTrue(query in params['data']['q'])
17− self.assertTrue('wt' in params['data'])
18− self.assertTrue('json' in params['data']['wt'])
19− self.assertTrue('method' in params)
20− self.assertTrue(params['method'] == 'POST')
21−
22− def test_response(self):
23− self.assertRaises(AttributeError, pdbe.response, None)
24− self.assertRaises(AttributeError, pdbe.response, [])
25− self.assertRaises(AttributeError, pdbe.response, '')
26− self.assertRaises(AttributeError, pdbe.response, '[]')
27−
28− json = """
29−{
30− "response": {
31− "docs": [
32− {
33− "citation_title": "X-ray crystal structure of ferric Aplysia limacina myoglobin in different liganded states.",
34− "citation_year": 1993,
35− "entry_author_list": [
36− "Conti E, Moser C, Rizzi M, Mattevi A, Lionetti C, Coda A, Ascenzi P, Brunori M, Bolognesi M"
37− ],
38− "journal": "J. Mol. Biol.",
39− "journal_page": "498-508",
40− "journal_volume": "233",
41− "pdb_id": "2fal",
42− "status": "REL",
43− "title": "X-RAY CRYSTAL STRUCTURE OF FERRIC APLYSIA LIMACINA MYOGLOBIN IN DIFFERENT LIGANDED STATES"
44− }
45− ],
46− "numFound": 1,
47− "start": 0
48− },
49− "responseHeader": {
50− "QTime": 0,
51− "params": {
52− "q": "2fal",
53− "wt": "json"
54− },
55− "status": 0
56− }
57−}
58−"""
59−
60− response = mock.Mock(text=json)
61− results = pdbe.response(response)
62− self.assertEqual(type(results), list)
63− self.assertEqual(len(results), 1)
64− self.assertEqual(results[0]['title'],
65− 'X-RAY CRYSTAL STRUCTURE OF FERRIC APLYSIA LIMACINA MYOGLOBIN IN DIFFERENT LIGANDED STATES')
66− self.assertEqual(results[0]['url'], pdbe.pdbe_entry_url.format(pdb_id='2fal'))
67− self.assertEqual(results[0]['img_src'], pdbe.pdbe_preview_url.format(pdb_id='2fal'))
68− self.assertTrue('Conti E' in results[0]['content'])
69− self.assertTrue('X-ray crystal structure of ferric Aplysia limacina myoglobin in different liganded states.' in
70− results[0]['content'])
71− self.assertTrue('1993' in results[0]['content'])
72−
73− # Testing proper handling of PDB entries marked as obsolete
74− json = """
75−{
76− "response": {
77− "docs": [
78− {
79− "citation_title": "Obsolete entry test",
80− "citation_year": 2016,
81− "entry_author_list": ["Doe J"],
82− "journal": "J. Obs.",
83− "journal_page": "1-2",
84− "journal_volume": "1",
85− "pdb_id": "xxxx",
86− "status": "OBS",
87− "title": "OBSOLETE ENTRY TEST",
88− "superseded_by": "yyyy"
89− }
90− ],
91− "numFound": 1,
92− "start": 0
93− },
94− "responseHeader": {
95− "QTime": 0,
96− "params": {
97− "q": "xxxx",
98− "wt": "json"
99− },
100− "status": 0
101− }
102−}
103−"""
104− response = mock.Mock(text=json)
105− results = pdbe.response(response)
106− self.assertEqual(type(results), list)
107− self.assertEqual(len(results), 1)
108− self.assertEqual(results[0]['title'], 'OBSOLETE ENTRY TEST (OBSOLETE)')
109− self.assertTrue(results[0]['content'].startswith('This entry has been superseded by'))
tests/unit/engines/test_photon.pydeleted−166
@@ -1,166 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import photon
5−from searx.testing import SearxTestCase
6−
7−
8−class TestPhotonEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dicto = defaultdict(dict)
13− dicto['pageno'] = 1
14− dicto['language'] = 'all'
15− params = photon.request(query, dicto)
16− self.assertIn('url', params)
17− self.assertIn(query, params['url'])
18− self.assertIn('photon.komoot.de', params['url'])
19−
20− dicto['language'] = 'all'
21− params = photon.request(query, dicto)
22− self.assertNotIn('lang', params['url'])
23−
24− dicto['language'] = 'al'
25− params = photon.request(query, dicto)
26− self.assertNotIn('lang', params['url'])
27−
28− dicto['language'] = 'fr'
29− params = photon.request(query, dicto)
30− self.assertIn('fr', params['url'])
31−
32− def test_response(self):
33− self.assertRaises(AttributeError, photon.response, None)
34− self.assertRaises(AttributeError, photon.response, [])
35− self.assertRaises(AttributeError, photon.response, '')
36− self.assertRaises(AttributeError, photon.response, '[]')
37−
38− response = mock.Mock(text='{}')
39− self.assertEqual(photon.response(response), [])
40−
41− response = mock.Mock(text='{"data": []}')
42− self.assertEqual(photon.response(response), [])
43−
44− json = """
45− {
46− "features": [
47− {
48− "properties": {
49− "osm_key": "waterway",
50− "extent": [
51− -1.4508446,
52− 51.1614997,
53− -1.4408036,
54− 51.1525635
55− ],
56− "name": "This is the title",
57− "state": "England",
58− "osm_id": 114823817,
59− "osm_type": "W",
60− "osm_value": "river",
61− "city": "Test Valley",
62− "country": "United Kingdom"
63− },
64− "type": "Feature",
65− "geometry": {
66− "type": "Point",
67− "coordinates": [
68− -1.4458571,
69− 51.1576661
70− ]
71− }
72− },
73− {
74− "properties": {
75− "osm_key": "place",
76− "street": "Rue",
77− "state": "Ile-de-France",
78− "osm_id": 129211377,
79− "osm_type": "R",
80− "housenumber": "10",
81− "postcode": "75011",
82− "osm_value": "house",
83− "city": "Paris",
84− "country": "France"
85− },
86− "type": "Feature",
87− "geometry": {
88− "type": "Point",
89− "coordinates": [
90− 2.3725025,
91− 48.8654481
92− ]
93− }
94− },
95− {
96− "properties": {
97− "osm_key": "amenity",
98− "street": "Allée",
99− "name": "Bibliothèque",
100− "state": "Ile-de-France",
101− "osm_id": 1028573132,
102− "osm_type": "N",
103− "postcode": "75001",
104− "osm_value": "library",
105− "city": "Paris",
106− "country": "France"
107− },
108− "type": "Feature",
109− "geometry": {
110− "type": "Point",
111− "coordinates": [
112− 2.3445634,
113− 48.862494
114− ]
115− }
116− },
117− {
118− "properties": {
119− "osm_key": "amenity",
120− "osm_id": 1028573132,
121− "osm_type": "Y",
122− "postcode": "75001",
123− "osm_value": "library",
124− "city": "Paris",
125− "country": "France"
126− },
127− "type": "Feature",
128− "geometry": {
129− "type": "Point",
130− "coordinates": [
131− 2.3445634,
132− 48.862494
133− ]
134− }
135− },
136− {
137− }
138− ],
139− "type": "FeatureCollection"
140− }
141− """
142− response = mock.Mock(text=json)
143− results = photon.response(response)
144− self.assertEqual(type(results), list)
145− self.assertEqual(len(results), 3)
146− self.assertEqual(results[0]['title'], 'This is the title')
147− self.assertEqual(results[0]['content'], '')
148− self.assertEqual(results[0]['longitude'], -1.4458571)
149− self.assertEqual(results[0]['latitude'], 51.1576661)
150− self.assertIn(-1.4508446, results[0]['boundingbox'])
151− self.assertIn(51.1614997, results[0]['boundingbox'])
152− self.assertIn(-1.4408036, results[0]['boundingbox'])
153− self.assertIn(51.1525635, results[0]['boundingbox'])
154− self.assertIn('type', results[0]['geojson'])
155− self.assertEqual(results[0]['geojson']['type'], 'Point')
156− self.assertEqual(results[0]['address'], None)
157− self.assertEqual(results[0]['osm']['type'], 'way')
158− self.assertEqual(results[0]['osm']['id'], 114823817)
159− self.assertEqual(results[0]['url'], 'https://openstreetmap.org/way/114823817')
160− self.assertEqual(results[1]['osm']['type'], 'relation')
161− self.assertEqual(results[2]['address']['name'], u'Bibliothèque')
162− self.assertEqual(results[2]['address']['house_number'], None)
163− self.assertEqual(results[2]['address']['locality'], 'Paris')
164− self.assertEqual(results[2]['address']['postcode'], '75001')
165− self.assertEqual(results[2]['address']['country'], 'France')
166− self.assertEqual(results[2]['osm']['type'], 'node')
tests/unit/engines/test_piratebay.pydeleted−166
@@ -1,166 +0,0 @@
1−# -*- coding: utf-8 -*-
2−from collections import defaultdict
3−import mock
4−from searx.engines import piratebay
5−from searx.testing import SearxTestCase
6−
7−
8−class TestPiratebayEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dicto = defaultdict(dict)
13− dicto['pageno'] = 1
14− dicto['category'] = 'Toto'
15− params = piratebay.request(query, dicto)
16− self.assertIn('url', params)
17− self.assertIn(query, params['url'])
18− self.assertIn('piratebay.org', params['url'])
19− self.assertIn('0', params['url'])
20−
21− dicto['category'] = 'music'
22− params = piratebay.request(query, dicto)
23− self.assertIn('100', params['url'])
24−
25− def test_response(self):
26− self.assertRaises(AttributeError, piratebay.response, None)
27− self.assertRaises(AttributeError, piratebay.response, [])
28− self.assertRaises(AttributeError, piratebay.response, '')
29− self.assertRaises(AttributeError, piratebay.response, '[]')
30−
31− response = mock.Mock(text='<html></html>')
32− self.assertEqual(piratebay.response(response), [])
33−
34− html = """
35− <table id="searchResult">
36− <tr>
37− </tr>
38− <tr>
39− <td class="vertTh">
40− <center>
41− <a href="#" title="More from this category">Anime</a><br/>
42− (<a href="#" title="More from this category">Anime</a>)
43− </center>
44− </td>
45− <td>
46− <div class="detName">
47− <a href="/this.is.the.link" class="detLink" title="Title">
48− This is the title
49− </a>
50− </div>
51− <a href="magnet:?xt=urn:btih:MAGNETLINK" title="Download this torrent using magnet">
52− <img src="/static/img/icon-magnet.gif" alt="Magnet link"/>
53− </a>
54− <a href="http://torcache.net/torrent/TORRENTFILE.torrent" title="Download this torrent">
55− <img src="/static/img/dl.gif" class="dl" alt="Download"/>
56− </a>
57− <a href="/user/HorribleSubs">
58− <img src="/static/img/vip.gif" alt="VIP" title="VIP" style="width:11px;" border='0'/>
59− </a>
60− <img src="/static/img/11x11p.png"/>
61− <font class="detDesc">
62− This is the content <span>and should be</span> OK
63− </font>
64− </td>
65− <td align="right">13</td>
66− <td align="right">334</td>
67− </tr>
68− <tr>
69− <td class="vertTh">
70− <center>
71− <a href="#" title="More from this category">Anime</a><br/>
72− (<a href="#" title="More from this category">Anime</a>)
73− </center>
74− </td>
75− <td>
76− <div class="detName">
77− <a href="/this.is.the.link" class="detLink" title="Title">
78− This is the title
79− </a>
80− </div>
81− <a href="magnet:?xt=urn:btih:MAGNETLINK" title="Download this torrent using magnet">
82− <img src="/static/img/icon-magnet.gif" alt="Magnet link"/>
83− </a>
84− <a href="/user/HorribleSubs">
85− <img src="/static/img/vip.gif" alt="VIP" title="VIP" style="width:11px;" border='0'/>
86− </a>
87− <img src="/static/img/11x11p.png"/>
88− <font class="detDesc">
89− This is the content <span>and should be</span> OK
90− </font>
91− </td>
92− <td align="right">13</td>
93− <td align="right">334</td>
94− </tr>
95− </table>
96− """
97− response = mock.Mock(text=html)
98− results = piratebay.response(response)
99− self.assertEqual(type(results), list)
100− self.assertEqual(len(results), 2)
101− self.assertEqual(results[0]['title'], 'This is the title')
102− self.assertEqual(results[0]['url'], 'https://thepiratebay.org/this.is.the.link')
103− self.assertEqual(results[0]['content'], 'This is the content and should be OK')
104− self.assertEqual(results[0]['seed'], 13)
105− self.assertEqual(results[0]['leech'], 334)
106− self.assertEqual(results[0]['magnetlink'], 'magnet:?xt=urn:btih:MAGNETLINK')
107− self.assertEqual(results[0]['torrentfile'], 'http://torcache.net/torrent/TORRENTFILE.torrent')
108−
109− self.assertEqual(results[1]['torrentfile'], None)
110−
111− html = """
112− <table id="searchResult">
113− <tr>
114− </tr>
115− <tr>
116− <td class="vertTh">
117− <center>
118− <a href="#" title="More from this category">Anime</a><br/>
119− (<a href="#" title="More from this category">Anime</a>)
120− </center>
121− </td>
122− <td>
123− <div class="detName">
124− <a href="/this.is.the.link" class="detLink" title="Title">
125− This is the title
126− </a>
127− </div>
128− <a href="magnet:?xt=urn:btih:MAGNETLINK" title="Download this torrent using magnet">
129− <img src="/static/img/icon-magnet.gif" alt="Magnet link"/>
130− </a>
131− <a href="http://torcache.net/torrent/TORRENTFILE.torrent" title="Download this torrent">
132− <img src="/static/img/dl.gif" class="dl" alt="Download"/>
133− </a>
134− <a href="/user/HorribleSubs">
135− <img src="/static/img/vip.gif" alt="VIP" title="VIP" style="width:11px;" border='0'/>
136− </a>
137− <img src="/static/img/11x11p.png"/>
138− <font class="detDesc">
139− This is the content <span>and should be</span> OK
140− </font>
141− </td>
142− <td align="right">s</td>
143− <td align="right">d</td>
144− </tr>
145− </table>
146− """
147− response = mock.Mock(text=html)
148− results = piratebay.response(response)
149− self.assertEqual(type(results), list)
150− self.assertEqual(len(results), 1)
151− self.assertEqual(results[0]['title'], 'This is the title')
152− self.assertEqual(results[0]['url'], 'https://thepiratebay.org/this.is.the.link')
153− self.assertEqual(results[0]['content'], 'This is the content and should be OK')
154− self.assertEqual(results[0]['seed'], 0)
155− self.assertEqual(results[0]['leech'], 0)
156− self.assertEqual(results[0]['magnetlink'], 'magnet:?xt=urn:btih:MAGNETLINK')
157− self.assertEqual(results[0]['torrentfile'], 'http://torcache.net/torrent/TORRENTFILE.torrent')
158−
159− html = """
160− <table id="searchResult">
161− </table>
162− """
163− response = mock.Mock(text=html)
164− results = piratebay.response(response)
165− self.assertEqual(type(results), list)
166− self.assertEqual(len(results), 0)
tests/unit/engines/test_qwant.pydeleted−339
@@ -1,339 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import qwant
4−from searx.testing import SearxTestCase
5−
6−
7−class TestQwantEngine(SearxTestCase):
8−
9− def test_request(self):
10− qwant.supported_languages = ['en-US', 'fr-CA', 'fr-FR']
11− qwant.language_aliases = {}
12− query = 'test_query'
13− dicto = defaultdict(dict)
14− dicto['pageno'] = 0
15− dicto['language'] = 'fr-FR'
16− qwant.categories = ['']
17− params = qwant.request(query, dicto)
18− self.assertIn('url', params)
19− self.assertIn(query, params['url'])
20− self.assertIn('web', params['url'])
21− self.assertIn('qwant.com', params['url'])
22− self.assertIn('fr_fr', params['url'])
23−
24− dicto['language'] = 'all'
25− qwant.categories = ['news']
26− params = qwant.request(query, dicto)
27− self.assertFalse('fr' in params['url'])
28− self.assertIn('news', params['url'])
29−
30− dicto['language'] = 'fr'
31− params = qwant.request(query, dicto)
32− self.assertIn('fr_fr', params['url'])
33−
34− def test_response(self):
35− self.assertRaises(AttributeError, qwant.response, None)
36− self.assertRaises(AttributeError, qwant.response, [])
37− self.assertRaises(AttributeError, qwant.response, '')
38− self.assertRaises(AttributeError, qwant.response, '[]')
39−
40− response = mock.Mock(text='{}')
41− self.assertEqual(qwant.response(response), [])
42−
43− response = mock.Mock(text='{"data": {}}')
44− self.assertEqual(qwant.response(response), [])
45−
46− json = """
47− {
48− "status": "success",
49− "data": {
50− "query": {
51− "locale": "en_us",
52− "query": "Test",
53− "offset": 10
54− },
55− "result": {
56− "items": [
57− {
58− "title": "Title",
59− "score": 9999,
60− "url": "http://www.url.xyz",
61− "source": "...",
62− "desc": "Description",
63− "date": "",
64− "_id": "db0aadd62c2a8565567ffc382f5c61fa",
65− "favicon": "https://s.qwant.com/fav.ico"
66− }
67− ],
68− "filters": []
69− },
70− "cache": {
71− "key": "e66aa864c00147a0e3a16ff7a5efafde",
72− "created": 1433092754,
73− "expiration": 259200,
74− "status": "miss",
75− "age": 0
76− }
77− }
78− }
79− """
80− response = mock.Mock(text=json)
81− qwant.categories = ['general']
82− results = qwant.response(response)
83− self.assertEqual(type(results), list)
84− self.assertEqual(len(results), 1)
85− self.assertEqual(results[0]['title'], 'Title')
86− self.assertEqual(results[0]['url'], 'http://www.url.xyz')
87− self.assertEqual(results[0]['content'], 'Description')
88−
89− json = """
90− {
91− "status": "success",
92− "data": {
93− "query": {
94− "locale": "en_us",
95− "query": "Test",
96− "offset": 10
97− },
98− "result": {
99− "items": [
100− {
101− "title": "Title",
102− "score": 9999,
103− "url": "http://www.url.xyz",
104− "source": "...",
105− "media": "http://image.jpg",
106− "desc": "",
107− "thumbnail": "http://thumbnail.jpg",
108− "date": "",
109− "_id": "db0aadd62c2a8565567ffc382f5c61fa",
110− "favicon": "https://s.qwant.com/fav.ico"
111− }
112− ],
113− "filters": []
114− },
115− "cache": {
116− "key": "e66aa864c00147a0e3a16ff7a5efafde",
117− "created": 1433092754,
118− "expiration": 259200,
119− "status": "miss",
120− "age": 0
121− }
122− }
123− }
124− """
125− response = mock.Mock(text=json)
126− qwant.categories = ['images']
127− results = qwant.response(response)
128− self.assertEqual(type(results), list)
129− self.assertEqual(len(results), 1)
130− self.assertEqual(results[0]['title'], 'Title')
131− self.assertEqual(results[0]['url'], 'http://www.url.xyz')
132− self.assertEqual(results[0]['content'], '')
133− self.assertEqual(results[0]['thumbnail_src'], 'http://thumbnail.jpg')
134− self.assertEqual(results[0]['img_src'], 'http://image.jpg')
135−
136− json = """
137− {
138− "status": "success",
139− "data": {
140− "query": {
141− "locale": "en_us",
142− "query": "Test",
143− "offset": 10
144− },
145− "result": {
146− "items": [
147− {
148− "title": "Title",
149− "score": 9999,
150− "url": "http://www.url.xyz",
151− "source": "...",
152− "desc": "Description",
153− "date": 1433260920,
154− "_id": "db0aadd62c2a8565567ffc382f5c61fa",
155− "favicon": "https://s.qwant.com/fav.ico"
156− }
157− ],
158− "filters": []
159− },
160− "cache": {
161− "key": "e66aa864c00147a0e3a16ff7a5efafde",
162− "created": 1433092754,
163− "expiration": 259200,
164− "status": "miss",
165− "age": 0
166− }
167− }
168− }
169− """
170− response = mock.Mock(text=json)
171− qwant.categories = ['news']
172− results = qwant.response(response)
173− self.assertEqual(type(results), list)
174− self.assertEqual(len(results), 1)
175− self.assertEqual(results[0]['title'], 'Title')
176− self.assertEqual(results[0]['url'], 'http://www.url.xyz')
177− self.assertEqual(results[0]['content'], 'Description')
178− self.assertIn('publishedDate', results[0])
179−
180− json = """
181− {
182− "status": "success",
183− "data": {
184− "query": {
185− "locale": "en_us",
186− "query": "Test",
187− "offset": 10
188− },
189− "result": {
190− "items": [
191− {
192− "title": "Title",
193− "score": 9999,
194− "url": "http://www.url.xyz",
195− "source": "...",
196− "desc": "Description",
197− "date": 1433260920,
198− "_id": "db0aadd62c2a8565567ffc382f5c61fa",
199− "favicon": "https://s.qwant.com/fav.ico"
200− }
201− ],
202− "filters": []
203− },
204− "cache": {
205− "key": "e66aa864c00147a0e3a16ff7a5efafde",
206− "created": 1433092754,
207− "expiration": 259200,
208− "status": "miss",
209− "age": 0
210− }
211− }
212− }
213− """
214− response = mock.Mock(text=json)
215− qwant.categories = ['social media']
216− results = qwant.response(response)
217− self.assertEqual(type(results), list)
218− self.assertEqual(len(results), 1)
219− self.assertEqual(results[0]['title'], 'Title')
220− self.assertEqual(results[0]['url'], 'http://www.url.xyz')
221− self.assertEqual(results[0]['content'], 'Description')
222− self.assertIn('publishedDate', results[0])
223−
224− json = """
225− {
226− "status": "success",
227− "data": {
228− "query": {
229− "locale": "en_us",
230− "query": "Test",
231− "offset": 10
232− },
233− "result": {
234− "items": [
235− {
236− "title": "Title",
237− "score": 9999,
238− "url": "http://www.url.xyz",
239− "source": "...",
240− "desc": "Description",
241− "date": 1433260920,
242− "_id": "db0aadd62c2a8565567ffc382f5c61fa",
243− "favicon": "https://s.qwant.com/fav.ico"
244− }
245− ],
246− "filters": []
247− },
248− "cache": {
249− "key": "e66aa864c00147a0e3a16ff7a5efafde",
250− "created": 1433092754,
251− "expiration": 259200,
252− "status": "miss",
253− "age": 0
254− }
255− }
256− }
257− """
258− response = mock.Mock(text=json)
259− qwant.categories = ['']
260− results = qwant.response(response)
261− self.assertEqual(type(results), list)
262− self.assertEqual(len(results), 0)
263−
264− json = """
265− {
266− "status": "success",
267− "data": {
268− "query": {
269− "locale": "en_us",
270− "query": "Test",
271− "offset": 10
272− },
273− "result": {
274− "filters": []
275− },
276− "cache": {
277− "key": "e66aa864c00147a0e3a16ff7a5efafde",
278− "created": 1433092754,
279− "expiration": 259200,
280− "status": "miss",
281− "age": 0
282− }
283− }
284− }
285− """
286− response = mock.Mock(text=json)
287− results = qwant.response(response)
288− self.assertEqual(type(results), list)
289− self.assertEqual(len(results), 0)
290−
291− json = """
292− {
293− "status": "success",
294− "data": {
295− "query": {
296− "locale": "en_us",
297− "query": "Test",
298− "offset": 10
299− },
300− "cache": {
301− "key": "e66aa864c00147a0e3a16ff7a5efafde",
302− "created": 1433092754,
303− "expiration": 259200,
304− "status": "miss",
305− "age": 0
306− }
307− }
308− }
309− """
310− response = mock.Mock(text=json)
311− results = qwant.response(response)
312− self.assertEqual(type(results), list)
313− self.assertEqual(len(results), 0)
314−
315− json = """
316− {
317− "status": "success"
318− }
319− """
320− response = mock.Mock(text=json)
321− results = qwant.response(response)
322− self.assertEqual(type(results), list)
323− self.assertEqual(len(results), 0)
324−
325− def test_fetch_supported_languages(self):
326− page = """some code...
327− config_set('project.regionalisation', {"continents":{},"languages":
328− {"de":{"code":"de","name":"Deutsch","countries":["DE","CH","AT"]},
329− "it":{"code":"it","name":"Italiano","countries":["IT","CH"]}}});
330− some more code..."""
331− response = mock.Mock(text=page)
332− languages = qwant._fetch_supported_languages(response)
333− self.assertEqual(type(languages), list)
334− self.assertEqual(len(languages), 5)
335− self.assertIn('de-DE', languages)
336− self.assertIn('de-CH', languages)
337− self.assertIn('de-AT', languages)
338− self.assertIn('it-IT', languages)
339− self.assertIn('it-CH', languages)
tests/unit/engines/test_reddit.pydeleted−71
@@ -1,71 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import reddit
4−from searx.testing import SearxTestCase
5−from datetime import datetime
6−
7−
8−class TestRedditEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dic = defaultdict(dict)
13− params = reddit.request(query, dic)
14− self.assertTrue('url' in params)
15− self.assertTrue(query in params['url'])
16− self.assertTrue('reddit.com' in params['url'])
17−
18− def test_response(self):
19− resp = mock.Mock(text='{}')
20− self.assertEqual(reddit.response(resp), [])
21−
22− json = """
23− {
24− "kind": "Listing",
25− "data": {
26− "children": [{
27− "data": {
28− "url": "http://google2.com/",
29− "permalink": "http://google.com/",
30− "title": "Title number one",
31− "selftext": "Sample",
32− "created_utc": 1401219957.0,
33− "thumbnail": "http://image.com/picture.jpg"
34− }
35− }, {
36− "data": {
37− "url": "https://reddit2.com/",
38− "permalink": "https://reddit.com/",
39− "title": "Title number two",
40− "selftext": "Dominus vobiscum",
41− "created_utc": 1438792533.0,
42− "thumbnail": "self"
43− }
44− }]
45− }
46− }
47− """
48−
49− resp = mock.Mock(text=json)
50− results = reddit.response(resp)
51−
52− self.assertEqual(len(results), 2)
53− self.assertEqual(type(results), list)
54−
55− # testing first result (picture)
56− r = results[0]
57− self.assertEqual(r['url'], 'http://google.com/')
58− self.assertEqual(r['title'], 'Title number one')
59− self.assertEqual(r['template'], 'images.html')
60− self.assertEqual(r['img_src'], 'http://google2.com/')
61− self.assertEqual(r['thumbnail_src'], 'http://image.com/picture.jpg')
62−
63− # testing second result (self-post)
64− r = results[1]
65− self.assertEqual(r['url'], 'https://reddit.com/')
66− self.assertEqual(r['title'], 'Title number two')
67− self.assertEqual(r['content'], 'Dominus vobiscum')
68− created = datetime.fromtimestamp(1438792533.0)
69− self.assertEqual(r['publishedDate'], created)
70− self.assertTrue('thumbnail_src' not in r)
71− self.assertTrue('img_src' not in r)
tests/unit/engines/test_scanr_structures.pydeleted−175
@@ -1,175 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import scanr_structures
4−from searx.testing import SearxTestCase
5−
6−
7−class TestScanrStructuresEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dicto = defaultdict(dict)
12− dicto['pageno'] = 1
13− params = scanr_structures.request(query, dicto)
14− self.assertIn('url', params)
15− self.assertIn(query, params['data'])
16− self.assertIn('scanr.enseignementsup-recherche.gouv.fr', params['url'])
17−
18− def test_response(self):
19− self.assertRaises(AttributeError, scanr_structures.response, None)
20− self.assertRaises(AttributeError, scanr_structures.response, [])
21− self.assertRaises(AttributeError, scanr_structures.response, '')
22− self.assertRaises(AttributeError, scanr_structures.response, '[]')
23−
24− response = mock.Mock(text='{}')
25− self.assertEqual(scanr_structures.response(response), [])
26−
27− response = mock.Mock(text='{"data": []}')
28− self.assertEqual(scanr_structures.response(response), [])
29−
30− json = u"""
31− {
32− "request":
33− {
34− "query":"test_query",
35− "page":1,
36− "pageSize":20,
37− "sortOrder":"RELEVANCY",
38− "sortDirection":"ASC",
39− "searchField":"ALL",
40− "from":0
41− },
42− "total":2471,
43− "results":[
44− {
45− "id":"200711886U",
46− "label":"Laboratoire d'Informatique de Grenoble",
47− "kind":"RNSR",
48− "publicEntity":true,
49− "address":{"city":"Grenoble","departement":"38"},
50− "logo":"/static/logos/200711886U.png",
51− "acronym":"LIG",
52− "type":{"code":"UR","label":"Unit\xe9 de recherche"},
53− "level":2,
54− "institutions":[
55− {
56− "id":"193819125",
57− "label":"Grenoble INP",
58− "acronym":"IPG",
59− "code":"UMR 5217"
60− },
61− {
62− "id":"130021397",
63− "label":"Universit\xe9 de Grenoble Alpes",
64− "acronym":"UGA",
65− "code":"UMR 5217"
66− },
67− {
68− "id":"180089013",
69− "label":"Centre national de la recherche scientifique",
70− "acronym":"CNRS",
71− "code":"UMR 5217"
72− },
73− {
74− "id":"180089047",
75− "label":"Institut national de recherche en informatique et en automatique",
76− "acronym":"Inria",
77− "code":"UMR 5217"
78− }
79− ],
80− "highlights":[
81− {
82− "type":"projects",
83− "value":"linguicielles d\xe9velopp\xe9s jusqu'ici par le GETALP\
84− du <strong>LIG</strong> en tant que prototypes op\xe9rationnels.\
85−\\r\\nDans le contexte"
86− },
87− {
88− "type":"acronym",
89− "value":"<strong>LIG</strong>"
90− },
91− {
92− "type":"websiteContents",
93− "value":"S\xe9lection\\nListe structures\\nD\xe9tail\\n\
94− Accueil\\n200711886U : <strong>LIG</strong>\
95− Laboratoire d'Informatique de Grenoble Unit\xe9 de recherche"},
96− {
97− "type":"publications",
98− "value":"de noms. Nous avons d'abord d\xe9velopp\xe9 LOOV \
99− (pour <strong>Lig</strong> Overlaid OCR in Vid\xe9o), \
100− un outil d'extraction des"
101− }
102− ]
103− },
104− {
105− "id":"199511665F",
106− "label":"Laboratoire Bordelais de Recherche en Informatique",
107− "kind":"RNSR",
108− "publicEntity":true,
109− "address":{"city":"Talence","departement":"33"},
110− "logo":"/static/logos/199511665F.png",
111− "acronym":"LaBRI",
112− "type":{"code":"UR","label":"Unit\xe9 de recherche"},
113− "level":2,
114− "institutions":[
115− {
116− "id":"130006356",
117− "label":"Institut polytechnique de Bordeaux",
118− "acronym":"IPB",
119− "code":"UMR 5800"
120− },
121− {
122− "id":"130018351",
123− "label":"Universit\xe9 de Bordeaux",
124− "acronym":null,
125− "code":"UMR 5800"
126− },
127− {
128− "id":"180089013",
129− "label":"Centre national de la recherche scientifique",
130− "acronym":"CNRS",
131− "code":"UMR 5800"
132− },
133− {
134− "id":"180089047",
135− "label":"Institut national de recherche en informatique et en automatique",
136− "acronym":"Inria",
137− "code":"UMR 5800"
138− }
139− ],
140− "highlights":[
141− {
142− "type":"websiteContents",
143− "value":"Samia Kerdjoudj\\n2016-07-05\\nDouble-exponential\
144− and <strong>triple</strong>-exponential bounds for\
145− choosability problems parameterized"
146− },
147− {
148− "type":"publications",
149− "value":"de cam\xe9ras install\xe9es dans les lieux publiques \
150− a <strong>tripl\xe9</strong> en 2009, passant de 20 000 \
151− \xe0 60 000. Malgr\xe9 le"
152− }
153− ]
154− }
155− ]
156− }
157− """
158− response = mock.Mock(text=json)
159− results = scanr_structures.response(response)
160− self.assertEqual(type(results), list)
161− self.assertEqual(len(results), 2)
162− self.assertEqual(results[0]['title'], u"Laboratoire d'Informatique de Grenoble")
163− self.assertEqual(results[0]['url'], 'https://scanr.enseignementsup-recherche.gouv.fr/structure/200711886U')
164− self.assertEqual(results[0]['content'],
165− u"linguicielles d\xe9velopp\xe9s jusqu'ici par le GETALP "
166− u"du LIG en tant que prototypes "
167− u"op\xe9rationnels. Dans le contexte")
168− self.assertEqual(results[1]['img_src'],
169− 'https://scanr.enseignementsup-recherche.gouv.fr//static/logos/199511665F.png')
170− self.assertEqual(results[1]['content'],
171− "Samia Kerdjoudj 2016-07-05 Double-exponential and"
172− " triple-exponential bounds for "
173− "choosability problems parameterized")
174− self.assertEqual(results[1]['url'], 'https://scanr.enseignementsup-recherche.gouv.fr/structure/199511665F')
175− self.assertEqual(results[1]['title'], u"Laboratoire Bordelais de Recherche en Informatique")
tests/unit/engines/test_searchcode_code.pydeleted−75
@@ -1,75 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import searchcode_code
4−from searx.testing import SearxTestCase
5−
6−
7−class TestSearchcodeCodeEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dicto = defaultdict(dict)
12− dicto['pageno'] = 0
13− params = searchcode_code.request(query, dicto)
14− self.assertIn('url', params)
15− self.assertIn(query, params['url'])
16− self.assertIn('searchcode.com', params['url'])
17−
18− def test_response(self):
19− self.assertRaises(AttributeError, searchcode_code.response, None)
20− self.assertRaises(AttributeError, searchcode_code.response, [])
21− self.assertRaises(AttributeError, searchcode_code.response, '')
22− self.assertRaises(AttributeError, searchcode_code.response, '[]')
23−
24− response = mock.Mock(text='{}')
25− self.assertEqual(searchcode_code.response(response), [])
26−
27− response = mock.Mock(text='{"data": []}')
28− self.assertEqual(searchcode_code.response(response), [])
29−
30− json = """
31− {
32− "matchterm": "test",
33− "previouspage": null,
34− "searchterm": "test",
35− "query": "test",
36− "total": 1000,
37− "page": 0,
38− "nextpage": 1,
39− "results": [
40− {
41− "repo": "https://repo",
42− "linescount": 1044,
43− "location": "/tests",
44− "name": "Name",
45− "url": "https://url",
46− "md5hash": "ecac6e479edd2b9406c9e08603cec655",
47− "lines": {
48− "1": "// Test 011",
49− "2": "// Source: "
50− },
51− "id": 51223527,
52− "filename": "File.CPP"
53− }
54− ]
55− }
56− """
57− response = mock.Mock(text=json)
58− results = searchcode_code.response(response)
59− self.assertEqual(type(results), list)
60− self.assertEqual(len(results), 1)
61− self.assertEqual(results[0]['title'], 'Name - File.CPP')
62− self.assertEqual(results[0]['url'], 'https://url')
63− self.assertEqual(results[0]['repository'], 'https://repo')
64− self.assertEqual(results[0]['code_language'], 'cpp')
65−
66− json = r"""
67− {"toto":[
68− {"id":200,"name":"Artist Name",
69− "link":"http:\/\/www.searchcode_code.com\/artist\/1217","type":"artist"}
70− ]}
71− """
72− response = mock.Mock(text=json)
73− results = searchcode_code.response(response)
74− self.assertEqual(type(results), list)
75− self.assertEqual(len(results), 0)
tests/unit/engines/test_searchcode_doc.pydeleted−70
@@ -1,70 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import searchcode_doc
4−from searx.testing import SearxTestCase
5−
6−
7−class TestSearchcodeDocEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dicto = defaultdict(dict)
12− dicto['pageno'] = 0
13− params = searchcode_doc.request(query, dicto)
14− self.assertIn('url', params)
15− self.assertIn(query, params['url'])
16− self.assertIn('searchcode.com', params['url'])
17−
18− def test_response(self):
19− self.assertRaises(AttributeError, searchcode_doc.response, None)
20− self.assertRaises(AttributeError, searchcode_doc.response, [])
21− self.assertRaises(AttributeError, searchcode_doc.response, '')
22− self.assertRaises(AttributeError, searchcode_doc.response, '[]')
23−
24− response = mock.Mock(text='{}')
25− self.assertEqual(searchcode_doc.response(response), [])
26−
27− response = mock.Mock(text='{"data": []}')
28− self.assertEqual(searchcode_doc.response(response), [])
29−
30− json = """
31− {
32− "matchterm": "test",
33− "previouspage": null,
34− "searchterm": "test",
35− "query": "test",
36− "total": 60,
37− "page": 0,
38− "nextpage": 1,
39− "results": [
40− {
41− "synopsis": "Synopsis",
42− "displayname": null,
43− "name": "test",
44− "url": "http://url",
45− "type": "Type",
46− "icon": null,
47− "namespace": "Namespace",
48− "description": "Description"
49− }
50− ]
51− }
52− """
53− response = mock.Mock(text=json)
54− results = searchcode_doc.response(response)
55− self.assertEqual(type(results), list)
56− self.assertEqual(len(results), 1)
57− self.assertEqual(results[0]['title'], '[Type] Namespace test')
58− self.assertEqual(results[0]['url'], 'http://url')
59− self.assertIn('Description', results[0]['content'])
60−
61− json = r"""
62− {"toto":[
63− {"id":200,"name":"Artist Name",
64− "link":"http:\/\/www.searchcode_doc.com\/artist\/1217","type":"artist"}
65− ]}
66− """
67− response = mock.Mock(text=json)
68− results = searchcode_doc.response(response)
69− self.assertEqual(type(results), list)
70− self.assertEqual(len(results), 0)
tests/unit/engines/test_soundcloud.pydeleted−192
@@ -1,192 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import soundcloud
4−from searx.testing import SearxTestCase
5−from searx.url_utils import quote_plus
6−
7−
8−class TestSoundcloudEngine(SearxTestCase):
9−
10− def test_request(self):
11− query = 'test_query'
12− dicto = defaultdict(dict)
13− dicto['pageno'] = 1
14− params = soundcloud.request(query, dicto)
15− self.assertIn('url', params)
16− self.assertIn(query, params['url'])
17− self.assertIn('soundcloud.com', params['url'])
18−
19− def test_response(self):
20− self.assertRaises(AttributeError, soundcloud.response, None)
21− self.assertRaises(AttributeError, soundcloud.response, [])
22− self.assertRaises(AttributeError, soundcloud.response, '')
23− self.assertRaises(AttributeError, soundcloud.response, '[]')
24−
25− response = mock.Mock(text='{}')
26− self.assertEqual(soundcloud.response(response), [])
27−
28− response = mock.Mock(text='{"data": []}')
29− self.assertEqual(soundcloud.response(response), [])
30−
31− json = """
32− {
33− "collection": [
34− {
35− "kind": "track",
36− "id": 159723640,
37− "created_at": "2014/07/22 00:51:21 +0000",
38− "user_id": 2976616,
39− "duration": 303780,
40− "commentable": true,
41− "state": "finished",
42− "original_content_size": 13236349,
43− "last_modified": "2015/01/31 15:14:50 +0000",
44− "sharing": "public",
45− "tag_list": "seekae flume",
46− "permalink": "seekae-test-recognise-flume-re-work",
47− "streamable": true,
48− "embeddable_by": "all",
49− "downloadable": true,
50− "purchase_url": "http://www.facebook.com/seekaemusic",
51− "label_id": null,
52− "purchase_title": "Seekae",
53− "genre": "freedownload",
54− "title": "This is the title",
55− "description": "This is the content",
56− "label_name": "Future Classic",
57− "release": "",
58− "track_type": "remix",
59− "key_signature": "",
60− "isrc": "",
61− "video_url": null,
62− "bpm": null,
63− "release_year": 2014,
64− "release_month": 7,
65− "release_day": 22,
66− "original_format": "mp3",
67− "license": "all-rights-reserved",
68− "uri": "https://api.soundcloud.com/tracks/159723640",
69− "user": {
70− "id": 2976616,
71− "kind": "user",
72− "permalink": "flume",
73− "username": "Flume",
74− "last_modified": "2014/11/24 19:21:29 +0000",
75− "uri": "https://api.soundcloud.com/users/2976616",
76− "permalink_url": "http://soundcloud.com/flume",
77− "avatar_url": "https://i1.sndcdn.com/avatars-000044475439-4zi7ii-large.jpg"
78− },
79− "permalink_url": "http://soundcloud.com/this.is.the.url",
80− "artwork_url": "https://i1.sndcdn.com/artworks-000085857162-xdxy5c-large.jpg",
81− "waveform_url": "https://w1.sndcdn.com/DWrL1lAN8BkP_m.png",
82− "stream_url": "https://api.soundcloud.com/tracks/159723640/stream",
83− "download_url": "https://api.soundcloud.com/tracks/159723640/download",
84− "playback_count": 2190687,
85− "download_count": 54856,
86− "favoritings_count": 49061,
87− "comment_count": 826,
88− "likes_count": 49061,
89− "reposts_count": 15910,
90− "attachments_uri": "https://api.soundcloud.com/tracks/159723640/attachments",
91− "policy": "ALLOW"
92− }
93− ],
94− "total_results": 375750,
95− "next_href": "https://api.soundcloud.com/search?&q=test",
96− "tx_id": ""
97− }
98− """
99− response = mock.Mock(text=json)
100− results = soundcloud.response(response)
101− self.assertEqual(type(results), list)
102− self.assertEqual(len(results), 1)
103− self.assertEqual(results[0]['title'], 'This is the title')
104− self.assertEqual(results[0]['url'], 'http://soundcloud.com/this.is.the.url')
105− self.assertEqual(results[0]['content'], 'This is the content')
106− self.assertIn(quote_plus('https://api.soundcloud.com/tracks/159723640'), results[0]['embedded'])
107−
108− json = """
109− {
110− "collection": [
111− {
112− "kind": "user",
113− "id": 159723640,
114− "created_at": "2014/07/22 00:51:21 +0000",
115− "user_id": 2976616,
116− "duration": 303780,
117− "commentable": true,
118− "state": "finished",
119− "original_content_size": 13236349,
120− "last_modified": "2015/01/31 15:14:50 +0000",
121− "sharing": "public",
122− "tag_list": "seekae flume",
123− "permalink": "seekae-test-recognise-flume-re-work",
124− "streamable": true,
125− "embeddable_by": "all",
126− "downloadable": true,
127− "purchase_url": "http://www.facebook.com/seekaemusic",
128− "label_id": null,
129− "purchase_title": "Seekae",
130− "genre": "freedownload",
131− "title": "This is the title",
132− "description": "This is the content",
133− "label_name": "Future Classic",
134− "release": "",
135− "track_type": "remix",
136− "key_signature": "",
137− "isrc": "",
138− "video_url": null,
139− "bpm": null,
140− "release_year": 2014,
141− "release_month": 7,
142− "release_day": 22,
143− "original_format": "mp3",
144− "license": "all-rights-reserved",
145− "uri": "https://api.soundcloud.com/tracks/159723640",
146− "user": {
147− "id": 2976616,
148− "kind": "user",
149− "permalink": "flume",
150− "username": "Flume",
151− "last_modified": "2014/11/24 19:21:29 +0000",
152− "uri": "https://api.soundcloud.com/users/2976616",
153− "permalink_url": "http://soundcloud.com/flume",
154− "avatar_url": "https://i1.sndcdn.com/avatars-000044475439-4zi7ii-large.jpg"
155− },
156− "permalink_url": "http://soundcloud.com/this.is.the.url",
157− "artwork_url": "https://i1.sndcdn.com/artworks-000085857162-xdxy5c-large.jpg",
158− "waveform_url": "https://w1.sndcdn.com/DWrL1lAN8BkP_m.png",
159− "stream_url": "https://api.soundcloud.com/tracks/159723640/stream",
160− "download_url": "https://api.soundcloud.com/tracks/159723640/download",
161− "playback_count": 2190687,
162− "download_count": 54856,
163− "favoritings_count": 49061,
164− "comment_count": 826,
165− "likes_count": 49061,
166− "reposts_count": 15910,
167− "attachments_uri": "https://api.soundcloud.com/tracks/159723640/attachments",
168− "policy": "ALLOW"
169− }
170− ],
171− "total_results": 375750,
172− "next_href": "https://api.soundcloud.com/search?&q=test",
173− "tx_id": ""
174− }
175− """
176− response = mock.Mock(text=json)
177− results = soundcloud.response(response)
178− self.assertEqual(type(results), list)
179− self.assertEqual(len(results), 0)
180−
181− json = """
182− {
183− "collection": [],
184− "total_results": 375750,
185− "next_href": "https://api.soundcloud.com/search?&q=test",
186− "tx_id": ""
187− }
188− """
189− response = mock.Mock(text=json)
190− results = soundcloud.response(response)
191− self.assertEqual(type(results), list)
192− self.assertEqual(len(results), 0)
tests/unit/engines/test_spotify.pydeleted−124
@@ -1,124 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import spotify
4−from searx.testing import SearxTestCase
5−
6−
7−class TestSpotifyEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dicto = defaultdict(dict)
12− dicto['pageno'] = 0
13− params = spotify.request(query, dicto)
14− self.assertIn('url', params)
15− self.assertIn(query, params['url'])
16− self.assertIn('spotify.com', params['url'])
17−
18− def test_response(self):
19− self.assertRaises(AttributeError, spotify.response, None)
20− self.assertRaises(AttributeError, spotify.response, [])
21− self.assertRaises(AttributeError, spotify.response, '')
22− self.assertRaises(AttributeError, spotify.response, '[]')
23−
24− response = mock.Mock(text='{}')
25− self.assertEqual(spotify.response(response), [])
26−
27− response = mock.Mock(text='{"data": []}')
28− self.assertEqual(spotify.response(response), [])
29−
30− json = """
31− {
32− "tracks": {
33− "href": "https://api.spotify.com/v1/search?query=nosfell&offset=0&limit=20&type=track",
34− "items": [
35− {
36− "album": {
37− "album_type": "album",
38− "external_urls": {
39− "spotify": "https://open.spotify.com/album/5c9ap1PBkSGLxT3J73toxA"
40− },
41− "href": "https://api.spotify.com/v1/albums/5c9ap1PBkSGLxT3J73toxA",
42− "id": "5c9ap1PBkSGLxT3J73toxA",
43− "name": "Album Title",
44− "type": "album",
45− "uri": "spotify:album:5c9ap1PBkSGLxT3J73toxA"
46− },
47− "artists": [
48− {
49− "external_urls": {
50− "spotify": "https://open.spotify.com/artist/0bMc6b75FfZEpQHG1jifKu"
51− },
52− "href": "https://api.spotify.com/v1/artists/0bMc6b75FfZEpQHG1jifKu",
53− "id": "0bMc6b75FfZEpQHG1jifKu",
54− "name": "Artist Name",
55− "type": "artist",
56− "uri": "spotify:artist:0bMc6b75FfZEpQHG1jifKu"
57− }
58− ],
59− "disc_number": 1,
60− "duration_ms": 202386,
61− "explicit": false,
62− "external_ids": {
63− "isrc": "FRV640600067"
64− },
65− "external_urls": {
66− "spotify": "https://open.spotify.com/track/2GzvFiedqW8hgqUpWcASZa"
67− },
68− "href": "https://api.spotify.com/v1/tracks/2GzvFiedqW8hgqUpWcASZa",
69− "id": "1000",
70− "is_playable": true,
71− "name": "Title of track",
72− "popularity": 6,
73− "preview_url": "https://p.scdn.co/mp3-preview/7b8ecda580965a066b768c2647f877e43f7b1a0a",
74− "track_number": 3,
75− "type": "track",
76− "uri": "spotify:track:2GzvFiedqW8hgqUpWcASZa"
77− }
78− ],
79− "limit": 20,
80− "next": "https://api.spotify.com/v1/search?query=nosfell&offset=20&limit=20&type=track",
81− "offset": 0,
82− "previous": null,
83− "total": 107
84− }
85− }
86− """
87− response = mock.Mock(text=json)
88− results = spotify.response(response)
89− self.assertEqual(type(results), list)
90− self.assertEqual(len(results), 1)
91− self.assertEqual(results[0]['title'], 'Title of track')
92− self.assertEqual(results[0]['url'], 'https://open.spotify.com/track/2GzvFiedqW8hgqUpWcASZa')
93− self.assertEqual(results[0]['content'], 'Artist Name - Album Title - Title of track')
94− self.assertIn('1000', results[0]['embedded'])
95−
96− json = """
97− {
98− "tracks": {
99− "href": "https://api.spotify.com/v1/search?query=nosfell&offset=0&limit=20&type=track",
100− "items": [
101− {
102− "href": "https://api.spotify.com/v1/tracks/2GzvFiedqW8hgqUpWcASZa",
103− "id": "1000",
104− "is_playable": true,
105− "name": "Title of track",
106− "popularity": 6,
107− "preview_url": "https://p.scdn.co/mp3-preview/7b8ecda580965a066b768c2647f877e43f7b1a0a",
108− "track_number": 3,
109− "type": "album",
110− "uri": "spotify:track:2GzvFiedqW8hgqUpWcASZa"
111− }
112− ],
113− "limit": 20,
114− "next": "https://api.spotify.com/v1/search?query=nosfell&offset=20&limit=20&type=track",
115− "offset": 0,
116− "previous": null,
117− "total": 107
118− }
119− }
120− """
121− response = mock.Mock(text=json)
122− results = spotify.response(response)
123− self.assertEqual(type(results), list)
124− self.assertEqual(len(results), 0)
tests/unit/engines/test_stackoverflow.pydeleted−106
@@ -1,106 +0,0 @@
1−from collections import defaultdict
2−import mock
3−from searx.engines import stackoverflow
4−from searx.testing import SearxTestCase
5−
6−
7−class TestStackoverflowEngine(SearxTestCase):
8−
9− def test_request(self):
10− query = 'test_query'
11− dicto = defaultdict(dict)
12− dicto['pageno'] = 0
13− params = stackoverflow.request(query, dicto)
14− self.assertTrue('url' in params)
15− self.assertTrue(query in params['url'])
16− self.assertTrue('stackoverflow.com' in params['url'])
17−
18− def test_response(self):
19− self.assertRaises(AttributeError, stackoverflow.response, None)
20− self.assertRaises(AttributeError, stackoverflow.response, [])
21− self.assertRaises(AttributeError, stackoverflow.response, '')
22− self.assertRaises(AttributeError, stackoverflow.response, '[]')
23−
24− response = mock.Mock(text='<html></html>')
25− self.assertEqual(stackoverflow.response(response), [])
26−
27− html = """
28− <div class="question-summary search-result" id="answer-id-1783426">
29− <div class="statscontainer">
30− <div class="statsarrow"></div>
31− <div class="stats">
32− <div class="vote">
33− <div class="votes answered">
34− <span class="vote-count-post "><strong>2583</strong></span>
35− <div class="viewcount">votes</div>
36− </div>
37− </div>
38− </div>
39− </div>
40− <div class="summary">
41− <div class="result-link">
42− <span>
43− <a href="/questions/this.is.the.url"
44− data-searchsession="/questions"
45− title="Checkout remote Git branch">
46− This is the title
47− </a>
48− </span>
49− </div>
50− <div class="excerpt">
51− This is the content
52− </div>
53− <div class="tags user-tags t-git t-git-checkout t-remote-branch">
54− </div>
55− <div class="started fr">
56− answered <span title="2009-11-23 14:26:08Z" class="relativetime">nov 23 '09</span> by
57− <a href="/users/214090/hallski">hallski</a>
58− </div>
59− </div>
60− </div>
61− """
62− response = mock.Mock(text=html)
63− results = stackoverflow.response(response)
64− self.assertEqual(type(results), list)
65− self.assertEqual(len(results), 1)
66− self.assertEqual(results[0]['title'], 'This is the title')
67− self.assertEqual(results[0]['url'], 'https://stackoverflow.com/questions/this.is.the.url')
68− self.assertEqual(results[0]['content'], 'This is the content')
69−
70− html = """
71− <div class="statscontainer">
72− <div class="statsarrow"></div>
73− <div class="stats">
74− <div class="vote">
75− <div class="votes answered">
76− <span class="vote-count-post "><strong>2583</strong></span>
77− <div class="viewcount">votes</div>
78− </div>
79− </div>
80− </div>
81− </div>
82− <div class="summary">
83− <div class="result-link">
84− <span>
85− <a href="/questions/this.is.the.url"
86− data-searchsession="/questions"
87− title="Checkout remote Git branch">
88− This is the title
89− </a>
90− </span>
91− </div>
92− <div class="excerpt">
93− This is the content
94− </div>
95− <div class="tags user-tags t-git t-git-checkout t-remote-branch">
96− </div>
97− <div class="started fr">
98− answered <span title="2009-11-23 14:26:08Z" class="relativetime">nov 23 '09</span> by
99− <a href="/users/214090/hallski">hallski</a>
100− </div>
101− </div>
102− """
103− response = mock.Mock(text=html)
104− results = stackoverflow.response(response)
105− self.assertEqual(type(results), list)
106− self.assertEqual(len(results), 0)
tests/unit/engines/test_startpage.pydeleted−140

This diff is too big to show here.

tests/unit/engines/test_tokyotoshokan.pydeleted−110

This diff is too big to show here.

tests/unit/engines/test_torrentz.pydeleted−87

This diff is too big to show here.

tests/unit/engines/test_twitter.pydeleted−502

This diff is too big to show here.

tests/unit/engines/test_unsplash.pydeleted−38

This diff is too big to show here.

tests/unit/engines/test_vimeo.pydeleted−36

This diff is too big to show here.

tests/unit/engines/test_wikidata.pydeleted−514

This diff is too big to show here.

tests/unit/engines/test_wikipedia.pydeleted−263

This diff is too big to show here.

tests/unit/engines/test_wolframalpha_api.pydeleted−166

This diff is too big to show here.

tests/unit/engines/test_wolframalpha_noapi.pydeleted−224

This diff is too big to show here.

tests/unit/engines/test_www1x.pydeleted−57

This diff is too big to show here.

tests/unit/engines/test_yacy.pydeleted−96

This diff is too big to show here.

tests/unit/engines/test_yahoo.pydeleted−190

This diff is too big to show here.

tests/unit/engines/test_yahoo_news.pydeleted−150

This diff is too big to show here.

tests/unit/engines/test_youtube_api.pydeleted−111

This diff is too big to show here.

tests/unit/engines/test_youtube_noapi.pydeleted−124

This diff is too big to show here.

tests/unit/engines/unsplash_fixture.jsondeleted−241

This diff is too big to show here.

tests/unit/test_query.py+42

This diff is too big to show here.

tests/unit/test_search.py+53−3

This diff is too big to show here.

tests/unit/test_utils.py+7

This diff is too big to show here.

tests/unit/test_webapp.py+7−6

This diff is too big to show here.

utils/makefile.includenew file+128

This diff is too big to show here.

utils/makefile.pythonnew file+290

This diff is too big to show here.

utils/makefile.sphinxnew file+216

This diff is too big to show here.