From 31b26412b0082e88e798f44c410deaf61b582cda Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Tue, 29 Mar 2022 12:02:57 +0530 Subject: [PATCH 01/11] add calculator plugin --- searx/plugins/__init__.py | 2 ++ searx/plugins/calculator.py | 32 +++++++++++++++++++++++++++++ searx/settings.yml | 4 ++-- searx/templates/etheme/results.html | 4 ++-- 4 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 searx/plugins/calculator.py diff --git a/searx/plugins/__init__.py b/searx/plugins/__init__.py index 95fc24798..f22797602 100644 --- a/searx/plugins/__init__.py +++ b/searx/plugins/__init__.py @@ -29,6 +29,7 @@ logger = logger.getChild('plugins') from searx.plugins import (oa_doi_rewrite, ahmia_filter, hash_plugin, + calculator, https_rewrite, infinite_scroll, self_info, @@ -175,6 +176,7 @@ plugins.register(search_on_category_select) plugins.register(tracker_url_remover) plugins.register(vim_hotkeys) plugins.register(rest_api) +plugins.register(calculator) # load external plugins if 'plugins' in settings: plugins.register(*settings['plugins'], external=True) diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py new file mode 100644 index 000000000..cbf7ae4e9 --- /dev/null +++ b/searx/plugins/calculator.py @@ -0,0 +1,32 @@ +from searx import logger +import math + +name = "Calculator" +description = 'This plugin extends the suggestions with the word "example"' +default_on = False +logger = logger.getChild("calculator") +ALLOWED_NAMES = { + k: v for k, v in math.__dict__.items() if not k.startswith("__") +} + +def check_if_loaded(): + logger.debug("initializing calculator plugin") + +def post_search(request, search): + if search.search_query.pageno > 1: + return True + try: + code = compile(search.search_query.query, "", "eval") + for name in code.co_names: + if name not in ALLOWED_NAMES: + return False + code = eval(code, {"__builtins__": {}}, ALLOWED_NAMES) + if type(code) != str: + search.result_container.answers.clear() + search.result_container.answers['Result'] = {'answer': code} + except Exception: + return False + return True + + +check_if_loaded() \ No newline at end of file diff --git a/searx/settings.yml b/searx/settings.yml index db3bedd4e..50469eb74 100644 --- a/searx/settings.yml +++ b/searx/settings.yml @@ -108,8 +108,8 @@ outgoing: # communication with search engines # uncomment below section if you want to configure which plugin is enabled by default # -# enabled_plugins: -# - "HTTPS rewrite" +enabled_plugins: + - "calculator" # - ... # Example to rewrite hostnames in external links diff --git a/searx/templates/etheme/results.html b/searx/templates/etheme/results.html index ba7530446..ff3a0c2e6 100644 --- a/searx/templates/etheme/results.html +++ b/searx/templates/etheme/results.html @@ -26,9 +26,9 @@ {% endif %} {% if answers %} - {% for answer in answers %} + {% for answer, value in answers.items() %}
- {{ answer }} + {{ answer }} : {{ value['answer'] }}
{% endfor %} {% endif %} -- GitLab From 31acff0dfd394461bcca86da99f445f0b3554122 Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Tue, 29 Mar 2022 13:41:48 +0530 Subject: [PATCH 02/11] fix calculator result --- searx/plugins/calculator.py | 17 ++++++++++++++--- searx/templates/etheme/results.html | 4 ++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py index cbf7ae4e9..5dcbbcd54 100644 --- a/searx/plugins/calculator.py +++ b/searx/plugins/calculator.py @@ -1,3 +1,4 @@ +from decimal import DivisionByZero from searx import logger import math @@ -21,10 +22,20 @@ def post_search(request, search): if name not in ALLOWED_NAMES: return False code = eval(code, {"__builtins__": {}}, ALLOWED_NAMES) - if type(code) != str: + if type(code) in (int, float): search.result_container.answers.clear() - search.result_container.answers['Result'] = {'answer': code} - except Exception: + answer = "The value of {} is {}".format(search.search_query.query, code) + search.result_container.answers[answer] = {'answer': str(answer)} + except (DivisionByZero, OverflowError) as e: + logger.debug(e) + search.result_container.answers[f'Please recheck the above query: {e}'] = {'answer': None} + return False + except (SyntaxError, NameError, TypeError) as e: + logger.debug(e) + search.result_container.answers[f'Please recheck syntax of above query'] = {'answer': None} + return False + except Exception as e: + logger.debug(e) return False return True diff --git a/searx/templates/etheme/results.html b/searx/templates/etheme/results.html index ff3a0c2e6..ba7530446 100644 --- a/searx/templates/etheme/results.html +++ b/searx/templates/etheme/results.html @@ -26,9 +26,9 @@ {% endif %} {% if answers %} - {% for answer, value in answers.items() %} + {% for answer in answers %}
- {{ answer }} : {{ value['answer'] }} + {{ answer }}
{% endfor %} {% endif %} -- GitLab From e9ba32433688673ba4e3cf679b88d549874587d9 Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Tue, 29 Mar 2022 13:55:13 +0530 Subject: [PATCH 03/11] add more errors in except --- searx/plugins/calculator.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py index 5dcbbcd54..fb27b3d8a 100644 --- a/searx/plugins/calculator.py +++ b/searx/plugins/calculator.py @@ -1,10 +1,10 @@ -from decimal import DivisionByZero from searx import logger import math name = "Calculator" +# TODO: translate the following line description = 'This plugin extends the suggestions with the word "example"' -default_on = False +default_on = True logger = logger.getChild("calculator") ALLOWED_NAMES = { k: v for k, v in math.__dict__.items() if not k.startswith("__") @@ -24,14 +24,17 @@ def post_search(request, search): code = eval(code, {"__builtins__": {}}, ALLOWED_NAMES) if type(code) in (int, float): search.result_container.answers.clear() + # TODO: translate the following line answer = "The value of {} is {}".format(search.search_query.query, code) search.result_container.answers[answer] = {'answer': str(answer)} - except (DivisionByZero, OverflowError) as e: + except (ZeroDivisionError, OverflowError, ValueError, FloatingPointError, MemoryError) as e: logger.debug(e) + # TODO: translate the following line search.result_container.answers[f'Please recheck the above query: {e}'] = {'answer': None} return False except (SyntaxError, NameError, TypeError) as e: logger.debug(e) + # TODO: translate the following line search.result_container.answers[f'Please recheck syntax of above query'] = {'answer': None} return False except Exception as e: -- GitLab From 770a39226a4899a193af33ccfa9163f7e0ddc17a Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Tue, 29 Mar 2022 14:03:09 +0530 Subject: [PATCH 04/11] fix pep8 issues --- searx/plugins/calculator.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py index fb27b3d8a..dbb6394eb 100644 --- a/searx/plugins/calculator.py +++ b/searx/plugins/calculator.py @@ -4,15 +4,17 @@ import math name = "Calculator" # TODO: translate the following line description = 'This plugin extends the suggestions with the word "example"' -default_on = True +default_on = True logger = logger.getChild("calculator") ALLOWED_NAMES = { k: v for k, v in math.__dict__.items() if not k.startswith("__") } + def check_if_loaded(): logger.debug("initializing calculator plugin") - + + def post_search(request, search): if search.search_query.pageno > 1: return True @@ -26,16 +28,16 @@ def post_search(request, search): search.result_container.answers.clear() # TODO: translate the following line answer = "The value of {} is {}".format(search.search_query.query, code) - search.result_container.answers[answer] = {'answer': str(answer)} + search.result_container.answers[answer] = {'answer': str(answer)} except (ZeroDivisionError, OverflowError, ValueError, FloatingPointError, MemoryError) as e: logger.debug(e) # TODO: translate the following line - search.result_container.answers[f'Please recheck the above query: {e}'] = {'answer': None} + search.result_container.answers[f'Please recheck the above query: {e}'] = {'answer': None} return False except (SyntaxError, NameError, TypeError) as e: logger.debug(e) # TODO: translate the following line - search.result_container.answers[f'Please recheck syntax of above query'] = {'answer': None} + search.result_container.answers[f'Please recheck syntax of above query'] = {'answer': None} return False except Exception as e: logger.debug(e) @@ -43,4 +45,4 @@ def post_search(request, search): return True -check_if_loaded() \ No newline at end of file +check_if_loaded() -- GitLab From 4547f73e21b01c2ed2182039453501ac08eed33d Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Wed, 30 Mar 2022 01:12:49 +0530 Subject: [PATCH 05/11] use numexpr for evaluation of expressions --- requirements-dev.txt | 1 + requirements.txt | 2 +- searx/plugins/calculator.py | 36 +++++++++++++++++++++++++----------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index a2c714de1..daeed84bc 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -18,3 +18,4 @@ sphinxcontrib-programoutput==0.17 sphinx-autobuild==2021.3.14 linuxdoc==20211220 aiounittest==1.4.1 +numexpr==2.8.1 diff --git a/requirements.txt b/requirements.txt index d737e113f..a25cb6ea6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,4 +16,4 @@ langdetect==1.0.9 setproctitle==1.2.2 redis==3.4.1 ring==0.7.3 - +numexpr==2.8.1 diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py index dbb6394eb..4f6292626 100644 --- a/searx/plugins/calculator.py +++ b/searx/plugins/calculator.py @@ -1,39 +1,53 @@ from searx import logger -import math +from numexpr import evaluate name = "Calculator" # TODO: translate the following line -description = 'This plugin extends the suggestions with the word "example"' +description = 'This plugin extends results when the query is a mathematical expression' default_on = True logger = logger.getChild("calculator") -ALLOWED_NAMES = { - k: v for k, v in math.__dict__.items() if not k.startswith("__") -} def check_if_loaded(): logger.debug("initializing calculator plugin") +def is_really_big(query): + # For cases like 2**99999**9999 + if len(query.split("**")) >= 3: + return True + # Add more cases if needed + return False + + def post_search(request, search): if search.search_query.pageno > 1: return True try: - code = compile(search.search_query.query, "", "eval") - for name in code.co_names: - if name not in ALLOWED_NAMES: - return False - code = eval(code, {"__builtins__": {}}, ALLOWED_NAMES) + # Not going to compute the result if the query is too big + if len(search.search_query.query) > 20: + return True + + # Not going to compute the result if the query is not within permissible range + if is_really_big(search.search_query.query): + raise OverflowError + + code = evaluate(search.search_query.query).item() if type(code) in (int, float): search.result_container.answers.clear() # TODO: translate the following line answer = "The value of {} is {}".format(search.search_query.query, code) search.result_container.answers[answer] = {'answer': str(answer)} - except (ZeroDivisionError, OverflowError, ValueError, FloatingPointError, MemoryError) as e: + except (ZeroDivisionError, ValueError, FloatingPointError, MemoryError) as e: logger.debug(e) # TODO: translate the following line search.result_container.answers[f'Please recheck the above query: {e}'] = {'answer': None} return False + except OverflowError as e: + logger.debug(e) + # TODO: translate the following line + search.result_container.answers[f'Please recheck the above query: Too big to compute {e}'] = {'answer': None} + return False except (SyntaxError, NameError, TypeError) as e: logger.debug(e) # TODO: translate the following line -- GitLab From 4046a5db74251b4bb80a2f6274b17a9bb6120d39 Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Wed, 30 Mar 2022 01:34:05 +0530 Subject: [PATCH 06/11] do not attempt to compute when not a number --- searx/plugins/calculator.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py index 4f6292626..bd42d67ad 100644 --- a/searx/plugins/calculator.py +++ b/searx/plugins/calculator.py @@ -24,19 +24,26 @@ def post_search(request, search): if search.search_query.pageno > 1: return True try: + query = search.search_query.query.lower() + query = query.replace("x", "*") + + # Not going to compute if no numbers are present + if not any(i.isdigit() for i in query): + return True + # Not going to compute the result if the query is too big - if len(search.search_query.query) > 20: + if len(query) > 30: return True # Not going to compute the result if the query is not within permissible range - if is_really_big(search.search_query.query): + if is_really_big(query): raise OverflowError - - code = evaluate(search.search_query.query).item() + + code = evaluate(query).item() if type(code) in (int, float): search.result_container.answers.clear() # TODO: translate the following line - answer = "The value of {} is {}".format(search.search_query.query, code) + answer = "The value of {} is {}".format(query, code) search.result_container.answers[answer] = {'answer': str(answer)} except (ZeroDivisionError, ValueError, FloatingPointError, MemoryError) as e: logger.debug(e) -- GitLab From b9b3ead91ad763c84f40b6058022fcdd6d87e0fa Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Wed, 30 Mar 2022 14:35:10 +0530 Subject: [PATCH 07/11] fix pep8 --- searx/plugins/calculator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py index bd42d67ad..35308cc77 100644 --- a/searx/plugins/calculator.py +++ b/searx/plugins/calculator.py @@ -34,7 +34,7 @@ def post_search(request, search): # Not going to compute the result if the query is too big if len(query) > 30: return True - + # Not going to compute the result if the query is not within permissible range if is_really_big(query): raise OverflowError -- GitLab From 290fc4215980ce8c9fc4c65d952a214fac5e5f19 Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Thu, 31 Mar 2022 12:30:16 +0530 Subject: [PATCH 08/11] enable calculator by default --- searx/settings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/searx/settings.yml b/searx/settings.yml index 50469eb74..df24a2141 100644 --- a/searx/settings.yml +++ b/searx/settings.yml @@ -109,7 +109,7 @@ outgoing: # communication with search engines # uncomment below section if you want to configure which plugin is enabled by default # enabled_plugins: - - "calculator" + - "Calculator" # - ... # Example to rewrite hostnames in external links -- GitLab From c0d8613bd8b4e70a491560ebf169b0c67f247b60 Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Fri, 8 Apr 2022 00:42:16 +0530 Subject: [PATCH 09/11] add design changes to calculator --- searx/plugins/calculator.py | 51 +++++++++---------- .../themes/etheme/less/etheme/defs.less | 1 + .../themes/etheme/less/etheme/results.less | 6 ++- searx/templates/etheme/results.html | 16 ++++-- 4 files changed, 40 insertions(+), 34 deletions(-) diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py index 35308cc77..aa7a8b5c0 100644 --- a/searx/plugins/calculator.py +++ b/searx/plugins/calculator.py @@ -1,9 +1,10 @@ from searx import logger from numexpr import evaluate +from flask_babel import gettext -name = "Calculator" -# TODO: translate the following line -description = 'This plugin extends results when the query is a mathematical expression' + +name = gettext('Calculator') +description = gettext('This plugin extends results when the query is a mathematical expression') default_on = True logger = logger.getChild("calculator") @@ -22,48 +23,42 @@ def is_really_big(query): def post_search(request, search): if search.search_query.pageno > 1: - return True + return try: query = search.search_query.query.lower() query = query.replace("x", "*") + # Not going to compute if only one number is present + try: + x = int(query) or float(query) + return + except ValueError: + pass + # Not going to compute if no numbers are present if not any(i.isdigit() for i in query): - return True + return # Not going to compute the result if the query is too big if len(query) > 30: - return True + return # Not going to compute the result if the query is not within permissible range if is_really_big(query): raise OverflowError - code = evaluate(query).item() - if type(code) in (int, float): + value = evaluate(query).item() + if type(value) in (int, float): search.result_container.answers.clear() - # TODO: translate the following line - answer = "The value of {} is {}".format(query, code) - search.result_container.answers[answer] = {'answer': str(answer)} - except (ZeroDivisionError, ValueError, FloatingPointError, MemoryError) as e: - logger.debug(e) - # TODO: translate the following line - search.result_container.answers[f'Please recheck the above query: {e}'] = {'answer': None} - return False - except OverflowError as e: - logger.debug(e) - # TODO: translate the following line - search.result_container.answers[f'Please recheck the above query: Too big to compute {e}'] = {'answer': None} - return False - except (SyntaxError, NameError, TypeError) as e: - logger.debug(e) - # TODO: translate the following line - search.result_container.answers[f'Please recheck syntax of above query'] = {'answer': None} - return False + answer = "{} = {}".format(query, value) + search.result_container.answers[answer] = {'answer': answer, 'calculator': True} + except (ZeroDivisionError, ValueError, FloatingPointError, MemoryError, OverflowError) as e: + answer = gettext('Error') + search.result_container.answers[answer] = {'answer': answer, 'calculator': True} except Exception as e: logger.debug(e) - return False - return True + + return check_if_loaded() diff --git a/searx/static/themes/etheme/less/etheme/defs.less b/searx/static/themes/etheme/less/etheme/defs.less index 2ecc3e188..41faa5a37 100644 --- a/searx/static/themes/etheme/less/etheme/defs.less +++ b/searx/static/themes/etheme/less/etheme/defs.less @@ -70,6 +70,7 @@ @fontsize_large: 18px; @fontsize_x-large: 22px; @fontsize_xx-large: 22px; +@fontsize_xxx-large: 30px; @spacing_xx-small: 2px; @spacing_x-small: 4px; diff --git a/searx/static/themes/etheme/less/etheme/results.less b/searx/static/themes/etheme/less/etheme/results.less index a35046a1d..9f54cedda 100644 --- a/searx/static/themes/etheme/less/etheme/results.less +++ b/searx/static/themes/etheme/less/etheme/results.less @@ -132,7 +132,11 @@ } } } - +.result-calculator { + font-size: @fontsize_xxx-large; + font-family: 'Noto Sans'; + font-weight: 700; +} .result.result-default, .result.result-torrent { margin-bottom: @spacing_xx-large; } diff --git a/searx/templates/etheme/results.html b/searx/templates/etheme/results.html index ba7530446..5967defe1 100644 --- a/searx/templates/etheme/results.html +++ b/searx/templates/etheme/results.html @@ -25,13 +25,19 @@ {% endif %} - {% if answers %} - {% for answer in answers %} + {% if answers -%} + {%- for answer in answers.values() %}
- {{ answer }} + {% if answer.url %} + {{ answer.answer }} + {% elif answer.calculator %} + {{ answer.answer }} + {% else %} + {{ answer.answer }} + {% endif %}
- {% endfor %} - {% endif %} + {%- endfor %} + {%- endif %} {% if not results and not answers %} {% include 'etheme/messages/no_results.html' %} -- GitLab From 07cce21f9e983e9d4e3fa5a595f935a21faa0b4a Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Fri, 8 Apr 2022 01:10:33 +0530 Subject: [PATCH 10/11] need to commit css genereated files --- searx/static/themes/etheme/css/etheme.css | 5 +++++ searx/static/themes/etheme/css/etheme.min.css | Bin 23792 -> 23866 bytes 2 files changed, 5 insertions(+) diff --git a/searx/static/themes/etheme/css/etheme.css b/searx/static/themes/etheme/css/etheme.css index 378f41ab1..ac923ba8b 100644 --- a/searx/static/themes/etheme/css/etheme.css +++ b/searx/static/themes/etheme/css/etheme.css @@ -992,6 +992,11 @@ input:checked + .slider:before { .result .code-block pre { white-space: pre-wrap; } +.result-calculator { + font-size: 30px; + font-family: 'Noto Sans'; + font-weight: 700; +} .result.result-default, .result.result-torrent { margin-bottom: 32px; diff --git a/searx/static/themes/etheme/css/etheme.min.css b/searx/static/themes/etheme/css/etheme.min.css index be2a65193fea6f9b43266721ee91ba9d50e053e7..de0844aad1f604236e09a46b5b01eea321b0d127 100644 GIT binary patch delta 89 zcmeyclX2HB#to~?nT$*}uQ5*%bJ9&t%tqHYljD26NLA mb2D=)t!q!nduoNR^|oqYm@BsiDdLdQ- delta 22 ecmdnBi}Axw#to~?nGDS~uQ5*%+Z^ThfDZt4oC$LP -- GitLab From 3fe817b3cdc758ecaea1d2b1d932cc5aab0b9e12 Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Mon, 11 Apr 2022 11:41:54 +0530 Subject: [PATCH 11/11] fix font color --- searx/static/themes/etheme/css/etheme.css | 13 ++++++++----- searx/static/themes/etheme/css/etheme.min.css | Bin 24132 -> 24238 bytes .../themes/etheme/less/etheme/defs.less | 2 ++ .../themes/etheme/less/etheme/results.less | 13 ++++++++----- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/searx/static/themes/etheme/css/etheme.css b/searx/static/themes/etheme/css/etheme.css index 9762b31cf..e0167b680 100644 --- a/searx/static/themes/etheme/css/etheme.css +++ b/searx/static/themes/etheme/css/etheme.css @@ -21,6 +21,8 @@ --menu-icon-color: #222; --color-dashboard-panels: #f2f2f2; --color-dashboard-background-plain: #d2d2d2; + --color-answer-value: #777777; + --color-answer-info: #979797; --text-muted-normal-alpha: rgba(0, 0, 0, 0.4); --input-border-color: rgba(0, 0, 0, 0.24); --input-text-color: black; @@ -994,7 +996,7 @@ input:checked + .slider:before { } .result-calculator { font-size: 30px; - font-family: 'Noto Sans'; + color: var(--color-answer-value); font-weight: 700; } .result.result-default, @@ -1002,20 +1004,21 @@ input:checked + .slider:before { margin-bottom: 32px; } .result .currency-value { - font-family: 'Noto Sans'; - color: var(--color-currency-value); + color: var(--color-answer-value); font-style: normal; font-weight: 700; font-size: 30px; padding-bottom: 15px; } .result .currency-info { - font-family: 'Noto Sans'; - color: var(--color-currency-value); + color: var(--color-answer-value); font-style: normal; font-weight: 400; font-size: 18px; } +.well { + padding-top: 10px; +} .conversion { margin-right: 15%; } diff --git a/searx/static/themes/etheme/css/etheme.min.css b/searx/static/themes/etheme/css/etheme.min.css index 4535b93c0cd69afe56697d66bb998c8d18c0beda..daf2bc559386eb95779020033af0cc1ec6c1f7b7 100644 GIT binary patch delta 237 zcmX@IhjHCr#tk!=Op^0+@{4p6^NPz;i*(Bpb4pXKl+De}t#x%#WHR&8@~xCD%|Xz5 z@&R7S&Fh&Gy}fjk6LXSFa}rDPi>lM|^GbA!Gpkaqj13AZtijr?$`Xq-(2N3GqG=6Q zUY?qno>5|DZeTE(!!Jq#m!8R5{%VtV`Pt!9U?p6hnv+vqkeHH^nU}6xl3!qDXs|iK H|1lo`^QBe* delta 115 zcmZ3tm+{CR#tk!=CO7+vZ+^;@=skIcUyyiOeqM=gT4HWyPNkK)Uw%oxLU3YUvHD~~ iUtx~q(xRf&yyVKsb^dCTHT>;}Rcy8Sy#IYZMlJyV