From 19e781e9f8dc8bfaeacfb3f86c3823fe4f6f1218 Mon Sep 17 00:00:00 2001 From: Munyoki Kilyungi Date: Tue, 14 May 2024 12:56:43 +0300 Subject: Revert "Disable gnqa functionality." This reverts commit 01eba6e9b54e45bc937983e33b439a353118de2c. --- gn2/wqflask/templates/base.html | 3 +-- gn2/wqflask/views.py | 6 +----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/gn2/wqflask/templates/base.html b/gn2/wqflask/templates/base.html index 14b484a5..26b75230 100644 --- a/gn2/wqflask/templates/base.html +++ b/gn2/wqflask/templates/base.html @@ -183,11 +183,10 @@ - + diff --git a/gn2/wqflask/views.py b/gn2/wqflask/views.py index 9f403ace..843ed07a 100644 --- a/gn2/wqflask/views.py +++ b/gn2/wqflask/views.py @@ -255,12 +255,8 @@ def gsearchtable(): return flask.jsonify(current_page) -"""@app.route("/gnqna", methods=["POST", "GET"]) ;;feature currently disabled -;;use ga.genenetwork.org +@app.route("/gnqna", methods=["POST", "GET"]) @require_oauth2 -""" - - def gnqna(): if request.method == "POST": -- cgit v1.2.3 From 1202ce35e22ec765deacf65724fbaa235aeafb20 Mon Sep 17 00:00:00 2001 From: Alexander_Kabui Date: Tue, 14 May 2024 13:17:39 +0300 Subject: Bug: fix issue form submission happening twice --- gn2/wqflask/templates/gnqa.html | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/gn2/wqflask/templates/gnqa.html b/gn2/wqflask/templates/gnqa.html index 1268ef39..8b50fe43 100644 --- a/gn2/wqflask/templates/gnqa.html +++ b/gn2/wqflask/templates/gnqa.html @@ -118,12 +118,8 @@ type="text" autocomplete="on" required placeholder="Ask More Questions or Topics (E.g Genes)" - value='' + value='' name="querygnqa" - hx-post="/gnqna" - hx-target="#swap" - hx-swap="innerHTML" - hx-indicator="#indicator" /> -- cgit v1.2.3 From 16f978ecdaf450cfa700bd6e78194831ed9a8f57 Mon Sep 17 00:00:00 2001 From: Munyoki Kilyungi Date: Tue, 14 May 2024 15:33:00 +0300 Subject: Use correct URL when redirecting user after a new registration. Signed-off-by: Munyoki Kilyungi --- gn2/wqflask/oauth2/users.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gn2/wqflask/oauth2/users.py b/gn2/wqflask/oauth2/users.py index 2407703c..8a935170 100644 --- a/gn2/wqflask/oauth2/users.py +++ b/gn2/wqflask/oauth2/users.py @@ -116,7 +116,7 @@ def register_user(): return redirect(url_for("oauth2.user.register_user")) flash("Registration successful! Please login to continue.", "alert-success") - return redirect(url_for("/")) + return redirect("/") @users.route("/masquerade", methods=["GET", "POST"]) def masquerade(): -- cgit v1.2.3 From cfbb1a847d20a726ff286734cba3fa429b4e93c4 Mon Sep 17 00:00:00 2001 From: Alexander_Kabui Date: Wed, 22 May 2024 13:53:32 +0300 Subject: Refactor template code for gnqa search history --- gn2/wqflask/templates/gnqa.html | 4 ++-- gn2/wqflask/templates/gnqa_search_history.html | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/gn2/wqflask/templates/gnqa.html b/gn2/wqflask/templates/gnqa.html index 8b50fe43..b3bc74fd 100644 --- a/gn2/wqflask/templates/gnqa.html +++ b/gn2/wqflask/templates/gnqa.html @@ -93,7 +93,7 @@ AI Search - @@ -107,7 +107,7 @@ - {% endfor %} -- cgit v1.2.3 From 292f4ab25508ef2e72a0caac6e609317113be232 Mon Sep 17 00:00:00 2001 From: Alexander_Kabui Date: Wed, 22 May 2024 14:00:30 +0300 Subject: View file code cleanup for gnqa. --- gn2/wqflask/views.py | 46 ++++++++++------------------------------------ 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/gn2/wqflask/views.py b/gn2/wqflask/views.py index 843ed07a..5d0075c5 100644 --- a/gn2/wqflask/views.py +++ b/gn2/wqflask/views.py @@ -258,23 +258,14 @@ def gsearchtable(): @app.route("/gnqna", methods=["POST", "GET"]) @require_oauth2 def gnqna(): - if request.method == "POST": try: - def __error__(resp): - return resp.json() - def error_page(resp): return render_template("gnqa_errors.html", **{"status_code": resp.status_code, **resp.json()}) def __success__(resp): return render_template("gnqa_answer.html", **{"gn_server_url": GN3_LOCAL_URL, **(resp.json())}) - """ - disable gn-auth currently not stable - if not user_logged_in(): - return error_page("Please Login/Register to Genenetwork to access this Service") - """ token = session_info()["user"]["token"].either( lambda err: err, lambda tok: tok["access_token"]) return monad_requests.post( @@ -290,44 +281,27 @@ def gnqna(): error_page, __success__) except Exception as error: return flask.jsonify({"error": str(error)}) - prev_queries = (monad_requests.get( - urljoin(GN3_LOCAL_URL, - "/api/llm/get_hist_names") - ).then( - lambda resp: resp - ).either(lambda x: [], lambda x: x.json()["prev_queries"])) - - return render_template("gnqa.html", prev_queries=prev_queries) - - -@app.route("/gnqna/hist/", methods=["GET"]) -@require_oauth2 -def get_hist_titles(): - token = session_info()["user"]["token"].either( - lambda err: err, lambda tok: tok["access_token"]) - response = monad_requests.get(urljoin(GN3_LOCAL_URL, - "/api/llm/hist/titles"), - headers={ - "Authorization": f"Bearer {token}" - } - ).then(lambda resp: resp).either( - lambda x: x.json(), lambda x: x.json()) - return render_template("gnqa_search_history.html", **response) + return render_template("gnqa.html") -@app.route("/gnqna/hist/search/", methods=["GET"]) +@app.route("/gnqna/hist", methods=["GET"]) @require_oauth2 -def fetch_hist_records(search_term): +def get_gnqa_history(): token = session_info()["user"]["token"].either( lambda err: err, lambda tok: tok["access_token"]) response = monad_requests.get(urljoin(GN3_LOCAL_URL, - f"/api/llm/history/{search_term}"), + (f"/api/llm/history?search_term={request.args.get('search_term')}" + if request.args.get("search_term") else "/api/llm/history")), headers={ "Authorization": f"Bearer {token}" } ).then(lambda resp: resp).either( lambda x: x.json(), lambda x: x.json()) - return render_template("gnqa_answer.html", **response) + if request.args.get("search_term"): + return render_template("gnqa_answer.html", + **{"gn_server_url": "GN3_LOCAL_URL", **response}) + return render_template("gnqa_search_history.html", + prev_queries=response) @app.route("/gnqna/rating//", -- cgit v1.2.3 From 13a554a9744bc70da9606c0348ec675276147a29 Mon Sep 17 00:00:00 2001 From: Alexander_Kabui Date: Thu, 23 May 2024 14:47:27 +0300 Subject: Update endpoints and add search history functionality. --- gn2/wqflask/templates/gnqa_search_history.html | 29 +++++++++++++------------- gn2/wqflask/views.py | 11 ++++++---- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/gn2/wqflask/templates/gnqa_search_history.html b/gn2/wqflask/templates/gnqa_search_history.html index af38392a..890a3995 100644 --- a/gn2/wqflask/templates/gnqa_search_history.html +++ b/gn2/wqflask/templates/gnqa_search_history.html @@ -1,39 +1,40 @@
-
-

You search History

+

Your AI search History

-
- {% for (key,val) in prev_queries.items() %} -
-
- +
+
+
    + {% for item in prev_queries %} +
  • +
    -
    -
-
- {% endfor %} +
+ + {% endfor %} +
diff --git a/gn2/wqflask/views.py b/gn2/wqflask/views.py index 5d0075c5..5bb443c1 100644 --- a/gn2/wqflask/views.py +++ b/gn2/wqflask/views.py @@ -270,7 +270,7 @@ def gnqna(): lambda err: err, lambda tok: tok["access_token"]) return monad_requests.post( urljoin(GN3_LOCAL_URL, - "/api/llm/gnqna"), + "/api/llm/search"), json=dict(request.form), headers={ "Authorization": f"Bearer {token}" @@ -287,6 +287,10 @@ def gnqna(): @app.route("/gnqna/hist", methods=["GET"]) @require_oauth2 def get_gnqa_history(): + def _error_(resp): + return render_template("gnqa_errors.html", + **{"status_code": resp.status_code, + **resp.json()}) token = session_info()["user"]["token"].either( lambda err: err, lambda tok: tok["access_token"]) response = monad_requests.get(urljoin(GN3_LOCAL_URL, @@ -296,10 +300,9 @@ def get_gnqa_history(): "Authorization": f"Bearer {token}" } ).then(lambda resp: resp).either( - lambda x: x.json(), lambda x: x.json()) + _error_, lambda x: x.json()) if request.args.get("search_term"): - return render_template("gnqa_answer.html", - **{"gn_server_url": "GN3_LOCAL_URL", **response}) + return render_template("gnqa_answer.html", **response) return render_template("gnqa_search_history.html", prev_queries=response) -- cgit v1.2.3 From 066adb63d2a539693a60fd2d120922de324a65ea Mon Sep 17 00:00:00 2001 From: Alexander_Kabui Date: Fri, 24 May 2024 18:04:25 +0300 Subject: Add UI code for gnqa history search delete functionality. --- gn2/wqflask/templates/gnqa_search_history.html | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/gn2/wqflask/templates/gnqa_search_history.html b/gn2/wqflask/templates/gnqa_search_history.html index 890a3995..c1e66541 100644 --- a/gn2/wqflask/templates/gnqa_search_history.html +++ b/gn2/wqflask/templates/gnqa_search_history.html @@ -11,12 +11,17 @@
-
+
+
+ +
+
+
-
    +
      {% for item in prev_queries %}
    • -
-
+ +{% block js %} + + +{% endblock %} -- cgit v1.2.3 From eff7011aa002aea41cd71d7cb0b21b9ab938ffc4 Mon Sep 17 00:00:00 2001 From: Alexander_Kabui Date: Mon, 27 May 2024 17:39:40 +0300 Subject: Mark answer and references as safe to render a tags. --- gn2/wqflask/templates/gnqa_answer.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gn2/wqflask/templates/gnqa_answer.html b/gn2/wqflask/templates/gnqa_answer.html index 0ddcfde7..62ce70d9 100644 --- a/gn2/wqflask/templates/gnqa_answer.html +++ b/gn2/wqflask/templates/gnqa_answer.html @@ -3,7 +3,7 @@

{{ query }}
- {{ answer }} + {{ answer|safe }}

@@ -32,7 +32,7 @@
-

{{ reference.comboTxt }}

+

{{ reference.comboTxt|safe }}

{% if reference.pubmed %}
@@ -60,7 +60,7 @@
-

{{reference.comboTxt}}

+

{{ reference.comboTxt|safe }}

{% if reference.pubmed %}
-- cgit v1.2.3 From 8edf35d35b91ca27f70d958f668589cfda201f52 Mon Sep 17 00:00:00 2001 From: Alexander_Kabui Date: Tue, 28 May 2024 17:35:49 +0300 Subject: Fix bug: Update DOM correctly when rating error occurs. --- gn2/wqflask/templates/gnqa_answer.html | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/gn2/wqflask/templates/gnqa_answer.html b/gn2/wqflask/templates/gnqa_answer.html index 62ce70d9..41c1b338 100644 --- a/gn2/wqflask/templates/gnqa_answer.html +++ b/gn2/wqflask/templates/gnqa_answer.html @@ -6,7 +6,7 @@ {{ answer|safe }}

- + @@ -93,20 +93,27 @@ {% block js %} {% endblock %} -- cgit v1.2.3 From c7b1210c1a8716ef045a1291bca76c1d822c134f Mon Sep 17 00:00:00 2001 From: Alexander_Kabui Date: Tue, 28 May 2024 17:51:59 +0300 Subject: BugFix: return correct status code for generic exceptions handler. --- gn2/wqflask/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gn2/wqflask/views.py b/gn2/wqflask/views.py index 5bb443c1..5bfcce83 100644 --- a/gn2/wqflask/views.py +++ b/gn2/wqflask/views.py @@ -137,6 +137,7 @@ def handle_generic_exceptions(e): stack={formatted_lines}, error_image=animation, version=current_app.config.get("GN_VERSION"))) + resp.status_code = exc_type.code or 500 resp.set_cookie(err_msg[:32], animation) return resp -- cgit v1.2.3 From 034b50502a6d15bccd52211a8bb282d46ac1558e Mon Sep 17 00:00:00 2001 From: Alexander_Kabui Date: Wed, 29 May 2024 12:47:12 +0300 Subject: Handle attributeError when getting error codes. --- gn2/wqflask/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gn2/wqflask/views.py b/gn2/wqflask/views.py index 5bfcce83..8f1c62ff 100644 --- a/gn2/wqflask/views.py +++ b/gn2/wqflask/views.py @@ -137,7 +137,10 @@ def handle_generic_exceptions(e): stack={formatted_lines}, error_image=animation, version=current_app.config.get("GN_VERSION"))) - resp.status_code = exc_type.code or 500 + try: + resp.status_code = exc_type.code + except AttributeError: + resp.status_code = 500 resp.set_cookie(err_msg[:32], animation) return resp -- cgit v1.2.3 From 30e5a84940bd9715bea02d07c5092bbfd717f7c5 Mon Sep 17 00:00:00 2001 From: Alexander_Kabui Date: Wed, 29 May 2024 14:05:44 +0300 Subject: integrate gnqa history delete functionality. --- gn2/wqflask/views.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/gn2/wqflask/views.py b/gn2/wqflask/views.py index 8f1c62ff..666e765a 100644 --- a/gn2/wqflask/views.py +++ b/gn2/wqflask/views.py @@ -288,7 +288,8 @@ def gnqna(): return render_template("gnqa.html") -@app.route("/gnqna/hist", methods=["GET"]) + +@app.route("/gnqna/hist", methods=["GET", "DELETE"]) @require_oauth2 def get_gnqa_history(): def _error_(resp): @@ -297,6 +298,14 @@ def get_gnqa_history(): **resp.json()}) token = session_info()["user"]["token"].either( lambda err: err, lambda tok: tok["access_token"]) + if request.method == "DELETE": + monad_requests.post(urljoin(GN3_LOCAL_URL, "/api/llm/history"), + json=dict(request.form), + headers={ + "Authorization": f"Bearer {token}" + } + ).either( + _error_, lambda x: x.json()) response = monad_requests.get(urljoin(GN3_LOCAL_URL, (f"/api/llm/history?search_term={request.args.get('search_term')}" if request.args.get("search_term") else "/api/llm/history")), -- cgit v1.2.3 From 842a758f31143a5934b2798a4d0f40f11a402919 Mon Sep 17 00:00:00 2001 From: Alexander_Kabui Date: Wed, 29 May 2024 14:27:40 +0300 Subject: Add htmx js api for delete functionality. --- gn2/wqflask/templates/gnqa_search_history.html | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/gn2/wqflask/templates/gnqa_search_history.html b/gn2/wqflask/templates/gnqa_search_history.html index c1e66541..976fd7fd 100644 --- a/gn2/wqflask/templates/gnqa_search_history.html +++ b/gn2/wqflask/templates/gnqa_search_history.html @@ -1,4 +1,4 @@ -
+
@@ -15,8 +15,8 @@
-
-
+
+
    {% for item in prev_queries %} @@ -44,15 +44,9 @@
-{% block js %} - - -{% endblock %} -- cgit v1.2.3 From 0f4c9fbe37ed74022d9fad35352b59d948789818 Mon Sep 17 00:00:00 2001 From: Alexander Kabui Date: Wed, 28 Aug 2024 14:58:16 +0300 Subject: Revert "Feature/gnqa search history" --- gn2/wqflask/templates/gnqa.html | 4 +- gn2/wqflask/templates/gnqa_answer.html | 33 ++++++------- gn2/wqflask/templates/gnqa_search_history.html | 46 ++++++++---------- gn2/wqflask/views.py | 64 +++++++++++++++----------- 4 files changed, 70 insertions(+), 77 deletions(-) diff --git a/gn2/wqflask/templates/gnqa.html b/gn2/wqflask/templates/gnqa.html index b3bc74fd..8b50fe43 100644 --- a/gn2/wqflask/templates/gnqa.html +++ b/gn2/wqflask/templates/gnqa.html @@ -93,7 +93,7 @@ AI Search - @@ -107,7 +107,7 @@ + @@ -32,7 +32,7 @@
-

{{ reference.comboTxt|safe }}

+

{{ reference.comboTxt }}

{% if reference.pubmed %}
@@ -60,7 +60,7 @@
-

{{ reference.comboTxt|safe }}

+

{{reference.comboTxt}}

{% if reference.pubmed %}
@@ -93,27 +93,20 @@ {% block js %} {% endblock %} diff --git a/gn2/wqflask/templates/gnqa_search_history.html b/gn2/wqflask/templates/gnqa_search_history.html index 976fd7fd..2c07b8c0 100644 --- a/gn2/wqflask/templates/gnqa_search_history.html +++ b/gn2/wqflask/templates/gnqa_search_history.html @@ -1,52 +1,42 @@ -
+
+
-

Your AI search History

+

You search History

-
-
- -
-
-
-
-
    - {% for item in prev_queries %} -
  • - +
    + {% for record in prev_queries %} +
    +
    +
    + {% for id,val in record.items() %} -
    -
  • - {% endfor %} -
+ {% endfor %} +
+
+
+ {% endfor %}
- - + diff --git a/gn2/wqflask/views.py b/gn2/wqflask/views.py index 666e765a..843ed07a 100644 --- a/gn2/wqflask/views.py +++ b/gn2/wqflask/views.py @@ -137,10 +137,6 @@ def handle_generic_exceptions(e): stack={formatted_lines}, error_image=animation, version=current_app.config.get("GN_VERSION"))) - try: - resp.status_code = exc_type.code - except AttributeError: - resp.status_code = 500 resp.set_cookie(err_msg[:32], animation) return resp @@ -262,19 +258,28 @@ def gsearchtable(): @app.route("/gnqna", methods=["POST", "GET"]) @require_oauth2 def gnqna(): + if request.method == "POST": try: + def __error__(resp): + return resp.json() + def error_page(resp): return render_template("gnqa_errors.html", **{"status_code": resp.status_code, **resp.json()}) def __success__(resp): return render_template("gnqa_answer.html", **{"gn_server_url": GN3_LOCAL_URL, **(resp.json())}) + """ + disable gn-auth currently not stable + if not user_logged_in(): + return error_page("Please Login/Register to Genenetwork to access this Service") + """ token = session_info()["user"]["token"].either( lambda err: err, lambda tok: tok["access_token"]) return monad_requests.post( urljoin(GN3_LOCAL_URL, - "/api/llm/search"), + "/api/llm/gnqna"), json=dict(request.form), headers={ "Authorization": f"Bearer {token}" @@ -285,39 +290,44 @@ def gnqna(): error_page, __success__) except Exception as error: return flask.jsonify({"error": str(error)}) - return render_template("gnqa.html") + prev_queries = (monad_requests.get( + urljoin(GN3_LOCAL_URL, + "/api/llm/get_hist_names") + ).then( + lambda resp: resp + ).either(lambda x: [], lambda x: x.json()["prev_queries"])) + return render_template("gnqa.html", prev_queries=prev_queries) -@app.route("/gnqna/hist", methods=["GET", "DELETE"]) +@app.route("/gnqna/hist/", methods=["GET"]) @require_oauth2 -def get_gnqa_history(): - def _error_(resp): - return render_template("gnqa_errors.html", - **{"status_code": resp.status_code, - **resp.json()}) +def get_hist_titles(): + token = session_info()["user"]["token"].either( + lambda err: err, lambda tok: tok["access_token"]) + response = monad_requests.get(urljoin(GN3_LOCAL_URL, + "/api/llm/hist/titles"), + headers={ + "Authorization": f"Bearer {token}" + } + ).then(lambda resp: resp).either( + lambda x: x.json(), lambda x: x.json()) + return render_template("gnqa_search_history.html", **response) + + +@app.route("/gnqna/hist/search/", methods=["GET"]) +@require_oauth2 +def fetch_hist_records(search_term): token = session_info()["user"]["token"].either( lambda err: err, lambda tok: tok["access_token"]) - if request.method == "DELETE": - monad_requests.post(urljoin(GN3_LOCAL_URL, "/api/llm/history"), - json=dict(request.form), - headers={ - "Authorization": f"Bearer {token}" - } - ).either( - _error_, lambda x: x.json()) response = monad_requests.get(urljoin(GN3_LOCAL_URL, - (f"/api/llm/history?search_term={request.args.get('search_term')}" - if request.args.get("search_term") else "/api/llm/history")), + f"/api/llm/history/{search_term}"), headers={ "Authorization": f"Bearer {token}" } ).then(lambda resp: resp).either( - _error_, lambda x: x.json()) - if request.args.get("search_term"): - return render_template("gnqa_answer.html", **response) - return render_template("gnqa_search_history.html", - prev_queries=response) + lambda x: x.json(), lambda x: x.json()) + return render_template("gnqa_answer.html", **response) @app.route("/gnqna/rating//", -- cgit v1.2.3 From 9671e9ef4bc20d562b831f97c52b40e91b1d4c20 Mon Sep 17 00:00:00 2001 From: Munyoki Kilyungi Date: Mon, 20 May 2024 12:55:52 +0300 Subject: Check metadata exists before setting 'editable' field in get_dataset. Signed-off-by: Munyoki Kilyungi --- gn2/wqflask/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gn2/wqflask/views.py b/gn2/wqflask/views.py index 843ed07a..a7bc8fa2 100644 --- a/gn2/wqflask/views.py +++ b/gn2/wqflask/views.py @@ -1230,8 +1230,8 @@ def get_dataset(name): lambda err: {"roles": []}, lambda val: val ) - - metadata["editable"] = "group:resource:edit-resource" in result["roles"] + if metadata: + metadata["editable"] = "group:resource:edit-resource" in result["roles"] return render_template( "dataset.html", name=name, -- cgit v1.2.3 From dc1485253ef4b9a4c2c1af45a56eff4018bc6d07 Mon Sep 17 00:00:00 2001 From: Munyoki Kilyungi Date: Mon, 20 May 2024 12:56:03 +0300 Subject: Remove styling for search field. Signed-off-by: Munyoki Kilyungi --- gn2/wqflask/templates/dataset.html | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/gn2/wqflask/templates/dataset.html b/gn2/wqflask/templates/dataset.html index 096a3724..62fac650 100644 --- a/gn2/wqflask/templates/dataset.html +++ b/gn2/wqflask/templates/dataset.html @@ -40,31 +40,6 @@ .panel-metadata dt::after { content: ":"; } - - .search { - width: 50%; - margin: 1em auto; - } - .has-search .form-control-feedback { - right: initial; - left: 0; - color: #ccc; - } - - .has-search .form-control { - padding-right: 12px; - padding-left: 34px; - } - - .search { - transform: scale(1.5, 1.5); - } - .search input { - min-width: 17em; - } - .dataset-search { - padding: 0 17%; - } {% endblock %} @@ -348,7 +323,7 @@
{% else %} -